Ace 编辑器国际化实战指南:翻译文件生成、nls 消息提取与运行时查找机制
【免费下载链接】aceAce (Ajax.org Cloud9 Editor)项目地址: https://gitcode.com/gh_mirrors/ac/ace
本文基于 Ace(Ajax.org Cloud9 Editor)仓库的 translations/Readme.md 展开,系统讲解如何为 Ace 编辑器添加全新的语言翻译文件(.json)、如何通过构建脚本Makefile.dryice.js nls自动提取源码中的待翻译消息,并深入解析 Ace 运行时(src/lib/app_config.js)的nls()翻译查找与占位符替换机制。读完本文,你将掌握从“创建语言文件”到“消息被界面消费”的完整国际化工作流,并能够为 Ace 自行新增一种语言支持。
一、生成新翻译文件的标准流程
Ace 的界面文本(如自动补全弹窗提示、搜索框按钮标题、无障碍 ARIA 标签等)默认以英文硬编码在源码中,通过nls()调用包裹。若要提供本地化界面,需要按以下三步生成并填充翻译文件(原文出处:translations/Readme.md):
第 1 步:创建语言文件
在仓库的translations/目录下新建一个 JSON 文件,文件名为目标语言的 ID,例如中文可用zh.json、法语可用fr.json:
translations/<language_id>.json语言 ID 的命名完全由你决定,只要不与现有文件冲突即可。当前仓库已存在的语言文件包括am.json(阿姆哈拉语)、es.json(西班牙语)、ru.json(俄语)、sl.json(斯洛文尼亚语),新增文件时同样放在该目录下。
第 2 步:写入$id字段
在空的 JSON 文件中写入语言 ID 标识:
{ "$id": "<language_id>" }例如为俄语文件写入的就是{"$id": "ru"}(见 translations/ru.json)。这个$id字段至关重要:运行时定位到某份翻译消息表后,会读取其$id用于调试告警信息(详见下文“运行时查找机制”)。
第 3 步:运行 nls 提取命令
在仓库根目录执行:
node Makefile.dryice.js nls该命令会自动扫描src/下的源码,提取所有nls("key", "defaultString")调用,完成两件事:
- 同步默认英文消息表:把源码中新出现的、尚未登记的消息写入 src/lib/default_english_messages.js;
- 补齐所有翻译文件:把默认消息表中每个 key 都合并进
translations/下每个.json翻译文件,缺失的翻译统一填充为空字符串"",供翻译者逐条填写。
命令执行后,控制台会输出Saved <文件名>之类的提示,对应实现见 Makefile.dryice.js 的extractNls()函数。
二、extractNls() 到底做了什么:源码级拆解
node Makefile.dryice.js nls入口在 Makefile.dryice.js,命中type == "nls"后调用extractNls()。其完整逻辑(Makefile.dryice.js)可拆解为以下步骤:
- 加载默认消息表:
require("./src/lib/default_english_messages").defaultEnglishMessages,得到当前默认英文消息的键值集合。 - 递归扫描
src/目录:跳过包含_test的测试文件,用正则匹配所有形如nls("key", "defaultString")或nls('key', 'defaultString')的调用:/nls\s*\(\s*("([^"\\]|\\.)+"|'([^'\\]|\\.)+'),\s*("([^"\\]|\\.)+"|'([^'\\]|\\.)+')/g该正则要求
nls的第一个参数(key)和第二个参数(默认英文串)都是字符串字面量,因此只有“硬编码字符串常量”形式的消息才会被提取,动态拼接的字符串无法被识别。 - 合并新 key:若某 key 尚不存在于默认消息表,则以
defaultData[key] = defaultString的形式追加。 - 回写默认消息文件:将更新后的默认消息表重新序列化写入 src/lib/default_english_messages.js,保持英文基准与源码同步。
- 补齐各翻译文件:遍历
translations/下所有.json文件,将默认表中的每个 key 都写入其中(existing[i] = existing[i] || "")——已有翻译保留原值,缺失翻译补空字符串,从而保证所有语言文件始终拥有与默认表一致的完整 key 集合。
这也是为什么步骤 2 只需写{"$id": "..."}一行:剩下的全部 key 会由extractNls()自动生成。执行完后打开新语言文件,你会看到类似 translations/ru.json 的结构——数十个 key 全部就位,翻译值待填。
三、翻译文件的结构与完整 key 清单
以 translations/ru.json 为参照,Ace 当前的全部可翻译消息分为以下几类(对应 key 前缀):
| 分类 | 前缀 | 覆盖的界面区域 |
|---|---|---|
| 自动补全 | autocomplete. | 补全弹窗的 ARIA 标签、加载提示 |
| 编辑器 | editor. | 编辑区滚动容器与槽(gutter)的无障碍描述 |
| 搜索框 | search-box. | 查找/替换输入框占位符、按钮标题、计数器 |
| 提示/命令面板 | prompt. | 最近使用、其他命令、无匹配命令 |
| 文本输入 | text-input. | 光标位置 ARIA 标签 |
| 代码折叠 | gutter.code-folding. | 折叠/展开按钮的标题与 ARIA 标签 |
| 行号槽标注 | gutter.annotation./gutter-tooltip. | 错误/警告/信息/安全/建议标注的无障碍描述 |
| 错误标记 | error-marker. | 错误状态提示 |
| 其他 | inline-fold.、editor.tooltip. | 行内折叠、禁用编辑提示 |
这些消息在源码中的实际消费点包括(均为nls()调用处):
- 自动补全弹窗 ARIA:src/autocomplete/popup.js
- 搜索框全部按钮与占位符:src/ext/searchbox.js
- 编辑器滚动区与槽的无障碍属性:src/editor.js
- 行号槽折叠控件与标注:src/layer/gutter.js
- 光标位置提示:src/keyboard/textinput.js
翻译时需注意:翻译值必须完整保留占位符(如$0、$1、{n}),仅翻译自然语言部分。以默认消息"search-box.search-counter": "$0 of $1"为例,俄语翻译为"$0 из $1"(见 translations/ru.json),$0/$1被原样保留,运行时由nls()填入实际数字。
四、运行时如何消费翻译:nls() 查找与占位符替换
翻译文件生成后,并不会被自动加载,还需要在应用中通过config.setMessages()注入,随后界面代码的nls()调用才会返回对应语言的文本。
4.1 消息注入与查找逻辑
config.setMessages(value, options)(src/lib/app_config.js)用于设置当前使用的消息表,可选options.placeholders指定占位符风格("dollarSigns"或"curlyBrackets")。
config.nls(key, defaultString, params)(src/lib/app_config.js)的查找优先级为:
messages[key]:按 key 精确命中翻译;messages[defaultString]:key 未命中时,尝试用默认英文串本身作为 key 查找(允许“翻译了默认串但 key 不同”的情况);defaultString:以上都未命中时,回退到源码中的默认英文文本。
未命中时还会输出告警,提示在messages.$id对应的语言表中找不到某 key——这正是$id字段在运行时的用途。相关告警实现见 src/lib/app_config.js。
4.2 占位符替换
当传入params时,nls()支持两种占位符风格:
- 美元符风格(默认):
$0、$1… 对应params[0]、params[1]…,$$转义为字面$; - 花括号风格:
{0}、{1}… 对应params[0]、params[1]…。
默认消息表 src/lib/default_english_messages.js 中的字符串(如"text-input.aria-label": "Cursor at row $0")即采用美元符风格。替换逻辑见 src/lib/app_config.js。
4.3 测试用例验证
仓库的 src/config_test.js 给出了完整的nls行为测试,可作为理解与排错参考:
nls("untranslated_key","bar $1")未命中任何翻译时返回默认串"bar $1";- key 未命中但默认串被翻译时,返回翻译结果;
nls("test_key", "this text should not appear")命中test_key时,返回翻译值而非默认串;setMessages({...}, {placeholders: "curlyBrackets"})与{placeholders: "dollarSigns"}下,同一字符串的$n/{n}替换结果不同(测试注释明确“默认使用美元符”)。
五、从零新增一种语言的完整清单
综合以上内容,为 Ace 新增一种语言的完整步骤如下:
- 在 translations/ 目录创建
<language_id>.json,写入{"$id": "<language_id>"}; - 在仓库根目录运行
node Makefile.dryice.js nls,生成带全部 key(值为空串)的翻译骨架; - 打开生成的文件,逐条将英文翻译为目标语言,保留
$0/$1/{n}等占位符; - 在应用初始化时通过
config.setMessages(require(".../<language_id>.json"))注入消息表(若使用打包构建,还需将翻译文件纳入构建产物); - 验证:对照 src/config_test.js 的用例逻辑,确认占位符替换与回退行为符合预期。
六、注意事项与限制
- 仅提取字符串常量:
extractNls()的正则只匹配nls("key", "default")字面量形式,动态 key 不会被自动提取; - key 集合始终对齐:每次执行
node Makefile.dryice.js nls都会把默认表中的新 key 合并进所有语言文件,因此建议在源码新增nls()消息后重新运行该命令,避免翻译文件缺 key; - 未翻译的 key 回退英文:翻译值为空串或缺失时,
nls()依次回退到默认串翻译、默认英文串,界面不会因此报错; - 占位符风格统一:翻译文件中
$n与{n}混用可能导致替换行为不一致,建议跟随默认表统一使用$n风格,或在setMessages时显式指定placeholders。
参考资料(仓库内路径)
- 官方翻译流程文档:translations/Readme.md
- nls 提取构建脚本:Makefile.dryice.js、命令分发入口 Makefile.dryice.js
- 默认英文消息表:src/lib/default_english_messages.js
- 运行时 nls 实现:src/lib/app_config.js
- 现有翻译示例:translations/ru.json
- nls 行为测试:src/config_test.js
【免费下载链接】aceAce (Ajax.org Cloud9 Editor)项目地址: https://gitcode.com/gh_mirrors/ac/ace
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考