阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
把
user_id
翻译成“用户标识符”,或者将
<div class="container">
里的 class 属性本地化,是技术文档翻译中最昂贵且难以排查的错误。这类问题通常不会导致程序崩溃,但会让复制粘贴的代码直接报错,或者让 API 文档的示例完全失效。解决这个问题的核心不在于翻译引擎有多智能,而在于预处理阶段能否准确地将“自然语言”与“机器语言”在 DOM 树中物理隔离。
为什么正则表达式无法胜任代码保护
很多团队尝试用正则表达式在翻译前替换代码片段,但这在 HTML 结构中极其脆弱。HTML 不是线性文本,而是嵌套树状结构。一个
<code>
标签内部可能包含
<span>
高亮,或者被
<a>
标签包裹形成链接。正则表达式无法理解这种嵌套语义,极易造成标签闭合错误或遗漏边界情况。
使用 Beautiful Soup 这类解析器,可以将代码保护从“字符串匹配”提升为“节点遍历”。根据 Beautiful Soup 4.15.0 官方文档,我们不再寻找特定的字符模式,而是直接操作 DOM 树中的 Tag 对象。通过识别
pre
、
code
、
kbd
、
samp
等语义化标签,以及带有特定 class(如
highlight
、
language-python
)的元素,我们可以精确地锁定需要屏蔽的区域,无论其内部结构多么复杂。
合成示例:正确输出与边界陷阱
为了验证保护逻辑,我们需要构造一套明确的合成测试用例。请注意,以下输入仅为演示解析逻辑而设计,并非真实生产数据,也不涉及任何外部文件读取。
合成输入 HTML:
<p>请运行 <code class="cmd">pip install -r requirements.txt</code> 来安装依赖。</p>
<pre><code># 初始化配置
config = {"timeout": 30}</code></pre>
<p>注意:<var>timeout</var> 参数单位为秒。</p>
预期正确提取结果:
翻译系统应仅接收以下纯文本段落进行翻译,代码部分被占位符或完全剥离:
1. "请运行 [CODE_0] 来安装依赖。"
2. "注意:[VAR_0] 参数单位为秒。"
<pre>
块内的内容不应出现在待翻译文本流中,或在导出时保持原始字节不变。
典型错误/边界输入及处理:
*
嵌套标签:
<code><b>bold_code</b></code>
。若只提取
code.string
会得到 None,因为内容在子节点
b
中。必须使用
get_text()
或递归遍历 descendants。
*
属性值泄露:
<a href="/api/v1/users">用户接口</a>
。翻译目标仅是“用户接口”,
href
属性值必须被锁定。若将整个标签转为字符串送入翻译,URL 可能被破坏。
*
伪代码标签:
<div class="code-snippet">
。这不是标准语义标签,需通过 CSS 类名白名单额外捕获,否则会被当作普通段落翻译。
基于DOM树的代码节点识别实现
以下 Python 示例展示了如何利用 Beautiful Soup 遍历文档树,区分可翻译文本与受保护代码。此脚本为纯内存操作的教学演示,未包含任何网络请求、Shell 命令或文件写入行为,建议在
beautifulsoup4>=4.15.0
环境中运行。
from bs4 import BeautifulSoup, NavigableString, Tag
# 合成示例:包含内联代码、代码块及普通文本(仅用于演示,非真实数据)
HTML_SAMPLE = """
<article>
<p>使用 <code class="cli">kubectl get pods</code> 查看状态。</p>
<pre><code>def hello():
print("Hello World")</code></pre>
<p>返回值 <var>result</var> 可能为空。</p>
</article>
"""
# 定义需要整体保护的标签集合
PROTECTED_TAGS = {'pre', 'code', 'kbd', 'samp', 'var'}
def extract_translatable_segments(html_content: str) -> list[dict]:
"""
提取HTML中的文本片段并标记是否可翻译。
注意:此为教学演示代码,生产环境需增加占位符生成与属性保护逻辑。
"""
soup = BeautifulSoup(html_content, 'html.parser')
segments = []
# 遍历所有文本节点,而非仅顶层标签
for element in soup.descendants:
if isinstance(element, NavigableString):
# 检查父链上是否存在受保护标签
parent_chain = list(element.parents)
is_protected = any(
p.name in PROTECTED_TAGS
for p in parent_chain
if isinstance(p, Tag)
)
text = str(element).strip()
if not text:
continue
segments.append({
'text': text,
'translatable': not is_protected,
'context': element.parent.name if element.parent else 'root'
})
return segments
# 执行提取并断言预期行为
results = extract_translatable_segments(HTML_SAMPLE)
translatable_texts = [s['text'] for s in results if s['translatable']]
protected_texts = [s['text'] for s in results if not s['translatable']]
# 验证:普通文本应被标记为可翻译
assert any('查看状态' in t for t in translatable_texts), "普通文本未被识别"
# 验证:代码内容不应出现在可翻译列表中
assert not any('kubectl' in t for t in translatable_texts), "内联代码泄露至翻译区"
assert not any('print' in t for t in translatable_texts), "代码块内容泄露至翻译区"
# 验证:受保护内容被正确归类
assert any('kubectl' in t for t in protected_texts), "内联代码未被保护"
print(f"可翻译片段数: {len(translatable_texts)}")
print(f"受保护片段数: {len(protected_texts)}")
这段代码的核心在于
element.parents
链式检查。它确保了即使
<code>
嵌套在
<p>
中,其内部的文本节点也会被正确标记为不可翻译。注意,这只是一个提取与校验的外围演示,并非完整的翻译替换系统;实际生产中还需处理占位符回填与属性保护。
验收标准与人工审查边界
代码保护不能仅靠“运行无报错”来判断。以下表格列出了在实际交付中应执行的验收动作,以及自动化脚本无法覆盖、必须转入人工审查的场景。
检查项
自动化校验方法
人工审查触发条件
处理决定
标签完整性
对比翻译前后 DOM 树结构哈希
译文出现未闭合标签或嵌套错位
拒绝交付,回退至原文重新处理
属性值保留
正则校验关键属性(href/src/id)是否变更
动态 URL 含路径参数或查询字符串
标记为高风险,由开发者确认
占位符还原
检查译文中占位符数量与原文一致
占位符位置不符合目标语言语法
调整语序,必要时拆分句子
伪代码识别
检查 class 白名单命中率
自定义组件或非标准代码容器
补充规则或手动标注
注释翻译
检测代码块内注释是否被跳过
注释包含重要业务逻辑说明
单独提取注释进行翻译
不适用范围声明:
上述自动化校验仅适用于结构良好的语义化 HTML。对于由 Markdown 渲染生成、缺乏语义标签的纯
<div>
+
<span>
代码块,或经过混淆压缩的单行 HTML,解析器可能无法正确识别代码边界。此类文档必须先经过格式标准化清洗,或直接交由人工处理。此外,本校验逻辑仅针对“代码不被翻译”,不保证翻译后的自然语言质量。
参考资料与下一步
Beautiful Soup Official Documentation
将这份检查清单用于文档翻译
网页文档的正文、链接、代码与结构要分别处理。把受保护的部分列入验收清单,再评估翻译后的可读性与页面展示。
OmniDoc(产品入口)
提供多格式文档翻译入口,官网介绍了 OCR、术语表与双语对照功能。对希望直接从文件开始处理的团队,这是一条值得用实际样本评估的路径。请使用有权上传的脱敏文件,并用本篇的检查项复核结果;这里不声称 OmniDoc 使用了本文的开源库或内部算法,也不以示例代替产品性能测试。
- 1 -
更新于 2026-10-08