libtool-bin:翻译流程自动化的命令行工具箱 翻译官这行看着风光干久了就知道真正消耗人的不是翻译本身是翻译之外那一堆破事从几十个文件里捞待翻译的文案、跟术语表一个字一个字对、数工作量报价、检查译文里占位符有没有被手滑删掉。这些问题我以前全靠肉眼加人工直到我把日常用的脚本整理成了一个命令行工具集取名 libtool-bin。名字有点碰瓷 GNU libtool 的意思但跟它真没关系这里 lib 是 librarytool 就是工具bin 是二进制合起来就是工具箱。这套工具不是某个商业软件而是我多年本地化工作里沉淀下来的一组脚本和命令专门解决翻译流程里重复、易错、脏活累活的部分。它面向的不是程序员而是翻译官、本地化项目经理、术语管理员甚至一个人干全活的独立译者。你不需要会写代码只需要会开终端、跑命令、读简单的报告就能把以前两小时的体力活压缩成两分钟。1. 一套面向翻译官的命令行工具箱在解决什么问题1.1 翻译工作的老难题重复、易错、难溯源我做本地化项目的时候最怕的不是难句子而是那种看起来没什么技术含量却特别耗时间的环节。举个实际场景一个软件要发新版本开发兄弟丢过来一个目录里面有几十个语言资源文件每个文件几百行我得找出哪些条目是这轮新加的哪些是改过的哪些文案里嵌了变量名和 HTML 标签。过去我怎么干用对比工具一屏一屏看看到眼冒金星遇到占位符问题只能靠译者自觉测试阶段才暴露出来返工成本特别高。这种问题在翻译行业太普遍了。GUI 翻译工具其实很强大记忆库、术语库、机器翻译都集成得好好的但它们有两个硬伤。第一批量处理能力弱你让它把一百个文件里的重复句一次性提取出来它得一个个项目加载第二流程自动化难你想把扫描文件、提取词条、统计字数、校验占位符串成一个流水线GUI 工具根本做不到。翻译项目一旦超过一定规模瓶颈往往不在翻译水平而在流程管理。1.2 Libtool-bin 到底是什么Libtool-bin 是我在实操中攒起来的一套命令行工具包。它的核心哲学是翻译官遇到的大部分体力活都可以拆解为几条命令像搭积木一样组合使用。你给工具一个源目录它帮你扫描出所有待翻译的文本你丢给它一个术语表它能标出哪些句子用词不一致你给它原文和译文它能把占位符、标签、括号这些最容易破坏的东西逐项核对。它的形态是一组可执行脚本底层用的都是常见命令行工具比如 grep、perl、python 的脚本以及 jq、xmllint 这类解析器。好处是透明出问题能拆开看不会像黑盒软件那样只能干瞪眼。坏处也比较明显它没有图形界面初次上手需要一点学习成本。但我的经验是这种学习成本两三天就能回本因为省下来的时间实在太多了。1.3 什么人适合这套工具箱我不是说所有人都应该扔下 CAT 工具来用命令行。适合这套工具箱的人通常符合这几个特征你经常处理多语言资源文件比如 JSON、PO、XML 这类结构化文本你不满足于能翻译还想把控术语一致性、校验格式安全、核算工作量你愿意花半天时间配置一次之后一劳永逸地跑自动化。如果你符合其中两条这套思路就值得往下看。我在实际团队里见过两种角色受益最大一种是独立译者自己接项目自己交付拿到源文件后先跑一遍扫描和统计心里就有数了另一种是本地化项目经理需要把翻译质量检查环节变成可重复执行的标准动作而不是每次靠抽检碰运气。2. 工具箱的整体设计与核心模块拆解2.1 设计原则一切皆文本、幂等、可管道Libtool-bin 的整体设计借用了 Unix 哲学一切皆文件工具与工具之间通过标准输入输出连接。听起来抽象落地到翻译场景其实很直观——中间数据统一用 JSON 格式传递。扫描模块产出一个 JSON 文件里面是所有待翻译条目校验模块吃进这个 JSON也吃进译文的 JSON然后输出一份检查报告。每个模块不关心上下游长什么样只关心数据格式对不对。第二个原则是幂等。同一个命令跑一百次和跑一次结果必须一致。这意味着每次执行它都从原始源文件重新计算不依赖上次运行留下的临时状态。这个设计做起来多花点功夫但用起来非常省心因为你可以随时改改过滤规则、调调参数然后放心重跑不会出现上一次的缓存污染了这次结果的问题。第三个原则是每个模块都支持标准输入。也就是说你前面接了别的工具产出的结果后面也可以接别的工具消费产物。比如我想从一批 Python 文件里提取带_()包裹的字符串可以用 grep 先粗筛一遍然后直接管道给 libtool-bin 的扫描器做结构化处理。这种组合能力是 GUI 给不了的。2.2 五大核心模块Libtool-bin 按功能分成五个模块基本覆盖了翻译流程里最值得自动化的环节。我最初写的时候只有扫描和统计两个命令后来实际用着用着才慢慢加出了术语校验和格式校验因为需求是真实项目逼出来的。模块职责核心命令典型输出扫描模块从源文件中提取待翻译文本libtool-bin scanextracted.json术语模块对照术语表检查用词一致性libtool-bin glossaryterm_report.md校验模块检查占位符、标签、括号等格式完整性libtool-bin checkcheck_report.txt统计模块字数、条目、重复率、工作量计算libtool-bin statstats.csv导出模块把提取结果转成译者友好的格式libtool-bin exporttranslations.xlsx扫描模块是源头所有其他模块的数据都从它来导出模块是出口负责把 JSON 中间格式转成译者熟悉的 Excel 或 Markdown。术语和校验是质检环节统计模块则服务报价和排期。五个模块串起来是一条完整流水线但也能单独使用比如你只是想快速统计一个文件的字数只跑 stats 就行。2.3 配置结构和项目化的思路Libtool-bin 的配置思路也是项目化的。每个翻译项目有自己的配置文件一般叫.libtool-bin.yml放在项目根目录。里面定义要扫描的文件类型、过滤规则、术语表路径、风格指南选项等。我喜欢这个设计的原因很朴素翻译项目是长期维护的第一版翻译完了第二版、第三版还要增量更新配置存在项目里下次跑直接一条命令。一个典型的配置结构长这样project: mock-desktop-app source_dir: source/en build_dir: build glossary: glossary/product_terms.csv scan: include: - *.json - *.md - *.html exclude: - dist/** - **/*.min.js min_length: 1 skip_comments: true stat: dedupe: true check: placeholders: true tags: true brackets: true全局配置和项目配置是叠加关系项目配置里的值覆盖全局默认值。这个优先级设计是踩过坑后加的早期只有全局配置结果不同项目的要求不一样改一次全局就把别的项目带偏了。拆成项目级配置之后每个项目独立维护互不干扰。3. 核心模块的原理解析与关键参数3.1 扫描模块从代码和文档里把人话挑出来扫描模块的核心任务是从一堆文件里精准识别哪些文本需要翻译、哪些不能碰。它的工作机制分三层。第一层按扩展名和格式特征识别文件类型JSON、YAML、PO、Android XML、iOS strings 各有各的格式解析方式完全不同。第二层按文件类型提取候选文本比如 JSON 文件提取所有 value 字段PO 文件提取 msgid。第三层是后处理用行号、上下文和去重逻辑生成结构化的提取结果。这里最考验经验的是过滤规则。我刚开始写扫描器的时候一股脑把所有字符串都提取进来结果翻了车。比如一个前端项目里CSS class 名、组件注册名、版本号、颜色值全被当成了翻译条目译员们对着几百条无效词条一脸茫然。后来我加了一组默认过滤规则把所有看起来不像自然语言的内容剔掉比如纯数字、URL、十六进制颜色、驼峰标识符。libtool-bin scan --source source/en \ --include *.json *.md \ --exclude build/** node_modules/** \ --min-length 2 \ --skip-comments几个关键参数在我实际用下来各有各的坑。--min-length默认我建议设成 2否则单个字母的控件文本会大量混进来--skip-comments非常有用很多开发会把废弃文案注释掉而不是删掉不跳过注释的话提取结果会带着一堆历史垃圾--exclude一定要加上构建产物目录否则前端项目能把几万行打包后的代码扫进来性能直接崩。3.2 术语模块一致性是本地化的生命线术语一致性对于翻译质量来说怎么强调都不过分。一个产品里同一个按钮有的地方叫登录有的地方叫登入用户就会质疑产品专业性一个 API 名称或者专有名词前后译法不一致开发联调时都可能出问题。术语模块的思路很直接你维护一张术语表它帮你检查每一句译文里该用的术语用了没有、不该用的禁词出现没有。术语表格式我用的 CSV兼容性最好Excel 能打开Git 能追踪变更。每行三列原文术语、标准译文、可选注释。检查时工具会先对原文做术语匹配定位找到包含术语的句子之后再去对应译文里检查标准译文是否出现。source_term,target_term,note workspace,工作区,UI 术语 cloud sync,云同步,功能名称 beta,测试版,版本发布用语参数里我要特别说--case-sensitive。很多语言的大小写规则会造成误报比如德语名词都是大写开头你要是开了大小写敏感术语核对会一堆错但你要是关了小写匹配到了品牌名又可能漏掉问题。我的建议是术语表里单独维护大小写变体检查的时候用精确匹配这样既不会误报也不会漏报。3.3 校验模块防止翻译好看但不可用翻译的文字质量重要格式安全更重要。文案里经常会嵌入程序要用的变量占位符和标记语言比如%s、{username}、{{ user.name }}、a href...。这些如果被译者不小心改坏轻则页面显示错乱重则程序直接报错崩溃。校验模块干的就是这个事把原文里的占位符提取成序列到译文里比对该序列是否一致。libtool-bin check --source build/extracted.json \ --target translations/zh_CN.json \ --placeholders \ --tags \ --brackets \ --report-format markdown它的内部机制不复杂但有几个细节值得注意。首先是占位符种类很多不同框架风格迥异所以我把占位符正则做成了可配置的不匹配所有情况只匹配你声明启用的类型。其次是 HTML 标签校验工具会提取...内容形成一个标签栈检查开闭标签是否配对、嵌套是否被打乱。比如原文有bbold/b译文翻译成了b加粗/b 多了个空格标签栈匹配就不通过能精准报出位置。还有一个很容易被忽略的检查项是括号配对。中文翻译里常有全角半角混用的情况原文(optional)译成可选左全角右半角这种肉眼很难看出来但检验报告一跑就现原形。这类问题单看人工审阅特别费神自动化检查反而是性价比最高的投入。3.4 统计模块翻译工作量不用一行行数统计模块是我用得最勤的一个它解决的是行业里最基础的报价和排期问题。接到一个项目客户问多少钱、多久交你不能说看着办得有数据支撑。统计模块按文件、按条目、按字符、按单词输出报告支持去重计算有效工作量。libtool-bin stat --source build/extracted.json \ --target translations/zh_CN.json \ --by-file \ --dedupe \ --format csv然后它会输出类似这样的数据filename,entries,words,unique_entries,unique_words settings.json,320,1845,112,690 welcome.md,45,320,40,310加--dedupe的原因很现实软件项目里重复文案特别多比如同一个确定按钮出现在十几个页面里如果按原始条目计费客户会觉得冤大头按去重后的有效工作量计费双方都服气。统计模块还有另一个进阶功能就是对比两个版本的源文件算出差量这一轮新增了多少词条、改了多少词条。我一般用它在发版节点快速估价不用从头把整个项目清点一遍。4. 实战操作从安装到完成一次完整翻译任务4.1 环境准备与安装Libtool-bin 的安装不复杂前提是你的机器上有 bash、python 3.8 以上以及几个常用的小工具jq 用于处理 JSONxmllint 用于 XML 类文件解析如果要做 Excel 导出还需要 python 的 openpyxl 库。# 拉取依赖macOS 为例Linux 用自家包管理器 brew install jq libxml2 python3 # 安装工具包以 pip 方式为例 pip install libtool-bin # 验证安装 libtool-bin version装完之后第一次跑建议先初始化一个空的项目目录它会自动生成默认配置文件方便你在此基础上改。这里有个经验别急着把真实项目直接挂上来跑先在一个几十个文件的小测试集上摸一遍所有命令的参数习惯了再上真项目不然面对一堆参数容易手忙脚乱。4.2 用一个模拟项目走完流程我拿一个模拟项目 X 演示这个项目是一个跨平台桌面应用源文件在source/en/目录有 JSON 配置、Markdown 文档和一个 Android 风格的 strings 文件。任务是把它本地化成中文。第一步让扫描模块生成待翻译条目libtool-bin scan --source source/en --config .libtool-bin.yml跑完会在build/目录下生成extracted.json。我会马上打开这个文件快速看一眼确认提取的条目类型是否符合预期。这里我要提醒第一次扫描结果基本不用指望完美废条目太多就一定需要调整过滤规则花几分钟把exclude和min_length调好长期受益。第二步用术语模块做预检。如果源文件里已经出现了术语表中定义的词条我可以提前掌握它们在哪些句子中出现方便给译员标注重点。术语模块支持只看原文、不校验译文这样译员还没开工你就能知道哪些术语是高频词。libtool-bin glossary --source build/extracted.json --glossary glossary/product_terms.csv第三步把待翻译条目导出成译者方便的形式。我通常导出双栏 Markdown 或者 Excel一列原文一列译文译员在表格或文档里填好再传回来不用学任何新工具。libtool-bin export --source build/extracted.json --format xlsx --output build/translations.xlsx第四步译员交回译文后把译文转换成工具能识别的 JSON 中间格式再用校验模块做格式和术语双重检查。这里我强烈建议把校验结果生成 HTML 或 Markdown 报告直接丢回给译员自己看上面带着条目编号和错误位置改起来效率很高。libtool-bin import --input translations_filled.xlsx --output build/translated.json libtool-bin check --source build/extracted.json --target build/translated.json libtool-bin glossary --source build/extracted.json --target build/translated.json最后跑一遍统计输出工作量报告和最终字数作为交付数据存档或客户结算依据。整个流程全部走完熟练之后五分钟不到而过去这些环节靠人工来做少说要一整天。4.3 把流程自动化成一个脚本既然每天跑的都这几条命令为什么不干脆写成脚本我喜欢用 Makefile 把工作流固化下来因为 Makefile 有文件依赖关系哪个步骤的输入变了就重跑哪个步骤不用每次全量执行。.PHONY: scan export check stat clean build/extracted.json: source/en/*.json source/en/*.md libtool-bin scan --source source/en build/translations.xlsx: build/extracted.json libtool-bin export --source build/extracted.json --format xlsx check: build/translated.json build/extracted.json libtool-bin check --source build/extracted.json --target build/translated.json libtool-bin glossary --source build/extracted.json --target build/translated.json stat: build/translated.json build/extracted.json libtool-bin stat --source build/extracted.json --target build/translated.json这套脚本对我这种手残党非常友好。我只需要记得两个命令一是make scan更新提取结果二是make check看质检报告。其他细节全部由脚本处理。如果你团队里有 CI 流水线还可以把 check 步骤加进去每次源文件更新或译文提交时自动校验不让有问题的翻译溜到下一环节。这种做法前人验证过就是在让机器做机器擅长的事让人做人擅长的事。5. 常见问题与排查技巧实录5.1 编码与换行符问题Libtool-bin 踩过最多的坑是编码问题尤其 Windows 同事交回的文件。常见两类一类是 UTF-8 带 BOM 的文件另一类是 GBK 编码的中文旧文件。UTF-8 BOM 在解析器眼里会在文件头多一个看不见的字符导致 JSON 解析失败GBK 文件更麻烦直接搜中文关键词搜不到还容易出现乱码。我现在的标准处理流程是拿到外部文件一律先转码命令就是 iconv。来源不明先file看一下实际编码再针对性转。在项目里我还会加一个 pre-commit 的钩子自动把所有入库文件统一成 UTF-8 无 BOM这样从源头就避免了大半问题。# 去掉 BOM sed -i 1s/^\xEF\xBB\xBF// file.json # 把 GBK 转 UTF-8 iconv -f GBK -t UTF-8 old.txt new.txt5.2 误提取和漏提取字符串扫描模块最头疼的不是跑得慢而是它把不该翻译的提取了、该翻译的漏了。误提取重灾区是代码里的单词、CSS 类名、日志消息。日志消息这个问题我一直处理不好它确实是给人看的信息但又不需要翻译因为日志只给开发者看。后来我的对策是维护一个ignore_patterns列表把日志专用的关键词加进去。漏提取的情况更隐蔽常见两种。一种是模板引擎里的嵌套变量比如Hello, {{ user.name }}这种整句拼进去的情况如果没配好规则就完全识别不出来。另一种是 HTML 属性里的可翻译内容比如title和aria-label这些对无障碍访问很重要但常规扫描经常漏掉。我现在的做法是扫描配置里明确列出要提取的 HTML 属性列表宁可多一点后面用校验去过滤也不能漏。5.3 术语误报与语言特例术语校验误报最多的是语言形态变化。我把中文内部术语表配好之后英文原文的复数、时态变化都容易让精确匹配失效结果术语模块频繁报警译员被无效 bug 搞得不胜其烦。后来我引入了术语变体匹配每一条术语可配置允许的变体形式比如英文动词的过去式、名词复数这样匹配时就自动把变体折叠回原型。还有一个语言特例是中文的的得地和某些通用动词。你不可能把所有不可能翻译的词都放进禁用词表所以我在最终方案里加了一个白名单机制。术语检查报告分两级error 级确定性违反和 warning 级需要人工判断。warning 可以在配置文件里静默掉只有 error 会阻断流水线。分级的价值在于机器把 99% 的确定问题解决了人只需要花精力看剩下的 1%。5.4 大量文件时的性能优化翻译项目越做越大几千个文件也不是不可能。早期我的扫描器是单线程遍历跑一个大项目要十几分钟完全不可接受。后来做了两处优化效果立竿见影。第一是缓存文件指纹。扫描器会先对每个文件算哈希如果哈希和上次一样就直接跳过这样就实现了增量扫描只有变化的文件才重新解析。软件发版核心是代码增量源文件大部分没变这一招直接让平均扫描时间从十分钟降到几十秒。第二是并行解析。不同格式的解析相互独立用标准库里的多进程池舒服地榨干 CPU 核心文件数量大时提升明显。libtool-bin scan --source source --incremental --parallel 4性能问题还有一个思路是换边界。有些大项目根本不需要每次都全量扫描完全可以只扫改动的子目录。我把扫描器的输入从单一路径改成支持多路径比如本次发版只涉及modules/auth和modules/payment就只扫这两个目录效率翻倍。最后说点个人体会。Libtool-bin 这套工具从我最早只有两三个脚本到现在形成了一套完整流程中间经历了无数真实项目的打磨。最大的感悟是工具不需要一步到位只要你把重复劳动看成一个待解决的问题动手去减少它就已经赢过大多数人了。我见过太多人宁愿手工复制粘贴也不想花时间学一个新命令结果每周都被琐事绑架。这套工具的思路你完全可以直接复制哪怕一行代码不写先把哪些环节能自动化列出来再逐个击破你的翻译工作就能轻松一大截。如果真要再往前推一步我建议你把这些脚本固化进团队协作流程里让译员、审校、项目经理都跑同一套检查那时你会明白什么叫工具改变流程流程改变质量。