fix(i18n): localePath 三处双 en 一刀治+canonical 全量(blog-5f T2/T3 车道收编)

- T2:localePath 先归一 zh 再拼前缀(Header/CommandPalette/
  BaseLayout 三处 /en/en/ 同源病根一刀),返回值统一尾斜杠;
  BaseLayout 自指 canonical 全量 35 页;E2E 新增 en canonical
  自指断言(33→34)
- T3:content-lint.mjs 零依赖三检(断链 FAIL/缺图 FAIL/zh-en
  配对 WARN;CONTENT_LINT 逃生门;photos-originals 叠加层与
  /admin 单语两误报已修);prod-smoke.sh 三断言(robots 未落明
  确 FAIL 不静默);build.sh 守卫行挂载(smoke 对 staging 首版
  容忍,T1 robots 上线后转硬门,触发条件注释在案)
- tasks.md verify 字面量 33→34 联动同步(6 处)

车道:op-gitea(verify 六条实录);收编验收:E2E 34/34+产物零
/en/en/+lint 0/0/0 实跑复现

验证: node tests/e2e.mjs 34/34 PASS;! grep -r /en/en/ dist/;
      content-lint 三检 0 违例;bash -n+test -x 过

Spec: 2026-10-26_blog-5f

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-01 09:12:01 +08:00
1 parent 8ec1712135
commit c307285a25
7 files changed
+131 -9

No files matched your search

+6 -3
View File
@@ -7,9 +7,12 @@ export type Locale = 'zh' | 'en';
export const localeOf = (pathname: string): Locale =>
pathname === '/en' || pathname.startsWith('/en/') ? 'en' : 'zh';
/** 当前路径在另一语言下的对应路径(zh → /en/...,en → 去 /en 前缀)。 */
/** 当前路径在另一语言下的对应路径(zh → /en/...,en → 去 /en 前缀)。
* 尾斜杠归一:返回值一律带尾斜杠(与全站/sitemap 口径一致)。
* 先归一 zh 再拼前缀——en→en 场景若直接 /en+clean 会产出 /en/en/(T2 病根) */
export function localePath(pathname: string, to: Locale): string {
const clean = pathname.replace(/\/index\.html$/, '').replace(/\/$/, '') || '/';
if (to === 'en') return clean === '/' ? '/en/' : `/en${clean}`;
return clean.replace(/^\/en(?=\/|$)/, '') || '/';
const zh = clean.replace(/^\/en(?=\/|$)/, '') || '/';
const slash = (p: string) => (p === '/' ? '/' : `${p}/`);
return to === 'en' ? slash(zh === '/' ? '/en' : `/en${zh}`) : slash(zh);
}