news 2026/9/21 16:31:54

AltTab 多语言本地化补全实战:基于 translate-missing-l10n 技能的 20 语言缺失翻译工作流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AltTab 多语言本地化补全实战:基于 translate-missing-l10n 技能的 20 语言缺失翻译工作流
  • 桌面应用

【免费下载链接】alt-tab-macos

Windows alt-tab on macOS

项目地址:https://gitcode.com/gh_mirrors/al/alt-tab-macos
点击查看免费下载

本篇技术指南围绕 AltTab(macOS 平台的开源窗口切换器,体验对标 Windows 的 Alt-Tab)仓库中的.claude/skills/translate-missing-l10n/SKILL.md技能文档展开,讲解如何利用 Claude 的多语言能力,从 Swift 源码重新生成本地化字符串、对比 20 个目标语言文件找出缺失键、按规范翻译并借助scripts/l10n/apply_translations.ts原子化合并回写。读完你将掌握一套可复制的"提取—对比—翻译—校验—合并"完整流水线,以及格式说明符校验、en.lproj 对称回写等底层实现细节。

背景:AltTab 的本地化体系

AltTab 是一个帮助用户在 macOS 上像 Windows Alt-Tab 一样切换窗口的应用,其待翻译字符串绝大部分来自设置界面(Settings UI),包括部分 tooltip、对话框和通用用户提示。仓库采用 Apple 标准的Localizable.strings机制,目录结构位于 resources/l10n,每个语言一个.lproj子目录:

  • resources/l10n/Localizable.strings:由genstrings从 Swift 源码重新生成的源文件(英语,965 行),格式为/* 工程师注释 */ "key" = "value";
  • resources/l10n/<lang>.lproj/Localizable.strings:各目标语言的翻译文件,格式为"key" = "translation";

从 src/Menubar.swift 可以看出源码中的字符串是如何进入本地化体系的——所有用户可见文案都通过NSLocalizedString(_:comment:)包裹,例如NSLocalizedString("About %@", comment: "Menubar option. %@ is AltTab")NSLocalizedString("Quit %@", comment: "%@ is AltTab"),以及带数字参数的String(format: NSLocalizedString("Trial: %d days remaining", comment: ""), daysRemaining)comment参数会被genstrings原样写入生成文件的/* */块中,作为翻译时消歧义的工程师指引。

目标语言矩阵(20 种)

技能文档定义了 20 个目标语言代码:

de, ja, fr, es, zh-CN, pt-BR, nl, ko, it, pl, ar, zh-HK, vi, tr, sv, th, zh-TW, he, id, ru

其中en是源语言,不需要人工翻译——它在应用阶段由脚本自动处理(详见下文"en.lproj 自动同步")。仓库中实际存在的语言目录与之一一对应:ar.lprojde.lprojes.lprojfr.lprojhe.lprojid.lprojit.lprojja.lprojko.lprojnl.lprojpl.lprojpt-BR.lprojru.lprojsv.lprojth.lprojtr.lprojvi.lprojzh-CN.lprojzh-HK.lprojzh-TW.lproj

以 resources/l10n/zh-CN.lproj/Localizable.strings 为例,其真实内容形如:

"%@ now has a Pro tier" = "%@ 现已推出 Pro 版本"; "%@ — last seen %@" = "%1$@ — 上次出现于 %2$@"; "3-finger Horizontal Swipe" = "三指水平滑动"; "About %@" = "关于 %@"; "All Spaces" = "所有桌面";

翻译硬性准则

