国际化
项目基于 react-i18next(i18next 的 React 绑定)实现国际化,支持英文(en)和中文(zh)两种语言。
架构概览
apps/app/src/integrations/i18n/
├── config.ts # i18next 初始化 + 语言切换
├── LanguageSwitcher.tsx # 语言切换 UI 组件
└── locales/
├── en.json # 英文翻译
└── zh.json # 中文翻译
初始化配置
config.ts 是入口文件:
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./locales/en.json";
import zh from "./locales/zh.json";
export const supportedLngs = ["en", "zh"] as const;
export const fallbackLng = "en" as const;
export const storageKey = "daedalus-lang";
i18n.use(initReactI18next).init({
resources: { en: { translation: en }, zh: { translation: zh } },
lng: fallbackLng, // 默认英文
fallbackLng,
interpolation: { escapeValue: false }, // React 已做 XSS 防护
});
- 翻译 JSON 文件直接
import进来,不走 HTTP 懒加载 - 语言选择通过
localStorage持久化(key:daedalus-lang),刷新后可恢复 escapeValue: false:React 默认转义插值内容,i18next 无需重复转义
组件内用法
import { useTranslation } from "react-i18next";
const { t } = useTranslation();
然后在 JSX 中通过 t(key, fallback?) 获取翻译文本:
| 用法 | 示例 | 说明 |
|---|---|---|
| 简单 key | t("archetypeDetail.back") | 从 JSON 取 archetypeDetail.back |
| 带默认值 | t("archetypeDetail.implements", "IMPLEMENTED BY") | key 不存在时兜底 |
| 动态 key | t(overview.scope.${scope}, scope) | 变量拼接 key,fallback 用 scope 原值 |
| 复数 | t("jobs.findingsCount", { count: n }) | 自动匹配 _other 后缀 |
翻译文件结构
en.json / zh.json 按命名空间分层,扁平 JSON 结构:
{
"archetypeDetail": {
"back": "Archetypes",
"conditions": "Conditions",
"requires": "Requires →",
"requiredBy": "Required by ←",
...
},
"common": {
"edit": "Edit",
"cancel": "Cancel",
"unknown": "—",
...
},
"overview": {
"scope": {
"project": "Project",
"service": "Service",
...
}
}
}
命名规范:
- 页面级 key 以页面名命名,如
archetypeDetail、crateDetail、jobs - 通用 key 放在
common下 - scope / category 等枚举值放在对应命名空间下
语言切换
LanguageSwitcher.tsx 提供 EN / 中文 两个按钮:
export const LanguageSwitcher = function() {
const { i18n } = useTranslation();
const current = i18n.resolvedLanguage ?? i18n.language;
return (
<div>
<button onClick={() => setLanguage("en")}>EN</button>
<button onClick={() => setLanguage("zh")}>中文</button>
</div>
);
};
setLanguage 同时更新 i18next 和 localStorage:
export const setLanguage = (lang: "en" | "zh") => {
i18n.changeLanguage(lang);
localStorage.setItem(storageKey, lang);
};
添加新翻译的步骤
- 在
en.json中添加新的 key-value - 在
zh.json中对应位置添加中文翻译 - 组件中使用
t("namespace.key")引用
踩坑
- 不要用
t()做字符串拼接:如t("a") + " " + t("b"),不同语言的语序可能不同,应使用插值t("key", { ... })或直接写完整短语 .replace()是 hack:如t("archetypeDetail.requires").replace(" →", ""),本质是因为翻译 value 里混入了箭头符号。更好的做法是把箭头放在 JSX 中而非翻译文本里- fallback 值不能省:动态 key(如 scope 名)必须传 fallback,否则 key 拼错时直接显示原始 key 字符串