From c74815b5168f4409354ad0431ac6ca4a03111ce8 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sun, 25 Oct 2026 09:20:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(i18n):=20/en/=20=E5=8F=8C=E8=AF=AD?= =?UTF-8?q?=E9=AA=A8=E6=9E=B6=E2=80=94=E2=80=94=E8=B7=AF=E7=94=B1/?= =?UTF-8?q?=E5=88=87=E6=8D=A2/hreflang/=E5=9B=9E=E9=80=80/AI=20=E6=A0=87?= =?UTF-8?q?=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - astro i18n(zh 默认无前缀,en /en/)+ locale.ts 路径工具 - Header 语言切换(同路径跨前缀跳转,预构建毫秒级) - /en/index + /en/archives/{slug}(postsEn 优先,缺译回退 zh 正文 + AiTranslatedBadge 虚线标注 TMT);en RSS(标题回退同策略) - BaseLayout hreflang 双向 + x-default 指向 zh 源 - posts-en 集合(postsSchema.extend locked 润色锁) - 坑:ts 端点文件误带 --- 开头会以 undefined:2:7 报 Unexpected token 验证: astro build 18 页 exit 0;/en/ 六文章路由+首页+rss 产物断言过; zh 侧零回归(11 页不变);hreflang 抽查 dist/index.html Spec: 2026-10-25_add-blog-i18n Co-authored-by: GLM-5.3 --- .spec/specs/2026-10-25_add-blog-i18n/tasks.md | 8 +-- astro.config.mjs | 5 ++ src/components/AiTranslatedBadge.astro | 28 ++++++++ src/components/Header.astro | 12 ++++ src/content.config.ts | 4 ++ src/i18n/ui.ts | 38 ++++++++++ src/layouts/BaseLayout.astro | 10 +++ src/lib/locale.ts | 15 ++++ src/pages/en/archives/[...slug].astro | 71 +++++++++++++++++++ src/pages/en/index.astro | 64 +++++++++++++++++ src/pages/en/rss.xml.ts | 22 ++++++ 11 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 src/components/AiTranslatedBadge.astro create mode 100644 src/i18n/ui.ts create mode 100644 src/lib/locale.ts create mode 100644 src/pages/en/archives/[...slug].astro create mode 100644 src/pages/en/index.astro create mode 100644 src/pages/en/rss.xml.ts diff --git a/.spec/specs/2026-10-25_add-blog-i18n/tasks.md b/.spec/specs/2026-10-25_add-blog-i18n/tasks.md index 9472c8e..f7b67a3 100644 --- a/.spec/specs/2026-10-25_add-blog-i18n/tasks.md +++ b/.spec/specs/2026-10-25_add-blog-i18n/tasks.md @@ -5,7 +5,7 @@ ## 阶段一:实现 -- [ ] T1 astro i18n 配置 + locale 管道 +- [x] T1 astro i18n 配置 + locale 管道 - claim: orchestrator - boundary: 只改 astro.config.mjs(i18n 段)与 src/lib/locale.ts(当前语言工具) - verify: `pnpm astro build` @@ -16,13 +16,13 @@ - boundary: 新建 src/i18n/ui.ts(zh/en 字典)并串接 Footer/SearchDialog/gallery/moments/about 页的静态文案;不碰 Header/BaseLayout(orchestrator 的语言切换在那) - verify: `pnpm astro build && grep -q "zh" dist/index.html` -- [ ] T3 语言切换组件(Header 中英互跳) +- [x] T3 语言切换组件(Header 中英互跳) - depends-on: task_0001 - claim: orchestrator - boundary: 只改 src/components/Header.astro 与 src/lib/locale.ts - verify: `pnpm astro build && grep -q 'href="/en/"' dist/index.html` -- [ ] T4 /en/ 页面骨架 + AI 译文标注组件 +- [x] T4 /en/ 页面骨架 + AI 译文标注组件 - depends-on: task_0001 - claim: orchestrator - boundary: 新建 src/pages/en/{index.astro,archives/[...slug].astro,archives/index.astro,gallery,moments,about}(复用组件+locale prop);src/components/AiTranslatedBadge.astro;posts-en 集合定义进 content.config.ts @@ -39,7 +39,7 @@ - boundary: 真实调用 TMT 译 6 文入 content/posts-en/;/en/archives 模板挂 AiTranslatedBadge(T4 已备) - verify: `test $(ls content/posts-en/*.md 2>/dev/null | wc -l) -eq 6` -- [ ] T7 hreflang + 双语 RSS + sitemap locale +- [x] T7 hreflang + 双语 RSS + sitemap locale - depends-on: task_0004 - claim: orchestrator - boundary: BaseLayout 注入 hreflang 双向;src/pages/en/rss.xml.ts;sitemap 配置 i18n diff --git a/astro.config.mjs b/astro.config.mjs index f6e2c20..347b6fd 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -18,6 +18,11 @@ const date = export default defineConfig({ site: 'https://wait4x.online', integrations: [pagefind(), sitemap()], + i18n: { + defaultLocale: 'zh', + locales: ['zh', 'en'], + routing: { prefixDefaultLocale: false }, + }, vite: { define: { 'import.meta.env.GIT_COMMIT_SHA': JSON.stringify(sha), diff --git a/src/components/AiTranslatedBadge.astro b/src/components/AiTranslatedBadge.astro new file mode 100644 index 0000000..a29cd91 --- /dev/null +++ b/src/components/AiTranslatedBadge.astro @@ -0,0 +1,28 @@ +--- +// AI 译文标注(用户拍板:文学内容机器翻译须明示) +import { t } from '../i18n/ui'; +interface Props { locale?: 'zh' | 'en' } +const { locale = 'en' } = Astro.props; +--- + +

{t('ai_translated_note', locale)}TMT

+ + diff --git a/src/components/Header.astro b/src/components/Header.astro index 44dd19b..2d0aeec 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -1,4 +1,6 @@ --- +import { localeOf, localePath } from '../lib/locale'; + // 顶部导航:≤4 项纪律(防 higan 十项复发);当前页 aria-current const nav = [ { href: '/archives/', label: '文章' }, @@ -8,6 +10,11 @@ const nav = [ const path = Astro.url.pathname; const isCurrent = (href: string) => path === href || path === href.replace(/\/$/, '') || path.startsWith(href); + +// 语言切换:同路径跨前缀跳转(zh 无前缀 ↔ /en/),预构建双语毫秒级 +const curLocale = localeOf(path); +const switchHref = localePath(path, curLocale === 'zh' ? 'en' : 'zh'); +const switchLabel = curLocale === 'zh' ? 'EN' : '中'; ---