阅读文本 / Reading text
译文读着很顺,型号却少了一次:用 Counter 检查翻译占位符
产品说明书翻译完,标题、段落和语气都没有问题,但同一个型号在表格里少了一次。人工顺着句子读,往往不容易发现;程序如果只检查“AX-19 是否出现过”,同样会放过它。这类问题适合在交付前增加一道确定性的检查:不仅比较有哪些不可翻译片段,还比较每个片段出现了几次。
先约定哪些东西不能被改写
本文使用 [[SKU:AX-19]] 和 [[AMOUNT:1200.50]] 作为教学用保留标记。它们不是任何产品的内置协议。上游先识别真正需要保护的字段,为其生成标记并保留映射;检查通过后才恢复显示文字。正文里的普通数字、单位和日期不能随手全替换:日期格式可能合理变化,货币也可能有专门的本地化规则。
相同的型号,出现次数也要相同
可点击的教学示例;不上传文档,不调用接口。
全屏
图 1
可切换的判断示意。仅演示处理规则,不代表产品界面或真实效果。
表 1
检查通过与不能证明的事
检查项目
发现什么
没有证明什么
标记多重集
缺失、重复、改写、新增
译文语义正确
标记语法
保留分隔符损坏
所有字段都已正确标记
逐段关联
字段出现在错误段落
术语选用自然
一段能复现错误的标准库代码
保存为 marker_audit.py,运行 python marker_audit.py。仅使用 Python 标准库。正则表达式刻意只接受本例的 ASCII 标记协议;遇到保留分隔符却无法解析时直接报错,而不是悄悄忽略。Counter 对每个不同标记记录次数,减法得到缺少或多出的次数。
import re
from collections import Counter
TOKEN = re.compile(r"\[\[[A-Z][A-Z0-9_]*:[A-Za-z0-9_.-]+\]\]")
def tokens(text):
found = TOKEN.findall(text)
remainder = TOKEN.sub("", text)
if "[[" in remainder or "]]" in remainder:
raise ValueError("malformed reserved marker")
return Counter(found)
def compare(source, target):
before, after = tokens(source), tokens(target)
return dict(before - after), dict(after - before)
source = "[[SKU:AX-19]] / [[AMOUNT:1200.50]] / [[SKU:AX-19]]"
good = "金额 [[AMOUNT:1200.50]];型号 [[SKU:AX-19]],再列 [[SKU:AX-19]]"
assert compare(source, good) == ({}, {})
missing = good.replace(",再列 [[SKU:AX-19]]", "")
assert compare(source, missing)[0] == {"[[SKU:AX-19]]": 1}
changed = good.replace("1200.50", "12000.50")
lost, added = compare(source, changed)
assert lost == {"[[AMOUNT:1200.50]]": 1}
assert added == {"[[AMOUNT:12000.50]]": 1}
extra = good + " [[SKU:AX-19]]"
assert compare(source, extra)[1] == {"[[SKU:AX-19]]": 1}
try:
tokens("[[SKU:AX 19]]")
raise AssertionError("malformed token accepted")
except ValueError:
pass
print("PASS reordered markers")
print("PASS missing, changed, extra and malformed markers")
本机实际执行得到两行 PASS:顺序重排被接受;缺失、改写、重复和格式破损被识别。特别注意第一个测试:允许改变顺序是为了容纳语言表达差异,不代表我们允许改变字段与句子的关系。不要把此测试输出当成翻译质量评分。
为什么全篇计数仍然不够
假设一份报告有两个产品段落,原文各出现一次相同型号;译文把两次都挤到第一段,总计数不会变。解决方法不是把正则写得更长,而是给每个结构单元分配稳定 ID,在段落、单元格或标题级别比较,再汇总文档结果。段落被合法拆分或合并时,需要显式映射关系,而不能按数组下标生硬配对。
还有一种更隐蔽的情况:金额标记被完整保留,但“含税”变成“不含税”。计数检查当然会通过。此类语义关系应进入人工审阅或专门的规则检查。因此,自动门禁最好输出“保留字段一致”,不要输出“译文正确”。
失败时不要自动拿原文覆盖
当检查失败,保存原文单元、译文单元、缺失和新增清单,让编辑决定如何修复。如果系统直接把缺失型号粘到段尾,文本虽然通过了下一次计数检查,含义可能更糟。修复后重新执行检查,保留前后版本和处理人,避免审阅过程变成无法追踪的改写。
对接 OmniDoc 的文档翻译流程时,可以把这个检查放在译文产物返回之后、公开发布之前。原生 UDOC 负责保留可编辑文档;质量规则负责指出哪些字段需要复核。二者解决的问题不同,不能用排版保真替代内容核对。本文不依赖未公开的翻译接口,也不虚构自动通过率。
参考与产品入口
Python:Counter 官方文档
Python:正则表达式官方文档
OmniDoc 产品入口
- 1 -
更新于 2026-10-10