阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
页面上显示出一串
&
,第一反应常是再解码一次。但问题也可能恰好相反:同一段内容已经转义过,又被模板转义了一遍。先弄清当前拿到的是原始 HTML、DOM 文本还是准备插入页面的普通字符串,再决定该不该转换。
转义是输出边界的事
html.escape
把普通文本中有 HTML 含义的字符转成实体;
html.unescape
则解析实体。它们不是可以随意交替调用的“清洗步骤”。翻译器需要的通常是语义文本,模板需要的则是符合当前位置规则的序列化结果。
比如产品名
R&D
作为文本显示时没有问题,写入 HTML 源码时通常表示为
R&D
。再转义一次会变成
R&D
,浏览器便把中间的实体字面量显示出来。相反,把不可信内容解码后直接当 HTML 插入,可能重新激活其中的标签。
用三种状态做一个小实验
import html
plain = 'R&D <Guide> "2026"'
encoded = html.escape(plain, quote=True)
double_encoded = html.escape(encoded, quote=True)
assert encoded == 'R&D <Guide> "2026"'
assert html.unescape(encoded) == plain
assert html.unescape(double_encoded) == encoded
assert html.unescape(double_encoded) != plain
untrusted = '<img src=x onerror=alert(1)>'
decoded = html.unescape(untrusted)
safe_as_text = html.escape(decoded, quote=True)
assert decoded.startswith('<img')
assert safe_as_text.startswith('<img')
这是标准库的合成转换样例,不会执行 HTML 或脚本。最后两行说明的是“作为文本输出”的处理,不是安全 HTML 清洗方案,也不能推导出把任意结果放进 JavaScript、CSS 或 URL 都安全。不同上下文需要不同规则。
在管线里给数据状态起名字
可以用
source_html
、
plain_text
、
translated_text
和
rendered_html
区分阶段,避免把几个类型都叫
content
。如果项目允许,也可以用轻量的数据类包裹,明确哪个函数只接受纯文本。命名不能替代测试,却能帮助审查发现“把最终 HTML 又交给翻译”的接线错误。
当前输入
希望得到什么
应先确认
原始 HTML
可翻译文字
用解析器定位文本节点
DOM 文本
目标语言文本
通常不要再无条件解码
译文纯文本
页面可见文字
让模板按文本转义
允许的富文本
安全展示片段
使用明确的清洗策略
不要循环解码直到“不再变化”
这种写法看起来能处理多层实体,实际上会破坏用户本来就想展示的代码。教程里讲的
<div>
就可能是有意保留的字面量,而不是漏处理的标签。是否应该再解一层,应由输入协议决定,不能由字符串外观猜测。
正文里的链接、属性值和代码块还可能有不同的翻译政策。保留一组含尖括号、引号、与号和实体字面量的回归样本,分别检查解析后的文本与最终浏览器展示,比只比较源文件字符串更有用。
翻译验收应该保留这种小样本
评估
OmniDoc(产品入口)
等文档翻译入口时,可以把这类样本放进 HTML 测试文件,观察译文里的标签示例和产品名是否仍按预期显示。不要把“英文翻出来了”作为唯一完成条件:内容含义、转义层数和代码保护都是交付的一部分。
参考:
Python html 模块
。
- 1 -
更新于 2026-10-08