Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库/前端/项目笔记/代达罗斯/需求

国际化

2 分钟阅读 · Note

目录树 578 篇

            • 国际化
            • 需求整体流程
            • Linear
          • 项目待做
          • 性能优化
          • UI设计
      • 前端技术栈
    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 6

↗需求整体流程同一路径↗Linear同一路径↗「Feature」Introduce Crate as an independent metadata entity[ˈentəti] | 引入 Crate 作为独立元数据实体共同主题↗实施计划:Archetype 管理 (COD-86)共同主题↗引入Archetype共同主题↗用于稳定描述代码结构的数据结构方案共同主题
  • 国际化

国际化

项目基于 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?) 获取翻译文本:

用法示例说明
简单 keyt("archetypeDetail.back")从 JSON 取 archetypeDetail.back
带默认值t("archetypeDetail.implements", "IMPLEMENTED BY")key 不存在时兜底
动态 keyt(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);
};

添加新翻译的步骤

  1. 在 en.json 中添加新的 key-value
  2. 在 zh.json 中对应位置添加中文翻译
  3. 组件中使用 t("namespace.key") 引用

踩坑

  • 不要用 t() 做字符串拼接:如 t("a") + " " + t("b"),不同语言的语序可能不同,应使用插值 t("key", { ... }) 或直接写完整短语
  • .replace() 是 hack:如 t("archetypeDetail.requires").replace(" →", ""),本质是因为翻译 value 里混入了箭头符号。更好的做法是把箭头放在 JSX 中而非翻译文本里
  • fallback 值不能省:动态 key(如 scope 名)必须传 fallback,否则 key 拼错时直接显示原始 key 字符串