一、翻得动一万个词条,靠的是管道不是一次调用

单个文本框里”输入中文输出英文”看起来是全部工作量;一旦对象变成上千条界面文案、几份产品手册、一批工单回复模板,真正的故障点会换一批面孔出现:段落被拆开又装不回去,占位符 %s 被译成了”百分之 s”,同一个部件在不同文件里有三种译法,两条并发写回把 A 的译文放进 B 的位置,跑完三万条之后没人说得清哪几条是机器猜的。这些都不是”模型翻得好不好”的问题,是工程问题。

所以把它当一条批处理管道看,四段:切分(把带结构的源文本拆成可独立翻译的最小单元,并把不可翻译的部分摘出来)、映射(确定源语言、目标语言与生效的约束)、请求(批量调度、限流、重试、缓存)、回填(按稳定标识装回原结构)。每段都有自己的失效模式,下面逐段拆。术语一致性与质量校验分别落在映射与回填之后,是这条管道里唯一需要长期维护资产的两处。

批量翻译管道的术语库与重试队列

二、切分与回填:结构标记不能整块丢进去

界面文案与文档不是散文。一条源文本里可能同时混着六类东西,处理方式各不相同,混在一起整块送进去就一定会丢:

  1. 可翻译的正文——按句子或段落切,不按字符数切,切点要对齐标点而不是硬截长度。
  2. 占位符与格式符——%s、{count}、{{name}}、ICU 消息语法,必须在切分时摘出并替换为抗变换的记号,回填后逐条比对数量。
  3. 标记与标签——Markdown 的 **、`,HTML 的标签名与属性;属性值里的 alt、title 反而是可翻译内容,这种嵌套要显式建模。
  4. 不该动的字面量——键名、代码片段、命令行、URL、邮箱、型号编号、接口字段名。
  5. 混合语种——一句里既有中文说明又有英文日志原文;按整条检测语言会猜错。
  6. 数字与单位——12个月、5kg,数字本身不译,单位的本地化形式要按目标语言规则处理。

回填环节最严重的错误是按下标写回。并发请求完成顺序与提交顺序不一致,下标就失去了意义,而且这种错位不会报错,只会让内容悄悄串行——一条错误译文可能出现在任何一条位置上,人工通读都很难发现。正确做法是每个片段带一个稳定标识(源文件路径加键名,或内容哈希),请求与响应都以这个标识为唯一契约,组装时按标识取值、按原始顺序排列,并在结尾断言”返回的标识集合与提交的标识集合完全相等,不多不少”。

# restore_slots / slot_count 是项目自己的登记函数:
# 切分时把占位符摘出并登记位置,回填时按登记原位装回并核对数量
def assemble(segments: dict[str, str], source_ids: list[str]) -> list[str]:
missing = [i for i in source_ids if i not in segments]
extra = set(segments) - set(source_ids)
if missing or extra:
raise ValueError(f"缺 {len(missing)} 段,多 {len(extra)} 段")
out = []
for sid in source_ids:
text = restore_slots(segments[sid], sid) # 按登记的原位装回占位符
assert slot_count(text) == slot_count(sid), f"占位符数量不一致: {sid}"
out.append(text)
return out

三、请求层:批大小、并发、限流与幂等

这一层与普通批量任务没有区别,但翻译有两个特殊之处:一是响应内容不确定(同一输入两次调用可能给出不同译文),二是失败代价不对称(重跑一整批的配额消耗远大于重跑一条)。

参数 调大的收益 调大的代价 定法
批内片段数 请求次数减少,固定开销摊薄 一段失败整批重来;跨段上下文互相干扰;返回条数与提交条数不一致时难以定位是哪段 按”可承受的重复成本”定,不按吞吐上限定
并发数 墙钟时间缩短 触发配额限流,被限流后重试风暴放大延迟 以令牌桶或信号量封顶,并把限流响应单独计数
单次重试次数 抗抖动 非幂等场景下产生重复计费与重复写入 只对可重试错误退避,重试必须带同一请求标识
缓存有效期 相同片段免重翻 术语表更新后仍返回旧译文 缓存键必须包含术语表与约束版本

限流与重试的组合要写清三件事。收到配额类响应(如 429)时优先按响应头里的等待提示,退避要带抖动,避免所有工作线程在同一时刻齐步重试;收到明确的内容拒绝类错误时不重试,直接入人工队列,否则一条无法翻译的片段能把管道卡死;重试要与幂等绑定——给每个片段一个请求标识,重试时带同一个标识,把”这条已经处理过”变成服务端或本地状态可判定的事实,否则超时后重发会产生重复记录与重复计费。

去重缓存是这条管道里性价比最高的一步:项目里同一句”确认删除?”往往出现上百次,按内容哈希复用译文既省钱又提升一致性。缓存键要覆盖全部影响输出的因素——源文本、源语言、目标语言、生效的术语表版本、约束与提示模板版本、处理通道标识。少写一项,就会在升级术语表后拿到一批旧译文,而且没人知道它旧。

接口通道选型按机制判断,不按”翻得漂不漂亮”判断:需要术语被硬性遵守,就选支持传入受控词表或在请求里携带术语约束的通道;数据不能出域,就只剩本地部署一条路;追求批量吞吐与低成本,公开批量任务接口比逐条同步调用合适;同一项目里不同内容可以走不同通道,但必须在记录里留下用了哪条通道与哪个版本。

四、术语一致性:库的形式、命中优先级与强制替换的风险

术语一致性靠一次翻译不可能得到,它是一项长期资产。最小可用的术语条目至少六个字段:源语言写法、目标语言规范译法、禁用译法(这一项常被漏掉,但它是发现问题的主要手段)、上下文限定(领域、词性、搭配动词、单数还是集合概念)、生效范围(全局、某产品线、某项目)、版本与生效时间。公开的交换格式里 TMX 用于翻译记忆、TBX 用于术语库,按这两种格式存可以避免资产锁在自家工具里。

命中优先级建议明确写成一条顺序:禁用译法否决最先判定(它不参与竞争,只要出现就是问题);其次全词精确匹配,区分大小写与词边界;再次词形归一后匹配(英文还原单数与动词词尾,中文做繁简与全半角归一);然后长短语优先于单词(否则”数据源”会被”数据”的译法抢先命中);同长度冲突时按生效范围的具体度取胜(项目级压过全局级),仍冲突就是术语库本身的问题,必须走人工裁决并记录结论,不能靠随机。

术语冲突要当缺陷管理,不当配置处理。两个团队给同一个部件起了不同译法,翻译层里”随机选一个”的结果是文档里两种写法并存,用户以为是一个新概念旧概念两件事。冲突要么在库里消除,要么在上下文限定里切开,都留下改动记录与版本。

至于”翻完再做正则强制替换”,风险要讲明白:词形变化让替换后的句子语法断裂(冠词与量词跟旧词形一致,改成新词形后不匹配);复合词与标识符里的子串会被误替换;同一术语在主语位置与修饰位置需要不同译法;替换本身不产生”哪里被改过”的证据,事后无法追责。合理用法是两条:把术语作为请求侧的约束送进去(这是主要手段),把禁用译法作为回填后的否决扫描(发现即标记,交人工重译),而不是让替换脚本静默改写完所有输出。

五、校验分层:每层能查出什么,查不出什么

分层的原则是便宜且高召回的检查先跑,昂贵且主观的检查只跑抽样。

校验项 判定方式 失败处理
结构完整性 占位符、标签、转义符、换行数量逐条比对;数字做数值等价而非字符串相等(千分位与小数点会被本地化) 直接打回重译,不进人工队列
长度与信息密度比率 按语向统计历史基线,偏离基线带过大即标记;异常短多半漏译,异常长多半夹带了机器的解释语 标记后重译一次,仍异常入人工
空译与自译 译文与源文完全相同(非借词表内)判为未译 重译,连续失败入人工
术语命中 规范译法出现率、禁用译法出现率;同一条源文在项目内多次出现时译文必须一致 禁用译法命中一律入人工
同输入一致性 全项目按源文本分组,组内译文必须唯一 保留先出现的,其余重译
回译比对 把译文翻回源语言,与原文做语义比对(分词后相似度而非逐字) 仅抽样跑;差异大的入人工
缺字与编码 目标字符是否落在字体覆盖内,是否出现替换符 换字体或改写,不放行
抽检打分 按准确性、术语、流畅度、格式、可本地化性五个维度逐条记分,打分人与阈值由项目定 低于阈值整批回退,不只改被抽到的条

回译要单独说清边界。它擅长发现漏译、增译与语义漂移,因为它强迫信息走一个来回;它不擅长发现”错得恰好对称”的译文——术语选错了,回译也会用同一个错词翻回来,比对结果完全正常。所以回译永远不能替代术语命中检查,两者查的是不同问题。回译的成本是双倍请求与双倍延迟,因此只对抽样与高风险内容(合同、条款、对外文档)跑。

本地化还有几个专坑与校验无关但会毁掉交付:复数规则不能把数量写进文案,要交给按类别取模板的机制,某些语言的复数还与语法性绑定,需要额外传入被修饰对象的属性;日期与数字格式属于格式化层,不该出现在被翻译的字符串里;从右向左书写的语言要同时处理段落方向、标点镜像、双向文本控制符混排,以及界面里方向性图标(返回箭头、播放键)是否需要镜像;界面文案变长会撑破布局,用伪本地化(把源文案替换成等长偏长的测试文本)在早期暴露截断与溢出,比等到真语言到位再改便宜;字体缺字在文档里表现为豆腐块,在导出环节表现为丢字。

六、洹拓视角:可追溯与抽检记录比译文漂亮更重要

给客户交付文档翻译时,我们更在意能不能回答这三个问题:这一句为什么是这个译法(命中了哪条术语、哪个版本)、这一批是谁检的(抽检样本号、打分人、结论)、这一条改过几次(重译原因与通道记录)。这三个问题有答案,交付才能复盘;只有漂亮译文而没有记录,下一次改术语表时没人敢动,因为不知道会牵动哪些已经验收过的段落。

落地的最小资产是三份东西:一份带版本与生效范围的术语库(含禁用译法,按公开交换格式存),一份管道不变量清单,一份抽检记录表。不变量清单建议至少锁住这几条,每条都能写成断言:回填按稳定标识而非下标;返回标识集合与提交标识集合完全相等;每条的占位符与标签数量一致;同一条源文本在项目内只有一个译文;缓存键包含术语库与通道版本;禁用译法命中率为零或已入人工队列;每一批都记录术语库版本号;重试带同一请求标识。这些断言跑在流水线里,比任何事后通读都稳定,因为它们不会累。