51 lines
6.4 KiB
Markdown
51 lines
6.4 KiB
Markdown
# 2026-08-16
|
||
|
||
## i18n 取语言方式重构
|
||
- 项目 i18n 已配置(defaultLocale: 'en', locales: ['en','cn'], prefixDefaultLocale: false)。
|
||
- 将 `.astro` 页面里 `getLocaleFromUrl(Astro.url)` 改为 `Astro.currentLocale`(Astro 路由解析,更稳健),并补类型兜底 `(Astro.currentLocale as Locale) ?? DEFAULT_LOCALE`。
|
||
- 涉及文件:src/layouts/Layout.astro、src/pages/index.astro、src/pages/cn/index.astro。
|
||
- src/i18n/utils.ts 的 `getLocaleFromUrl` 纯函数保留(供 .ts 模块或解析任意 URL 使用)。
|
||
## 结论
|
||
- `Astro.currentLocale` 可替代 `getLocaleFromUrl(Astro.url)`,但仅限 .astro 文件;纯 TS / 解析非当前页 URL 仍需自定义函数。
|
||
|
||
## Astro 浏览器语言检测(重要,修正此前误解)
|
||
- Astro 确实提供 `Astro.preferredLocale` / `Astro.preferredLocaleList`,但它是**服务端按请求**结合 `Accept-Language` 头计算的,仅 SSR 运行时有效。
|
||
- **本项目是静态构建 + nginx 托管**:build 阶段无访客、无 Accept-Language 头,运行时也无 Node 进程重算,故 `preferredLocale` 在静态产物里是 undefined、`preferredLocaleList` 回退为全部 i18n.locales,**无法在运行时检测访客语言**。
|
||
- 客户端 `navigator.language` 脚本仍是当前静态部署下唯一运行时生效的方案。
|
||
- 若要改用 `Astro.preferredLocale` + `Astro.redirect()`:必须迁移到 SSR(加 adapter、output:'server'、nginx 后跑 Node),且需在 i18n.locales 为 `cn` 补 `codes: ['zh','zh-CN','zh-TW','zh-HK']` 才能把浏览器 `zh-CN` 匹配到 `cn`(当前 `locales:['en','cn']` 裸码匹配不到)。
|
||
|
||
## Bug 修复:header 语言切换器不显示
|
||
- 根因:`src/layouts/Layout.astro` 中语言切换器(`LOCALES.map`)原是 `#auth-slot` 的子节点;页脚 auth 脚本 `fetchMe()` 未登录返回 null → `render(null)` 用 `slot.innerHTML` 整块重写成 Login/Signup,把语言切换器一并抹掉。任何未登录访客都触发,故语言选项永远看不见。
|
||
- 修复:(1) 将语言切换器移出 `#auth-slot`,独立为 `#lang-switch` 兄弟节点,脚本重写不再波及;(2) 未登录时不再硬编码 `/login` 重写 `#auth-slot`,保留 SSR 的带语言前缀 Login/Signup,顺带修好 /cn 页登录链接丢前缀问题。
|
||
- 教训:header 中「语言切换器」与「登录态 UI」必须分属不同容器,避免被 auth 脚本的 innerHTML 重写误伤。
|
||
|
||
## 语言切换器改为下拉菜单
|
||
- 将 header `#lang-switch` 从「English / 中文」并排链接改为 Alpine 下拉(`x-data="{open:false}"` + `@click.outside` + `@keydown.escape.window`,绝对定位 `right-0`、`z-50`,带 chevron 旋转)。选中项 `font-bold`,其余 `opacity-60`。
|
||
- 在 `src/styles/global.css` 补 `[x-cloak]{display:none!important}`(原仅 shows/index 各自 `<style>` 有,Layout 作为全站模板缺此规则会导致下拉闪烁)。
|
||
- 移除原链接间的分隔斜杠 `<span class="opacity-25">/</span>`。
|
||
- 仍保留独立 `#lang-switch` 容器,不被 footer auth 脚本重写。
|
||
|
||
## 语言切换器升级:地球图标 + hover 展开
|
||
- 把按钮内容从 `{LOCALE_NAMES[locale]} + chevron` 换成地球 SVG 图标(`w-[18px] h-[18px]`,圆+经线+纬线),移除文本标签和 chevron。
|
||
- 行为从「click 切换」改为「hover 展开」,Alpine 加 `@mouseenter="open=true"` + `@mouseleave="open=false"`;click 仍保留(`@click="open=!open"`)作为触屏兜底。
|
||
- 关键坑:按钮与下拉之间的 `mt-2` 空隙会让鼠标从按钮移到下拉时 `mouseleave` 先触发、面板被收起。改为 `top-full`(紧贴按钮,无外间距),且整个切换器(图标+菜单)作为同一 Alpine 容器,鼠标在内部移动不会触发关闭。
|
||
- 加 `x-transition` 做淡入淡出(150ms / 100ms)+ `py-2` 给菜单项留呼吸空间。
|
||
- 后续补充:按钮在地球图标后追加当前语言名文字 `{LOCALE_NAMES[locale]}`(`normal-case text-[12px] tracking-[0.5px]` + `gap-1.5`),即「图标 + 当前语言」显示。
|
||
|
||
## i18n URL 转换改用 astro:i18n 内置函数
|
||
- `src/i18n/utils.ts` 的 `useTranslatedPath` 内部改为委托 `astro:i18n` 的 `getRelativeLocaleUrl(targetLocale, clean)`,自动遵循 i18n 配置(prefixDefaultLocale:false → 默认语言无前缀)。
|
||
- 同文件 `getLocaleFromUrl` 改为委托 `getLocaleByPath(pathname)`(保留 LOCALES 校验 + DEFAULT_LOCALE 兜底,try/catch)。
|
||
- `astro:i18n` 可在 `.ts` 模块(utils.ts)中 import,前端 frontmatter 同样可用;项目 astro ^7.1.6 支持。
|
||
- 顺手修复首页语言切换器瑕疵:`Layout.astro` 的 `currentPath` 原只剥离语言前缀,未去尾随 `index.html`,导致首页生成 `/index.html`、`/cn/index.html`;改为额外 `if 末段==='index.html' 去掉`,现首页正确生成 `/` 与 `/cn`。`currentPath` 仅用于语言切换器,改动只影响切换器。
|
||
- 验证:构建通过(exit 0),产物 dist/index.html 语言切换器 href 为 `/` 与 `/cn`(首页)、`/shows` 与 `/cn/shows`(其他页)。
|
||
|
||
## 彻底去掉 useTranslatedPath 包装层
|
||
- `src/i18n/utils.ts`:删除 `useTranslatedPath` 函数,移除不再使用的 `getRelativeLocaleUrl` 导入(仅 useTranslatedPath 引用过)。`getLocaleFromUrl` 仍委托 `getLocaleByPath`。
|
||
- `Layout.astro`:frontmatter 直接 `import { getRelativeLocaleUrl } from 'astro:i18n'`,删除 `const translatePath = useTranslatedPath(locale)`;所有调用点(nav 5 项 + 语言切换器 `getRelativeLocaleUrl(l, currentPath)` + footer 登录/注册/About/Contact)直接改为 `getRelativeLocaleUrl(locale, path)`。行为与原先一致。
|
||
|
||
## Bug 修复:中文首页切换器链接错误(format:'file' 坑)
|
||
- 站点 `build.format:'file'`,中文首页路由 /cn/ 产物是 `dist/cn.html`(英文首页是 `index.html`)。构建期 `Astro.url.pathname` 取的是产物路径 `/cn.html`。
|
||
- 原 currentPath 只剥离 `index.html`,不处理 `cn.html`,导致中文首页 currentPath=`/cn.html`,切换器英文项误生成 `/cn.html`(实际是中文首页)、中文项 `/cn/cn.html`。
|
||
- 修复:把"去尾随 index.html"改为"去尾随任意 .html"(`_last.endsWith('.html')` 则去掉末段)。现中英文首页切换器均正确:index.html → `/`/`/cn`;cn.html → `/`/`/cn`。
|
||
- 教训:`format:'file'` 下 Astro.url.pathname 是产物文件名(含 .html),做"当前逻辑路径"推导时必须剥 .html 后缀,不能只认 index.html。
|