Files
blog/src/lib/locale.ts
T
wait4xandGLM-5.3 c74815b516 feat(i18n): /en/ 双语骨架——路由/切换/hreflang/回退/AI 标注
- 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
2026-10-25 09:20:16 +08:00

16 lines
694 B
TypeScript

/**
* 双语路径工具:zh 无前缀(历史 URL 1:1),en 加 /en/ 前缀。
* 语言切换 = 同路径跨前缀跳转(预构建双语,毫秒级)。
*/
export type Locale = 'zh' | 'en';
export const localeOf = (pathname: string): Locale =>
pathname === '/en' || pathname.startsWith('/en/') ? 'en' : 'zh';
/** 当前路径在另一语言下的对应路径(zh → /en/...,en → 去 /en 前缀)。 */
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(?=\/|$)/, '') || '/';
}