Next.js i18n 字典与提供者(nextjs-i18n-usage)
用于在 React 服务器组件、客户端组件、Storybook 故事和测试工具中消费 next-intl 翻译的工程标准、钩子和提供者模式。
[!TIP] 实现模式: 请查阅
references/examples.md获取完整代码示例(RSC、客户端表单、语言切换器、Storybook 装饰器和测试包装器)。 快速执行: 将字典验证或键同步委托给轻量级子代理(Model: 'flash')。
1. 零硬编码契约
- 零硬编码文本: 绝不在 JSX 中编写面向用户的标签、占位符或回退字符串。
- 无模拟对象: 禁止使用文件中模拟的字典(例如
const DEFAULT_CONTENT = {...})。 - 同步同步: 添加/更新 UI 文案时,在编写 JSX 之前,须向
messages/[locale].json中的所有语言文件(例如messages/en.json和messages/fa.json)插入真实的翻译。
2. API 与钩子快速参考
| 环境/目标 | 钩子/API | 示例语法 |
|---|---|---|
| 服务器组件(RSC) | getTranslations | const t = await getTranslations('namespace'); |
| 服务器格式化器 | getFormatter | const format = await getFormatter(); format.dateTime(...) |
| 动态元数据 | getTranslations | export async function generateMetadata({ params }) { ... } |
| 客户端组件 | useTranslations | const t = useTranslations('namespace'); |
| 客户端格式化器 | useFormatter | const format = useFormatter(); format.number(...) |
| 富文本(客户端) | t.rich | t.rich('terms', { link: (c) => <Link href="/t">{c}</Link> }) |
| 导航 | @/i18n/navigation | import { Link, useRouter, usePathname } from '@/i18n/navigation'; |
| Storybook 预览 | NextIntlClientProvider | 将预览装饰器包裹在 <NextIntlClientProvider locale="en" messages={enMessages}> 中 |
| 单元测试(Jest) | renderWithIntl | 将渲染包裹在 <NextIntlClientProvider locale="en" messages={messages}> 中 |
3. BiDi(LTR / RTL)与样式标准
- 仅使用 Tailwind 逻辑属性:
- 禁止:
ml-*、mr-*、pl-*、pr-*、left-*、right-*、text-left、text-right - 必需:
ms-*、me-*、ps-*、pe-*、start-*、end-*、text-start、text-end
- 禁止:
- 动态方向: 为
fa/ar设置动态<html dir="rtl">,为en设置dir="ltr"。
4. 反模式与陷阱
| 错误 | 根本原因 | 解决方案 |
|---|---|---|
在 RSC 中使用 useTranslations | 钩子无法在异步服务器组件中运行 | 使用 await getTranslations('ns') |
在客户端中使用 getTranslations | 仅用于服务器的异步函数 | 使用 useTranslations('ns') 并添加 "use client" |
| “未找到国际化上下文” | Storybook/测试中缺少提供者 | 将故事/测试包裹在 <NextIntlClientProvider> 中 |
| 硬编码回退 | 例如 `t('btn') | |
原生 next/link | 路由变化时丢失语言前缀 | 使用来自 @/i18n/navigation 的 Link |
5. 一致性验证
执行字典一致性检查:
pwsh .agents/skills/nextjs-i18n-usage/scripts/verify-dictionaries.ps1