AionUi 多语言 i18n 架构与实战指南:从 i18next 初始化到 13 语言全球化
2026/9/19 5:16:20 网站建设 项目流程

AionUi 多语言 i18n 架构与实战指南:从 i18next 初始化到 13 语言全球化

【免费下载链接】AionUi免费、本地、开源的 24/7 全天候 Cowork 应用,以及适用于 Gemini CLI、Claude Code、Codex、OpenCode、Qwen Code、Goose CLI、Auggie 等的 OpenClaw | 🌟 喜欢就点star吧项目地址: https://gitcode.com/iOfficeAI/AionUi

AionUi 是一个基于 Electron 的本地 AI Cowork 桌面应用,其渲染层(renderer)采用 i18next + react-i18next 构建了一套可扩展的多语言体系,支持简体中文、英文、日文、繁体中文、韩文、土耳其文、俄文、乌克兰文、葡萄牙文(巴西)、德文、西班牙文、法文与波斯文共 13 种语言。本文以仓库中的 i18n README 为核心脉络,结合 i18n 初始化源码、语言配置、语言切换器组件 与 i18n 校验脚本 等实现证据,系统讲解语言包的目录结构、初始化与切换机制、翻译键命名规范、新增语言包的完整流程,以及数字、日期格式化和 RTL 布局等进阶主题。读完本文,你将能在 AionUi 中独立完成翻译键的添加、新语言包的接入与校验,并理解这套体系在桌面端与 WebUI 双端同步场景下的设计取舍。

一、技术选型与总体架构

AionUi 的渲染层选择i18next + react-i18next作为多语言基础设施(见 README 首行)。其中:

  • i18next是核心的国际化引擎,负责语言包资源管理、语言切换与回退(fallback);
  • react-i18next是面向 React 的绑定层,提供useTranslation()Hook,让组件在语言切换时自动重渲染。

围绕这两者,仓库在packages/desktop/src/renderer/services/i18n/目录下组织了一整套服务层代码:

文件职责
index.tsi18next 实例初始化、语言探测、懒加载与主进程同步
list.ts基于Intl.ListFormat的本地化列表拼接
format.ts基于Intl.*的数字、货币、日期、字节大小格式化
direction.ts依据应用语言推导文档方向(LTR/RTL)
i18n-keys.d.ts自动生成的翻译键联合类型(I18nKey)
locales/各语言的语言包目录

值得注意的是,当前仓库实际实现的架构与 README 中最初的“单一zh-CN.json/en-US.json”结构相比已经大幅演进:语言包被拆分为按功能模块组织的多个 JSON 文件,每个语言目录下还有聚合入口index.ts(例如 zh-CN/index.ts)。README 中描述的“两个语言包”是最简模型,而真实仓库已将其扩展为 13 语言的完整体系,本文后续将基于真实代码结构展开。

二、目录结构与语言包组织

2.1 语言包目录

所有语言包位于packages/desktop/src/renderer/services/i18n/locales/,每个语言一个子目录,目录名采用标准 BCP 47 标签(连字符分隔):

locales/ ├── zh-CN/ # 简体中文 ├── en-US/ # 英文 ├── ja-JP/ # 日文 ├── zh-TW/ # 繁体中文 ├── ko-KR/ # 韩文 ├── tr-TR/ # 土耳其文 ├── ru-RU/ # 俄文 ├── uk-UA/ # 乌克兰文 ├── pt-BR/ # 葡萄牙文(巴西) ├── de-DE/ # 德文 ├── es-ES/ # 西班牙文 ├── fr-FR/ # 法文 └── fa-IR/ # 波斯文(唯一的 RTL 语言)

每个语言目录下包含统一的模块文件集合,由 i18n-config.json 中的modules数组定义,共 19 个模块:commonagentModeupdateloginfileSelectionpreviewconversationsettingsmessagesmcpacpcodextoolsgooglecronguidagentteampet

以 zh-CN/ 为例:

zh-CN/ ├── index.ts # 聚合所有模块 JSON 并默认导出 ├── common.json # 通用按钮、文案 ├── conversation.json # 会话与聊天界面 ├── settings.json # 设置界面 ├── acp.json # ACP 代理协议相关 ├── agent.json # Agent 运行时相关 ├── cron.json # 定时任务 ├── preview.json # 文件预览 ├── team.json # 团队协作 ├── pet.json # 桌面宠物 └── ... # 其余模块