SKILL.md 给出了六条必须遵守的翻译规则,任何偏离都会导致译文被工具拒绝或破坏 UI 排版:

  1. 格式说明符必须原样保留%@%d%1$@%2$@\n\t的数量和顺序必须与源文一致。带位置索引与不带索引的形式可以互换(%@ %@%1$@ %2$@),但数量必须匹配。例如源文"%@ — last seen %@"在 zh-CN 中翻译为"%1$@ — 上次出现于 %2$@"是合法的——说明符数量一致,只是改用了位置索引形式。
  2. 专有名词不翻译AltTabmacOSMission ControlSpacesDock等保持原文。仓库的 zh-CN 文件也印证了这一点,如"AltTab is a free, open-source window switcher..."中 AltTab 保持原样。
  3. 修饰键名称不翻译CmdOptionAltShiftCtrlControlFnCommand保持原文。
  4. 优先采用 Apple 官方平台术语:若目标语言在 macOS 系统设置中存在官方术语,应优先采用。例如法语中 macOS 用的是 "Réglages" 而非字面翻译的 "Préférences"。
  5. 匹配源文的简洁度:设置项字符串通常很短,译文也应保持简洁,优先使用符合语言习惯的短表达,而非逐字逐句的完整语法。
  6. 匹配 macOS 语气:中性、直接,除非源文本身有感叹号,否则译文不要加感叹号。
  7. 源文件注释是工程师指引而非用户可见文本/* */中的 comment 用于消歧义,绝不进入译文。

完整工作流:七个步骤补全 20 语言缺失翻译

步骤 1:刷新源文件

bash scripts/l10n/extract_l10n_strings.sh

该脚本(scripts/l10n/extract_l10n_strings.sh)用genstrings从当前 Swift 代码重新生成resources/l10n/Localizable.strings。其内部实现值得关注:

  • find src -name '*.swift' | xargs genstrings -a -o resources/l10n:收集 src 下全部 Swift 文件并追加生成;-a表示追加模式。
  • iconv -f UTF-16LE -t UTF-8将 genstrings 输出的 UTF-16LE 转成 UTF-8。
  • sed $'1s/\xef\xbb\xbf//'去掉可能存在的 BOM,保证输出确定性(字节级可复现)。

步骤 2:解析源文件

读取resources/l10n/Localizable.strings,每条记录形如:

/* engineer comment */ "key" = "value";

需要构建有序的(comment, key, value)三元组列表。注意:源文件中value通常与key相同,但当存在多个说明符时 value 可能包含位置索引(%1$@%2$@)。在 apply_translations.ts 中,解析由正则/\/\*\s*([\s\S]+?)\s*\*\/\s*"([\s\S]+?)"\s*=\s*"([\s\S]+?)"\s*;/g完成,同时捕获注释、键与值,并保证按源文件顺序输出。

步骤 3:逐语言计算缺失键

对 20 个目标语言,读取resources/l10n/<lang>.lproj/Localizable.strings一个键被视为缺失,当且仅当

  • (a) 它存在于源文件中,但在目标文件中不存在;或
  • (b) 目标文件中的值为空或仅含空白字符

情况 (b) 与 (a) 同等处理——必须产出真实译文。这一判定逻辑在脚本中表现为:parseTarget只读取非空文件中匹配到的"key" = "value";条目,空值条目自然不会被合并,等同于缺失。

步骤 4:无缺失则停止

如果所有语言都没有缺失键,报告结果并退出,不产生任何写操作。

步骤 5:翻译(分批进行)

对每个语言、每个缺失键产出译文,严格遵守上文六条准则。不要发明键——只翻译源文件中真实存在的键。为提高单次输出的可管理性,建议每 5~10 个语言分一批进行。

步骤 6:应用批次

将每批结果写到/tmp下的新文件(不入库),JSON 形状为:

{ "fr": { "About %@": "À propos de %@", "Quit": "Quitter" }, "ja": { "About %@": "%@について" } }

然后运行:

npx ts-node scripts/l10n/apply_translations.ts /tmp/batch-NN.json

apply_translations.ts(scripts/l10n/apply_translations.ts)会执行以下关键行为:

  • 校验格式说明符:译文与源 value 的说明符集合不匹配时,输出清晰错误并拒绝合并。校验算法normalizedSpecs先提取%(?:\d+\$)?[@d](即%@%d%1$@等,并把%1$@归一化为%@),再提取\n\t,排序后逐项比对。
  • 总是从源键重写en.lproj/Localizable.strings:每条写为"key" = "key";保持对称,无需在批次中包含en。这样能避免 genstrings 改写出的%1$@形式值泄漏进英文文件(当源键本身用的是普通%@时)。
  • 按源顺序重写每个<lang>.lproj/Localizable.strings:已有翻译保留,新翻译合并进去,已不在源中的键被剪除(pruned)。
  • 存在被拒绝条目时以退出码2结束

