next-intl 负责 UI 字符串(在
messages/ 下),加上一层薄薄的命名约定负责 MDX 内容(在 content/ 下)。
熟悉这套规则后,写两遍就行,不需要额外仪式。
前置条件
无。管线都接好了,你只管加文件。路由如何识别语言
路由策略是as-needed(见 src/i18n/routing.ts):
- 英文(默认)走根路径:
/docs/quickstart - 中文加前缀:
/zh/docs/quickstart - 语言列表来自
siteConfig.i18n.locales(['en', 'zh'])
setRequestLocale(locale)——
不调的话 server component 会退回到默认语言,所有 t(...) 都默默用错语言。
MDX 命名约定
每篇内容两个文件并排放:.zh.mdx 后缀是唯一的信号——没有单独的目录,没有 JSON 清单。
src/lib/source-helpers.ts 里的 helper 会去掉后缀算出 canonical slug。
按语言查找
三个 helper 覆盖所有场景:pickByLocale('zh') 优先返回 .zh.mdx,没有就回落到英文版——
所以 /zh/ 永远不会因为缺翻译而 404。
UI 字符串——两份文件,同一套 key
翻译放在messages/en.json 与 messages/zh.json。两份文件的 key 结构必须一致,
靠 scripts/check-i18n.mjs 做结构 diff。
en.json 加新 key 时,请同时在 zh.json 同位置加上——
哪怕中文是占位符。否则 validator 会报错。
新增一种语言
- 追加到
siteConfig.i18n.locales(如['en', 'zh', 'ja'])。 - 创建
messages/ja.json,结构镜像en.json。 - 任何想翻译的 MDX,加上
slug.ja.mdx。 - 如果要非 en 的回落策略,在
pickByLocale里加分支。
验证一下
t('foo.bar') 字面调用。
常见坑(5 个)
- 忘写
.zh.mdx——/zh/页面悄悄回落到英文。开发时切到中文模式手动点一遍才能发现。 - 两份文件的日期对不上——更新英文博客时记得把
.zh.mdx的 date 也改了, 否则首页排序顺序会分叉。 - 模板字符串
t()调用——t(\Foo.$`)` 没法静态校验, validator 只能检查前缀存在。要靠实际跑页面来兜底。 - 少了
setRequestLocale(locale)——会让 locale 前缀页面用默认语言渲染, 极易漏掉。 - 直接用
next/link——一定要从@/i18n/navigation导入Link与useRouter,否则 client 跳转会丢掉 locale 前缀。
官方文档
- next-intl.dev——i18n 层的完整参考
- next-intl App Router——request config 与 routing
- Next.js i18n 路由——Next.js 基础