跳到正文
工程约 1 分钟

国际化

路径级 locale、同步预渲染、严格 key 对齐与 hreflang。

更新于 2025年11月6日约 1 分钟编辑此页
本页目录

Locale 是 URL 的一部分。英文无前缀,中文在 /zh,因此每个页面在两种语言下都可分享、可缓存、可索引。

首次访问#

<head> 中的一小段脚本先读取已存偏好,再读取 navigator.languages。中文浏览器进入无前缀 URL 时会在首帧前跳到 /zh,英文浏览器留在原地。跳转是单向的:/zh URL 永远不会被跳走,同源深链保持当前语言,爬虫直接跳过。

  • 渲染出的 locale 会被保存,语言菜单在跳转前显式写入。
  • 跳转保留路径、查询参数与 hash。
  • 两种语言都已预渲染;脚本只选择入口,不生成页面。

路由#

Locale 工具typescript
localePath('zh', '/docs/mcp') // '/zh/docs/mcp'stripLocale('/zh/docs/mcp')    // '/docs/mcp'switchLocalePath('/lumo', 'zh') // '/zh/lumo'

路由表按 locale 生成,因此产品页与它的翻译是同一个组件。Locale Provider 从 useLocation() 推导当前语言,并选择对应的 i18next 实例。

同步预渲染#

i18next 使用 initAsync: false 和打包资源初始化。这使初始化同步完成,是静态生成的前提:中文路由在构建时就必须包含中文 HTML,而不是等水合后才有。

每个 locale 一个实例typescript
const instance = i18next.createInstance();instance.init({  lng: locale,  resources,  initAsync: false,});

内容#

  • 界面文案在 app/lib/i18n/resources/{en,zh}.ts。
  • 长文档在 app/content/docs/{en,zh}.ts,使用同一套 DocBlock 模型。
  • 测试会比较中英文 key 树;缺 key 会在运行时之前失败。
  • 技术标识(chrome.userScripts、GM_setValue)保持英文。

SEO#

  • 每个路由输出自己的 title、description、canonical、Open Graph 与 Twitter 标签。
  • hreflang 配对两种语言,并为英文页提供 x-default。
  • 构建后从预渲染 HTML 生成 sitemap。

新增语言#

  1. 1

    新增资源

    创建翻译对象,并按英文结构做类型约束。

  2. 2

    扩展 manifest

    把 locale 加进 LOCALES 与 LOCALE_META。路由生成与语言菜单会自动接管。

  3. 3

    新增内容

    翻译文档集合。完整性测试会列出缺失的 slug。

  4. 4

    预渲染

    把 locale 加进 react-router.config.ts 的文档路径列表。