每个index.ts负责把本语言的各模块 JSON 导入并聚合导出(见 zh-CN/index.ts):

import common from './common.json'; import conversation from './conversation.json'; // ...其余模块 export default { common, conversation, // ...其余模块 };

模块化拆分的好处:翻译键天然按功能分区,多人协作时冲突面更小;同时 i18next 支持按命名空间(namespace)加载,为未来的按需加载留出了空间。

2.2 配置中心:i18n-config.json

语言支持情况与模块清单由 i18n-config.json 统一声明,它是主进程与渲染进程共享的单一事实来源(single source of truth):

{ "referenceLanguage": "en-US", "fallbackLanguage": "en-US", "supportedLanguages": [ "zh-CN", "en-US", "ja-JP", "zh-TW", "ko-KR", "tr-TR", "ru-RU", "uk-UA", "pt-BR", "de-DE", "es-ES", "fr-FR", "fa-IR" ], "modules": ["common", "agentMode", "update", "login", "fileSelection", "preview", "conversation", "settings", "messages", "mcp", "acp", "codex", "tools", "google", "cron", "guid", "agent", "team", "pet"] }

字段语义:

  • referenceLanguageen-US):翻译基准语言。校验脚本以它为基准比对各语言键的完整性;
  • fallbackLanguageen-US):回退语言。当某语言缺少某个键时,i18next 会回退到该语言包取值;
  • supportedLanguages:应用实际支持并随包分发的语言列表;
  • modules:每个语言必须提供的翻译模块清单。

该配置被 i18n.ts 读取并导出为SUPPORTED_LANGUAGESDEFAULT_LANGUAGE常量,供主进程与渲染进程两侧共用。

三、初始化流程与语言探测策略

3.1 不使用浏览器语言探测器

一个值得注意的设计决策是:AionUi 刻意不使用i18next-browser-languagedetector。在 index.ts 的初始化注释中明确说明了原因:

