i18n
规则
- Next.js App Router:使用
next-intl — useTranslations() 钩子、NextIntlClientProvider、用于本地化检测的中间件
- React SPA:使用
react-i18next — useTranslation() 钩子、使用 i18next-http-backend 进行懒加载的 i18n.init()
- 本地化路由:
/en/about、/fr/about — 使用中间件检测 Accept-Language 头并进行重定向
- 翻译文件:每个区域每个命名空间一个 JSON 文件 —
messages/en/common.json、messages/fr/common.json
- 命名空间拆分:每个功能/页面一个命名空间 —
auth.json、dashboard.json、settings.json — 只加载页面所需的资源
- 复数化:使用 ICU 消息格式 —
{count, plural, one {# 个项目} other {# 个项目}}
- 插值:
t('greeting', { name }) — 永远不要拼接翻译后的字符串
- 日期/数字/货币:使用
Intl.DateTimeFormat、Intl.NumberFormat — 永远不要硬编码格式
- RTL 支持:在
<html> 上使用 dir="rtl"、CSS 逻辑属性(使用 margin-inline-start 而非 margin-left)、使用阿拉伯语/希伯来语进行测试
模式
import createMiddleware from "next-intl/middleware";
export default createMiddleware({
locales: ["en", "fr", "de", "ar"],
defaultLocale: "en",
});
import { useTranslations } from "next-intl";
function ProductCard({ price, date }: { price: number; date: Date }) {
const t = useTranslations("products");
const format = useFormatter();
return (
<div>
<h2>{t("title")}</h2>
<p>{format.number(price, { style: "currency", currency: "USD" })}</p>
<p>{format.dateTime(date, { dateStyle: "medium" })}</p>
</div>
);
}
避免
- 硬编码面向用户的字符串 — 每个字符串都必须通过
t() 处理
- 为翻译后的文本进行字符串拼接 — 使用插值或 ICU 格式
- 预先加载所有语言环境 — 按区域和命名空间进行懒加载
- 在布局中使用 CSS
left/right — 使用逻辑属性以确保 RTL 兼容性
- 仅将语言环境存储在
localStorage 中 — 使用基于 URL 的语言环境以确保 SEO 和可分享性