如何读懂 Obsidian i18n:Babel AST 字符串提取原理完整解析
【免费下载链接】obsidian-i18n项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i18n
Obsidian i18n是一款专为 Obsidian 打造的插件国际化工具,核心能力是Babel AST 字符串提取:它把社区插件的main.js解析成语法树,像"拆积木"一样精准定位所有界面文案,再配合大模型批量翻译并安全写回,让不懂代码的用户也能一键完成 Obsidian 插件汉化。本文用图解方式带你完整看懂这套"字符串提取"的工作原理。
为什么不用正则,而要用 AST 提取字符串?
最朴素的汉化方案是"全文搜索替换":在main.js里搜"Cancel",替换成"取消"。但这样做很容易翻车:
- 误伤代码里的同名标识符、URL 或日志常量;
- 插件更新后文本位置变化,替换规则全部失效;
- 无法记录"这段文字出现在哪个上下文",同一句
OK在不同弹窗里含义可能不同。
Obsidian i18n 选择了更稳妥的路线:先理解代码结构,再提取字符串。Babel 是 JavaScript 生态最成熟的语法解析器,它能把一整份压缩代码还原成结构清晰的"抽象语法树"(AST,Abstract Syntax Tree)。树的每个节点都带着"这句话是什么类型的语法、变量叫什么、出现在哪个函数调用里"等上下文信息——这正是安全提取界面文案所需的依据。
💡 简单说:正则是在"找词",AST 是在"读懂句子结构后挑词"。
Babel AST 字符串提取的完整流程
整个提取引擎的核心实现在 core-ast-translator.ts,可以拆成四步流水线:
① 解析(Parse):代码 → 语法树
引擎调用 Babel 的parse把插件main.js读成 AST。值得注意的是解析配置里开启了errorRecovery(容错模式)和一整套现代语法插件(TypeScript、JSX、可选链等),保证再"怪异"的压缩产物也能尽量解析成功,而不是直接报错放弃。相关代码见 parseAst。
② 遍历(Traverse):按白名单锁定"UI 上下文"
这是提取策略的灵魂——极度保守的白名单机制。引擎不会把代码里所有字符串都抓出来,只收集以下五类节点的字符串:
| 节点类型 | 代码长相 | 提取条件 |
|---|---|---|
| 变量声明 | const title = "..." | 变量名在"赋值白名单"中 |
| 赋值表达式 | el.textContent = "..." | 属性名在白名单中 |
| 对象属性 | { name: "..." } | 键名在"键名白名单"中 |
| 函数调用 | new Notice("...") | 函数名在"函数白名单"中 |
| 构造表达式 | new Setting(...) | 同上 |
默认白名单本身就是一份"Obsidian UI 词典":title、placeholder、textContent、setName、setDesc、Notice、renderMarkdown等等,覆盖几乎所有面向用户的展示位置,配置集中在 config.ts。遍历逻辑见 traverseWhitelist。
③ 过滤(Filter):双重校验内容有效性
通过白名单的字符串还要过第二道关 isValidText,采用"先拒绝、后放行"的双重校验:
- 拒绝规则(命中即丢弃):URL、文件路径、十六进制颜色、CSS 单位、camelCase 变量名、纯数字、kebab-case ID……共 14 条正则,定义在 AST_DEFAULT_RULES;
- 放行规则(命中其一即保留):包含空格(多半是人类语句)、包含中文等非 ASCII 字符、以标点结尾;纯英文单词则作为兜底直接放行。
这套设计的哲学是:宁可漏提,不可错提——漏掉的词条用户可以在表格里手动补,而错提的词条会在"应用"时破坏代码。
④ 指纹(Fingerprint)与去重
每条提取结果最终被整理成一个结构简单的词条:
{ type: 'CallExpression', name: 'Notice', source: 'Saving...', target: 'Saving...' }对应类型定义 PluginTranslationV1Ast,其中type+name+source三元组构成唯一"指纹",用于去重和后续精准回写,实现见 deduplicateResults。
提取之后:表格化编辑与译文回写
提取出的词条进入可视化 AST 编辑器,按"节点类型 / 变量名 / 原文 / 译文"四列展示,支持行内直写、全文搜索与"仅看未翻译"筛选,完整操作说明见官方文档 ast-editor.mdx。
当你点击"应用",真正的回写发生。InjectorManager 会按"备份 → 替换 → 健康检查"三步安全执行:
- 优先从备份读取原始代码再翻译,保证永远基于母语原文而非已翻译内容做二次替换;
- 调用 translate 做两级匹配:先用完整指纹严格匹配,匹配不到再退化为"按原文宽松匹配",这样即使插件版本微调、变量重命名,旧译文也能继续命中;
- 替换字符串时若译文里含
${变量},会先重新解析成模板字符串节点再写回(见 replaceSource),避免把${name}当成普通文本写坏语法。
写回后系统会自动重启目标插件做健康检查:一旦发现插件加载失败,立刻触发自动回滚,用备份恢复原始文件(injector.ts)。此外还有 validateSecurity 对译文做安全审计,拦截eval()、<script>等危险模式——这套"备份 + 回滚 + 审计"机制就是插件汉化敢直接改写main.js的底气。
如何按你的目标插件微调提取规则?
白名单和过滤正则都开放给用户自定义,入口在插件设置的"AST 配置"面板(i18n-ast.ts),共五个可调项:
- 变量赋值白名单:追加目标插件私有的变量名;
- 函数调用白名单:追加自定义 UI 函数名;
- 对象键名白名单:追加自定义配置项键名;
- 排除正则:命中即丢弃的文本特征;
- 有效特征正则:命中其一才保留的文本特征。
举个例子:若某插件总用showToast("...")弹提示,把showToast加进函数白名单即可让 AST 提取引擎自动捕获这些文案,无需改一行源码。
💡 除了 AST 路线,插件还内置了基于正则的兜底提取器 core-regex-translator.ts,两者互补:AST 管"精准",正则管"覆盖"。提取入口的调度逻辑位于 extract-manager.ts。
总结:Obsidian i18n 的 AST 提取为什么可靠
把整条链路串起来看,Babel AST 字符串提取的原理其实是一条层层设防的流水线:
- Babel 容错解析,把压缩代码还原成语法树;
- UI 上下文白名单,只从变量赋值、函数调用、对象键名里挑"长得像界面文案"的字符串;
- 拒绝/放行双重正则,滤掉 URL、颜色、CSS、变量名等噪音;
- 指纹去重,每条译文都有唯一坐标,可追溯、可回滚;
- 备份 + 健康检查 + 自动还原,让"改写插件源码"这件事变得可逆。
正是这种"保守提取 + 安全回写"的设计,Obsidian i18n 才能把原本属于程序员的黑活,变成任何用户点三次按钮就能完成的插件汉化。
【免费下载链接】obsidian-i18n项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i18n
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考