界面本地化
约 920 字大约 3 分钟
客户端展示的 M9A 项目文本——任务名称、选项标签、说明、预设、资源与控制器名称——来自 interface.json 和 tasks/ 下的文件。这些字符串通过 MaaFramework Project Interface V2 的国际化机制进行本地化。
工作方式
interface.json 中声明可用的翻译文件:
"languages": {
"zh_cn": "locales/zh_cn.json",
"en_us": "locales/en_us.json"
}路径相对于 interface.json 所在目录。M9A 将这些 Project Interface 资产放在项目根目录的 locales/ 中,而不是 resource/;后者只存放 MaaFW 运行资源。(i18n 指国际化机制,locales 指语言数据目录。)每个翻译文件都是「键 → 译文」的扁平映射:
{
"Task.Wilderness": "收取荒原",
"Option.Wilderness.Wellspring": "好梦井"
}任何支持国际化的字段,只要其值以 $ 开头,就会被当作翻译文件中的键。客户端按当前语言解析该键。缺少译文时的回退行为取决于客户端,可能显示键本身或回退到稳定名称,因此所有引用都必须通过 pnpm check:i18n 保证完整。
{
"name": "收取荒原",
"label": "$Task.Wilderness",
"entry": "Wilderness"
}name 是 ID,不是显示名
name 是稳定标识符。它会被写入用户配置文件,并被预设的任务列表以及各任务的 option 数组引用,因此重命名会破坏用户已有的配置。它保持中文原样不变,显示文本改由 label 提供。
option 映射的键和 cases[].name 同理:在旁边新增 label,绝不要改写键本身。
如果某个 case 的 name 在各语言下写法一致(Yes、No、24h、MAX、纯数字等),则无需 label,客户端会回退显示 name;但其 description 仍可能需要一个键。
支持填键的字段
label、description、desc、pattern_msg、icon、doc,以及项目级的 title、contact、license、welcome。注意 pipeline_override 属于面向游戏的 pipeline 数据,不参与翻译。
键命名规范
键使用 ASCII、以点分隔,结构与字符串出现的位置一致:
| 类型 | 格式 | 示例 |
|---|---|---|
| 任务 | Task.<Name> | Task.BalancedFarming |
| 任务说明 | Task.<Name>.desc | Task.BalancedFarming.desc |
| 选项 | Option.<Task>.<Option> | Option.Combat.StageType |
| 选项 case | Option.<Task>.<Option>.<Case> | Option.Combat.StageType.MainStory |
| 选项输入框 | Option.<Task>.<Option>.<Input> | Option.Combat.StageCustom.Chapter |
| 预设 | Preset.<Name> | Preset.DailyIdle |
| 欢迎公告 | Welcome.<Index> | Welcome.1 |
| 接口层级 | Controller.*、Resource.*、Group.* | Resource.GlobalEn |
说明追加 .desc,pattern_msg 追加 .msg。被多个选项共用的字符串(例如编队序号)使用 Common.* 键,只需翻译一次。
新增任务的流程
- 照常在
tasks/下编写任务,name保持中文。 - 添加
"label": "$Task.<Name>";若有说明,再添加"description": "$Task.<Name>.desc"。 - 在
locales/zh_cn.json和locales/en_us.json两个文件中补上对应条目。 - 运行
pnpm check:i18n。
校验
pnpm check:i18n 已并入 pnpm check,出现以下情况会导致校验失败:
- 某个
$key引用在语言文件中缺少对应条目 - 语言文件中存在已无人引用的条目
- 两个语言文件的键集合不一致
- 任意支持国际化的字段仍然写死了中文
新增语言
在 interface.json 的 languages 中添加文件,复制 locales/zh_cn.json 作为起点并翻译其值即可。校验要求新文件的键集合与现有文件完全一致。
后续扩展:多命名空间
locales/ 只承载 Project Interface 界面文案,因此现在是 <lang>.json 的扁平结构——语言在最外层,与 Rails、gettext、Chrome、Android 等主流约定一致。
将来 agent 若也需要自己的文案,沿用同一分层方式扩展为 <lang>/<namespace>.json(locales/zh_cn/interface.json、locales/zh_cn/agent.json),并同步 interface.json 的 languages。届时 tools/build-release.mjs 需要改为打包整个 locales/ 目录——它现在只打包 languages 中显式声明的文件,新增的命名空间不会自动进发布包。
