国际化
支持的语言
主前端在 static/locales/ 下恰好有 8 个 locale 文件:
| 代码 | 文件 |
|---|---|
zh-CN | zh-CN.json |
zh-TW | zh-TW.json |
en | en.json |
ja | ja.json |
ko | ko.json |
ru | ru.json |
es | es.json |
pt | pt.json |
任何改动都必须同步更新全部 8 个文件。它们是通过 i18next 点路径访问的嵌套 JSON 对象,不是扁平键值文件。
运行时与语言选择
static/i18n-i18next.js 加载本地 i18next 库,然后使用资源版本请求 /static/locales/.json。回退语言是 zh-CN。
初始语言按以下顺序选择:
GET /api/config/steam_language返回的后端uiLanguage强制覆盖;- URL 中的
?ui_lang=或?lang=; - 同一接口返回的规范化 Steam 语言;
localStorage.i18nextLng;navigator.language;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.i18n、window.changeLanguage、window.updatePageTexts、window.updateLive2DDynamicTexts 和 window.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 不会自动翻译服务器文本。
审查清单
修改用户可见文本时:
- 在全部 8 个
static/locales/*.json中添加或更新相同嵌套键; - 使用合适的
data-i18n-*属性或window.t(); - 在所有语言中保留一致的插值名称;
- 在运行时切换语言后检查页面,而不只检查刷新后的状态;
- React 或 Vue 源 locale 改动后重新构建对应产物;
- 验证所有 locale 文件可解析且叶子键集合一致。