步骤 7:处理拒绝

apply_translations.ts报告格式说明符不匹配,修正对应译文后,在后续批次中只重跑受影响的语言。在有拒绝未解决之前,不要继续推进。

底层实现剖析:apply_translations.ts 的核心逻辑

理解脚本内部行为,有助于批量翻译时一次通过。其关键实现要点如下:

格式说明符归一化比对(normalizedSpecs/specsEqual):位置索引形式%1$@会被归一化为%@,因此"%@""%1$@"等价,但数量必须完全一致;\n\t被单独作为 token 参与比对,说明译文里换行/制表符的数量和位置也必须与源一致

en.lproj 自动同步(main 中的 en 分支):脚本无条件从源键重写resources/l10n/en.lproj/Localizable.strings,值为键本身(key == value)。这保证了英文文件永远与当前源码的键集合同步,且不会继承 genstrings 对 value 的位置索引改写。即使批次里出现"en"键,也会被跳过并提示自动同步。

按源顺序合并回写(writeTarget):目标文件不是简单追加,而是以源文件的键顺序为基准逐条写出——已在目标文件中的旧翻译从 Map 中取出保留,新翻译写入,源中已删除的键自动消失。这使每个.lproj文件保持与源一致的稳定顺序,利于 diff 审查。

批次键合法性检查:批次中出现源中不存在的键会被计入rejected并输出key not in source错误,杜绝凭空发明键。

退出码约定:有任何拒绝时进程以2退出,便于 CI 或脚本化流程捕获失败;正常情况为0

结果报告与收尾

一次完整运行结束后,需要向用户报告:

  • 处理的语言数量;
  • 产出并合并的译文总数;
  • 有意保留不翻译的条目(例如源文本身就是专有名词的情况),列出清单交由用户决策;
  • 需要人工修复的格式说明符拒绝,说明修了什么、为什么。

这四类信息中,尤其重要的是"故意未译清单"与"拒绝修复记录"——它们是人工复核与后续回归的基础。

最佳实践小结

  • 先刷新、再对比:每次翻译前务必重新执行extract_l10n_strings.sh,否则新增/删除的键会使缺失判定失真。
  • 分批控制规模:每批 5~10 个语言,避免单次输出过大导致质量下降。
  • 重视说明符%@%d\n\t的复现是整个流程最容易出错、也最容易自动化拦截的环节,翻译完成后可先自查再提交批次。
  • 善用 en 自动同步:批次 JSON 永远不需要包含en,也不要手动修改en.lproj——脚本会以源键为准保持其对称与最新。
  • 不通过则不复用:只要存在 rejected,就停下修复并只对受影响语言重跑,保证最终落地文件 100% 通过校验。

这套工作流将"人工翻译判断"与"机器校验合并"明确分工:Claude 负责语言与术语判断,apply_translations.ts负责格式安全与文件一致性,两者结合,使得 AltTab 的 20 语言本地化可以在不破坏格式、不引入无效键的前提下持续跟进源码演进。

  • 桌面应用

【免费下载链接】alt-tab-macos

Windows alt-tab on macOS

项目地址:https://gitcode.com/gh_mirrors/al/alt-tab-macos
点击查看免费下载
上一篇:终端Markdown查看器mdv最佳实践:团队协作中的Markdown文档管理终极指南
下一篇:Liftoff项目安装与配置指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 16:29:09

Hermes Agent 跑多代理 Crew:Key 用 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/21 16:25:06

Nix SSH Substituter 指南:通过 SSH 远程 Nix Store 自动拉取二进制包

Nix SSH Substituter 指南&#xff1a;通过 SSH 远程 Nix Store 自动拉取二进制包 【免费下载链接】nix Nix, the purely functional package manager 项目地址: https://gitcode.com/gh_mirrors/ni/nix 本指南讲解 Nix 包管理器的 SSH Substituter 机制&#xff1a;如何…

作者头像 李华