应保留h1–h6、p、li、dt/dd中的可见纯文本,删除script/style等噪声及aria-hidden元素;键名需用DOM路径+文本哈希生成,避免语义冲突与序列化问题;提取时过滤短词、空格、实体并保留旧翻译值。
直接用 innerText 或 textContent 拿全文,大概率会混入导航栏、页脚、广告脚本输出等噪声。真正要进翻译字典的,是用户可见且语义独立的文本节点。
推荐做法是先用 CSS 选择器明确范围,再逐节点过滤:
<h1>–<h6>、<p>、<li>、<dt>/<dd> 中的纯文本style、script、noscript、meta、link 标签及其后代aria-hidden="true" 或 role="presentation" 的元素<input> 和 <textarea>,只取 placeholder 属性值,value 不提取(它属于运行时状态,不是界面文案)“提交”“确定”“OK”这种短词在不同上下文里语义不同,直接当 key 会导致翻译错位;更糟的是,带空格、换行、HTML 实体(如 )的文本无法稳定哈希或 JSON 序列化。
可靠做法是为每个文本节点生成唯一、可复现的键:
立即学习“前端免费学习笔记(深入)”;
"main-article-header-01#sha256:abc123"
element.closest("article")?.dataset.id 或 element.parentElement?.tagName 等轻量标识,避免依赖 class 名(易变)"button-readmore-01"、"button-readmore-02"
不用重写轮子,BeautifulSoup 配合少量清洗逻辑就足够。关键不是功能全,而是输出稳定、可 diff、可增量更新。
示例片段(注意 strip() 和 replace("xa0", " ") 处理不间断空格):
from bs4 import BeautifulSoupimport hashlibimport json<p>def extract_translatable_texts(html_path):with open(html_path, encoding="utf-8") as f:soup = BeautifulSoup(f, "html.parser")</p><pre class='brush:php;toolbar:false;'>texts = {}for tag in soup.find_all(["h1", "h2", "h3", "p", "li", "dt", "dd"]): text = tag.get_text(strip=True) if not text or len(text) < 2: # 过滤单字符、空白 continue text_clean = text.replace("xa0", " ").strip() key = hashlib.sha256(text_clean.encode()).hexdigest()[:8] # 加上下文前缀防冲突 full_key = f"{tag.name}-{key}" texts[full_key] = {"source": text_clean, "target": ""}return texts
with open("zh-CN.json", "w", encoding="utf-8") as f:json.dump(extract_translatable_texts("index.html"), f, indent=2, ensure_ascii=False)
生成字典只是第一步,真正卡住团队的是后续同步和冲突处理:
<p> 换成 <div role="paragraph">)会导致 key 全变——必须配套维护 DOM 路径规则,不能只靠哈希zh-CN.json 后,前端 JS 加载时若遇到缺失 key,应 fallback 到源文本,而不是留空或报错"target" 字段要尽量保留,仅新增未出现的 key;用 dict.update() 而非覆盖写入