在 WebUI 模式下,浏览器的 localStorage 与 Electron 渲染进程位于不同的 origin,语言探测器会读取到错误(或缺失)的值并回退到navigator.language,导致语言不一致(Issue #1176)。

因此项目采用自定义的多级语言探测策略,核心逻辑在getInitialLanguage()中:

function getInitialLanguage(): SupportedLanguage { const backendStartupFailed = ...; const localStorageLanguage = getLocalStorageLanguageHint(); // localStorage 的 i18nextLng const injectedLanguage = getInjectedLanguageHint(); // window.__initialLanguage const systemLanguage = backendStartupFailed ? getElectronSystemLanguageHint() : null; const hint = backendStartupFailed ? injectedLanguage || localStorageLanguage || systemLanguage : localStorageLanguage || injectedLanguage; return normalizeLanguageCode(hint || DEFAULT_LANGUAGE); }

语言提示来源优先级如下:

  1. localStorage 中的i18nextLng:用户上次选择的语言(普通启动时的首选);
  2. window.__initialLanguage:Electron 注入的本地配置语言提示;
  3. navigator.language:仅在后端启动失败(__backendStartupFailed)时作为兜底,用于保证失败页也能以用户系统语言呈现;
  4. 以上都不可用时,回退到DEFAULT_LANGUAGE(en-US)。

3.2 同步加载回退语言,避免 FOUC

为避免首帧出现错误的语言闪烁(FOUC),初始化时会将默认回退语言与初始语言同步注入 i18next 的 resources:

const initialResources = { [DEFAULT_LANGUAGE]: { translation: fallbackLocale }, }; if (initialLanguage !== DEFAULT_LANGUAGE) { initialResources[initialLanguage] = { translation: getLocaleModules(initialLanguage) }; } i18n.use(initReactI18next).init({ resources: initialResources, lng: initialLanguage, fallbackLng: DEFAULT_LANGUAGE, interpolation: { escapeValue: false }, });

interpolation.escapeValue: false是 react-i18next 的标准配置——React 自身已经处理了 XSS 转义,无需 i18next 再转义一次。

3.3 configService 作为语言权威来源

初始化完成后,initLanguage()会等待configService.whenReady(),从后端配置中读取权威的语言设置并切换:

async function initLanguage(): Promise<void> { await configService.whenReady(); const savedLanguage = configService.get('language'); const language = savedLanguage || normalizeLanguageCode(navigator.language || DEFAULT_LANGUAGE); await ensureAndSwitch(i18n, language, loadLocaleModules); localStorage.setItem('i18nextLng', normalizeLanguageCode(language)); }

这套流程形成了清晰的层级:localStorage / 注入提示只是“快速提示”,后端 configService 才是权威真相。语言选择落盘到后端配置后,即使清空浏览器缓存,语言也不会丢失。

3.4 语言切换的懒加载

i18next 初始化后,通过监听languageChanged事件实现按需加载语言包:

i18n.on('languageChanged', async (lang: string) => { const normalizedLang = normalizeLanguageCode(lang); if (i18n.hasResourceBundle(normalizedLang, 'translation')) return; const translation = await loadLocaleModules(normalizedLang); i18n.addResourceBundle(normalizedLang, 'translation', translation, true, true); });

语言包本身是静态 import(见 index.ts 顶部的一系列import enUS from './locales/en-US/index'),以保证打包后的应用始终可以离线切换任意语言,无需网络请求。

3.5 语言代码归一化:normalizeLanguageCode

用户提供的语言代码可能是zhja_JPzh-Hant等多种形态,i18n.ts 中的normalizeLanguageCode()负责将其归一为受支持的 BCP 47 标签:

export function normalizeLanguageCode(language: string): SupportedLanguage { const normalized = language.replace(/_/g, '-'); if (SUPPORTED_LANGUAGES.includes(normalized)) return normalized; const lower = normalized.toLowerCase(); // 繁体中文区域的读者期望 zh-TW,不能降级为简体 if (lower.startsWith('zh')) { return /\bhant\b|-hk\b|-mo\b/.test(lower) ? 'zh-TW' : 'zh-CN'; } // 按语言主码映射:ja→ja-JP、ko→ko-KR、fa→fa-IR ... const langOnly = lower.split('-')[0]; switch (langOnly) { /* ... */ default: return DEFAULT_LANGUAGE; } }

一个关键的细节是:zh-HKzh-MOzh-Hant-*会归一化为zh-TW而非zh-CN,避免繁体字区域用户被错误地切到简体中文。

3.6 回退合并:mergeWithFallback

当某语言缺少部分翻译键时,AionUi 并不完全依赖 i18next 的运行时回退,而是在加载时就做深度合并

export function mergeWithFallback(fallback, target) { const merged = { ...fallback }; for (const [key, value] of Object.entries(target)) { if (isPlainObject(merged[key]) && isPlainObject(value)) { merged[key] = mergeWithFallback(merged[key], value); // 递归合并 } else { merged[key] = value; } } return merged; }

在 index.ts 的getLocaleModules()中,非默认语言加载时都会调用mergeWithFallback(fallbackLocale, modules),确保缺失键在运行时也能拿到兜底文案。

四、在组件中使用翻译

4.1 useTranslation Hook 的基本用法

在任意 React 组件中,通过useTranslation()获取t函数:

import { useTranslation } from 'react-i18next'; const MyComponent = () => { const { t } = useTranslation(); return ( <div> <h1>{t('common.title')}</h1> <p>{t('common.description')}</p> </div> ); };

t('key')支持点号分隔的嵌套键路径,例如t('common.send')会解析到common模块下send键的值。react-i18next 会在i18n.language变化时自动触发使用该 Hook 的组件重渲染。

4.2 完整可用的语言切换器实现

仓库真实的语言切换器位于 LanguageSwitcher.tsx,它比 README 中的简化示例更完整,可作为生产级参考:

import AionSelect from '@/renderer/components/base/AionSelect'; import { useTranslation } from 'react-i18next'; import { changeLanguage } from '@/renderer/services/i18n'; const LanguageSwitcher: React.FC = () => { const { i18n } = useTranslation(); const selectRef = useRef<SelectHandle>(null); const handleLanguageChange = useCallback((value: string) => { // 先 blur 触发元素,避免下拉层与语言切换竞争布局 selectRef.current?.blur?.(); const applyLanguage = () => { changeLanguage(value).catch((error: Error) => { console.error('Failed to change language:', error); }); }; // 延迟到下一帧执行,确保 DOM 动画完成 if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) { window.requestAnimationFrame(() => window.requestAnimationFrame(applyLanguage)); } else { setTimeout(applyLanguage, 0); } }, []); return ( <div className='flex items-center gap-8px'> <AionSelect ref={selectRef} className='w-160px' value={i18n.language} onChange={handleLanguageChange}> <AionSelect.Option value='zh-CN'>简体中文</AionSelect.Option> <AionSelect.Option value='zh-TW'>繁體中文</AionSelect.Option> <AionSelect.Option value='ja-JP'>日本語</AionSelect.Option> <AionSelect.Option value='ko-KR'>한국어</AionSelect.Option> <AionSelect.Option value='tr-TR'>Türkçe</AionSelect.Option> <AionSelect.Option value='ru-RU'>Русский</AionSelect.Option> <AionSelect.Option value='uk-UA'>Українська</AionSelect.Option> <AionSelect.Option value='pt-BR'>Português (BR)</AionSelect.Option> <AionSelect.Option value='de-DE'>Deutsch</AionSelect.Option> <AionSelect.Option value='es-ES'>Español</AionSelect.Option> <AionSelect.Option value='fr-FR'>Français</AionSelect.Option> <AionSelect.Option value='fa-IR'>فارسی</AionSelect.Option> <AionSelect.Option value='en-US'>English</AionSelect.Option> </AionSelect> </div> ); };

该组件体现了两个工程细节:一是切换前先 blur 下拉框,避免弹层与语言切换互相干扰布局;二是通过双重requestAnimationFramechangeLanguage推迟到下一帧,确保 DOM 动画结束后再触发重渲染。

4.3 切换语言的核心函数 changeLanguage

组件最终调用的是 index.ts 导出的changeLanguage(),它的完整链路是:

export async function changeLanguage(lang: string): Promise<void> { await ensureAndSwitch(i18n, lang, loadLocaleModules); // 加载语言包并切换 const normalized = normalizeLanguageCode(lang); await configService.set('language', normalized); // 写入后端配置(权威) localStorage.setItem('i18nextLng', normalized); // 同步 localStorage 提示 ipcBridge.systemSettings.changeLanguage.invoke({ language: normalized }); // 通知主进程 }

它依次完成四件事:

  1. 加载并切换:通过ensureAndSwitch()(见 i18n.ts)判断语言包是否已加载,未加载则先addResourceBundle,再changeLanguage
  2. 持久化到后端配置configService.set('language', ...),保证重启后语言生效;
  3. 同步 localStorage:让 WebUI 下次加载时能快速命中;
  4. 通知主进程:通过 IPC 广播语言变更,驱动系统托盘菜单等主进程侧文案同步更新。

4.4 桌面端与 WebUI 的实时同步

index.ts 还监听了主进程广播的语言变更事件:

ipcBridge.systemSettings.languageChanged.on(async ({ language }) => { const normalized = normalizeLanguageCode(language); if (i18n.language === normalized) return; // 自己触发的变更直接跳过 await ensureAndSwitch(i18n, normalized, loadLocaleModules); localStorage.setItem('i18nextLng', normalized); });

这意味着桌面端与 WebUI 中任意一端切换语言,另一端会立即同步更新,无需重启

五、翻译键的命名规范与语言包格式

5.1 命名规范

README 明确规定了翻译键的命名规范,当前仓库的实现完全遵循:

  • 使用点号分隔的层级结构common.sendconversation.welcome.title
  • 使用小写字母和下划线:如copySuccessopenInSystemBrowserfileAttach.uploading等,均为小驼峰或下划线风格,键内单词以下划线连接;
  • 按功能模块分组:键的顶层命名空间与模块 JSON 文件名一一对应。

以 README 中的示例为基础,对照仓库真实语言包,一个完整的语言包片段(zh-CN)如下:

{ "common": { "send": "发送", "cancel": "取消", "save": "保存", "delete": "删除", "confirm": "确定" }, "conversation": { "welcome": { "title": "今天有什么安排?" } } }

实际仓库中conversation模块要丰富得多,例如conversation.welcome.titleconversation.welcome.placeholderconversation.welcome.newConversation等欢迎区文案(见 en-US 的 i18n-keys.d.ts 中conversation.welcome.*键)。

5.2 键的自动生成类型:I18nKey

仓库通过 generate-i18n-types.js 从参考语言包自动生成 i18n-keys.d.ts,其中导出一个包含全部翻译键字符串字面量的联合类型:

export type I18nKey = | 'common.send' | 'common.cancel' | 'conversation.welcome.title' | 'conversation.agentError.codes.USER_AGENT_DISCONNECTED.title' | /* ... 数百个键 */;

该类型在渲染进程的I18nModule类型中被引用(export type { I18nKey, I18nModule } from './i18n-keys'),让t()的键参数享受完整的 TypeScript 编译期检查——写错键名会在编译阶段直接报错,而不是等到运行时才发现文案缺失。

5.3 插值(Interpolation)与复数

i18next 的插值语法在语言包中同样可用。例如conversation.minimap.count_one/conversation.minimap.count_other这样的键对,就是 i18next 的复数形式(_one/_other后缀),组件中通过t('conversation.minimap.count', { count })调用,i18next 会根据count值自动选择合适的复数形态。

六、新增翻译与新增语言的完整流程

6.1 新增一个翻译键(三步骤)

  1. 在 zh-CN 对应模块 JSON 中添加中文翻译,例如在packages/desktop/src/renderer/services/i18n/locales/zh-CN/common.json中加入"retry": "重试"
  2. 在 en-US 对应模块 JSON 中添加对应英文翻译(参考语言),例如在packages/desktop/src/renderer/services/i18n/locales/en-US/common.json中加入"retry": "Retry"
  3. 在组件中使用t('common.retry')获取翻译

注意:由于 en-US 是 referenceLanguage,新增键时必须同步更新 en-US 语言包,否则校验脚本会报错。

6.2 新增一个语言包

当前架构下新增语言(以新增it-IT为例)需要:

  1. 在 i18n-config.json 的supportedLanguages数组中添加"it-IT"
  2. 复制任意现有语言目录为locales/it-IT/,按 en-US 基准翻译全部 19 个模块 JSON;
  3. 在 index.ts 中静态 import 并注册'it-IT': itITlocaleData映射;
  4. normalizeLanguageCode()(i18n.ts)中补充case 'it': return 'it-IT';的语言主码映射;
  5. 如语言为 RTL 布局,还需在 direction.ts 的RTL_LANGUAGES集合中登记;
  6. 在 LanguageSwitcher.tsx 的下拉选项中添加对应选项(以该语言母语名称展示)。

6.3 自动校验:check-i18n.js

仓库提供了强大的 i18n 一致性校验脚本 check-i18n.js,用于 pre-commit 钩子:

node scripts/check-i18n.js

脚本的校验维度包括:

  • 目录结构:检查每个受支持语言目录是否存在、19 个必需模块文件是否齐全、JSON 语法是否合法、是否残留旧式的单一语言包文件(zh-CN.json这种旧格式会被报错要求删除);
  • 键一致性:以 en-US(referenceLanguage)为基准,比对其他语言包是否缺失键或存在多余键;
  • 硬编码检测:扫描渲染层源码,检测未被翻译函数包裹的用户可见文本。
✅ Locale directory exists: en-US ❌ Missing module file: it-IT/cron.json 🔑 Checking translation key consistency...

这条流水线保证了 13 种语言在每次提交时都保持键的完全对齐,从机制上杜绝了“某语言漏翻”悄悄进入主分支。

七、进阶主题:本地化格式化与 RTL 布局

7.1 为什么不能直接使用 toLocaleString()

README 未涉及的另一个重要话题是本地化格式化。AionUi 在 format.ts 中实现了全套格式化工具,其动机在文件注释中讲得很清楚:

Intl.NumberFormat(undefined, …)Date.prototype.toLocaleString()系列解析的是宿主操作系统的语言环境,与用户在 AionUi 内选择的语言无关。一台运行英文版 AionUi 的德文系统会渲染出0,42 $17.8.2025,与英文标签混在一起。

因此,所有用户可见的数字、日期都必须以应用语言显式格式化,语言参数来自useTranslation().i18n.language。工具函数如下:

函数作用示例
formatNumber(value, language)数字格式化de-DE 下12.612,6
formatCurrency(amount, currency, language)货币格式化,含非法货币码兜底非法 code 时回退为12.5 USD形式
formatDateTime(value, language)日期时间复刻toLocaleString()默认值
formatDate/formatTime纯日期 / 纯时间toLocaleDateString()/toLocaleTimeString()的替代
formatByteSize(bytes, language)字节大小12.5 MB(de-DE 渲染12,5 MB
formatByteRate(bytesPerSecond, language)传输速率1.2 MB/s
formatNameList(names, language)人名/列表拼接基于Intl.ListFormat,zh 用顿号、fa 用阿拉伯逗号、de/fr 用 und/et

实现上还做了性能优化:Intl.NumberFormat/Intl.DateTimeFormat的构造相对昂贵,而这些格式化函数经常在列表渲染中调用,因此 format.ts 以locale|options为键缓存了已构造的 formatter 实例。

7.2 RTL:波斯文的布局适配

方向处理 从应用语言推导文档方向,而非宿主系统:

const RTL_LANGUAGES: ReadonlySet<string> = new Set(['fa-IR']); export function applyDocumentDirection(language) { document.documentElement.dir = isRtlLanguage(language) ? 'rtl' : 'ltr'; document.documentElement.lang = normalizeLanguageCode(language); }

fa-IR(波斯文)是 AionUi 唯一自带的 RTL 语言。方向切换后:

  • <html dir>驱动渲染层中使用的 CSS 逻辑属性(logical properties)与 flex/grid 的 start/end 方向;
  • <html lang>驱动拼写检查、CJK 字形选择和无障碍技术(assistive technology)。

index.ts 单独注册了一个languageChanged监听器调用applyDocumentDirection,并在模块加载时立即执行一次,保证首次渲染方向正确。注释还给出了一条实用的开发约定:代码块、终端输出、文件路径等天生从左到右的内容,应在容器上用dir="ltr"局部跳出 RTL,而不是与文档方向对抗

八、测试与质量保障

AionUi 对 i18n 的测试覆盖在多份测试文件中可见(位于 tests/unit/common/ 等目录):

  • i18n.test.ts:覆盖语言代码归一化、回退合并等核心工具函数;
  • i18nDirection.dom.test.ts:DOM 环境下方向应用与切换行为的测试;
  • i18nFormat.test.ts:验证数字、日期、货币等格式化函数在多种语言下的输出。

结合 check-i18n.js 的 pre-commit 校验、generate-i18n-types.js 的类型生成,以及测试套件,形成了「生成类型 → 组件编译期校验 → 提交前键一致性检查 → 单元/DOM 测试」的完整质量闭环。

九、开发注意事项与最佳实践

综合 README 的「注意事项」一节与仓库实现,整理如下:

  1. 所有用户可见文本都应使用翻译函数,避免在代码中硬编码字符串——check-i18n.js会扫描渲染层源码检测硬编码文本;
  2. 翻译键应具有描述性,便于维护:优先conversation.welcome.title而非conversation.w1这类无意义缩写;
  3. 新增翻译时确保中英文都有对应翻译:en-US 是 referenceLanguage 与 fallbackLanguage,缺了它校验脚本会直接报错;
  4. 不要在组件里自行拼接列表分隔符:中文的顿号、德文的 "und" 各不相同,应使用formatNameList()
  5. 不要用宿主系统语言格式化数字/日期:统一走format.ts,并把i18n.language显式传入;
  6. 不要直接修改 i18n-keys.d.ts:该文件由脚本自动生成(文件头有AUTO-GENERATED FILE - DO NOT EDIT声明),修改语言包后重新运行生成脚本即可;
  7. RTL 语言的内容容器要按需局部dir="ltr",例如代码块与终端输出。

十、总结

AionUi 的 i18n 体系围绕i18next + react-i18next构建,但在工程化层面做了大量超越框架默认能力的强化:自定义语言探测(绕开i18next-browser-languagedetector在 WebUI/桌面双端 origin 不一致的坑)、模块化语言包 + 自动生成的I18nKey类型、configService作为语言权威来源、桌面端与 WebUI 的语言实时同步、基于Intl.*的本地化格式化层、以及 fa-IR 的 RTL 布局支持。13 种语言包在 pre-commit 校验脚本与测试套件的守护下保持键级对齐。

对于开发者而言,日常接触最多的仍是三个动作:在语言包 JSON 中加键、在组件中用t()取文案、跑node scripts/check-i18n.js校验。理解了本文的初始化链路与工程化细节后,你不仅能熟练完成这些操作,还能在遇到「语言切换不生效」「WebUI 与桌面端语言不一致」「某语言缺翻译」等问题时,快速定位到对应的机制环节。

相关资源

  • i18n 说明文档
  • i18n 初始化源码
  • 语言支持配置
  • i18n 工具函数(归一化/回退合并)
  • 语言切换器组件
  • 本地化格式化工具
  • RTL 方向处理
  • 翻译键自动生成脚本
  • i18n 一致性校验脚本

【免费下载链接】AionUi免费、本地、开源的 24/7 全天候 Cowork 应用,以及适用于 Gemini CLI、Claude Code、Codex、OpenCode、Qwen Code、Goose CLI、Auggie 等的 OpenClaw | 🌟 喜欢就点star吧项目地址: https://gitcode.com/iOfficeAI/AionUi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询