Skip to content

国际化

支持的语言

主前端在 static/locales/ 下恰好有 8 个 locale 文件:

代码文件
zh-CNzh-CN.json
zh-TWzh-TW.json
enen.json
jaja.json
koko.json
ruru.json
eses.json
ptpt.json

任何改动都必须同步更新全部 8 个文件。它们是通过 i18next 点路径访问的嵌套 JSON 对象,不是扁平键值文件。

运行时与语言选择

static/i18n-i18next.js 加载本地 i18next 库,然后使用资源版本请求 /static/locales/.json。回退语言是 zh-CN

初始语言按以下顺序选择:

  1. GET /api/config/steam_language 返回的后端 uiLanguage 强制覆盖;
  2. URL 中的 ?ui_lang=?lang=
  3. 同一接口返回的规范化 Steam 语言;
  4. localStorage.i18nextLng
  5. navigator.language
  6. zh-CN

切换语言会保存 i18nextLng、更新文档语言、刷新已翻译的 DOM 节点,并派发 localechange

标记与脚本 API

根据目标属性使用对应标记:

html
<span data-i18n="settings.title"></span>
<input data-i18n-placeholder="chat.textInputPlaceholder">
<button data-i18n-title="common.close" data-i18n-aria="common.close"></button>
<img data-i18n-alt="avatar.previewAlt" alt="">

data-i18n-params 使用 JSON 保存插值参数;旧标记仍可使用 data-i18n-options。按钮同时含有图标等结构化内容时,应把翻译文字放入子 span

经典脚本可以调用 window.t(key, params)。加载器还暴露 window.i18nwindow.changeLanguagewindow.updatePageTextswindow.updateLive2DDynamicTextswindow.translateStatusMessage

普通翻译通过 textContent 写入。只有包含受支持 <br><img> 标记的翻译会进入已清洗的 HTML 路径;不允许任意翻译 HTML。

前端边界

  • React 聊天源码通过 frontend/react-neko-chat/src/i18n.ts 使用宿主的 window.t,并以英文文案作为最终回退。UI 暴露新文本时仍需添加主 locale 键。
  • Vue 插件管理器在 frontend/plugin-manager/src/i18n/locales/ 下维护独立的 TypeScript locale 包。其 8 种语言也必须对齐,但主页面 JSON 键不会自动出现在这里。
  • 后端 prompt 与运行时消息使用各自的翻译结构。切换主前端 locale 不会自动翻译服务器文本。

审查清单

修改用户可见文本时:

  1. 在全部 8 个 static/locales/*.json 中添加或更新相同嵌套键;
  2. 使用合适的 data-i18n-* 属性或 window.t()
  3. 在所有语言中保留一致的插值名称;
  4. 在运行时切换语言后检查页面,而不只检查刷新后的状态;
  5. React 或 Vue 源 locale 改动后重新构建对应产物;
  6. 验证所有 locale 文件可解析且叶子键集合一致。