实战指南 › 多语言静态站实战:源与产物同目录的陷阱

多语言静态站实战:源与产物同目录的陷阱

更新:2026-10建站实战

这个站有 180 个页面、5 个语种。某天发现英文页的导航是英文、正文却整段是中文——而且已经上线好几天。查下来根因不是翻译丢了,是构建顺序。

症状:只有导航被翻译了

语言下拉框正确显示 EN,导航也是英文,但正文 hero、卡片、列表全是中文。这种「一半对一半错」的形态最容易让人误判成翻译数据丢了。

真正的诊断方法不是看页面,而是看源文件:统计每个页面正文里还有多少个多语 span。

# 统计 </nav> 之后的多语 span 数量
import re
s = open("src5/tools/chatgpt.html", encoding="utf-8").read()
body = s[s.find("</nav>"):]
print(len(re.findall(r'class="(?:zh|en|id|sl|it)"', body)))

结果是 0。36 个源页面的正文 span 全部为 0,只有 header nav 里的 25 个还在——因为 nav 是另一个脚本后来补回去的。

根因:源和产物写在同一个目录

最初的构建链是这样的:生成器把带 5 语 span 的页面写到根目录,然后 build 脚本折叠 span 生成各语种页面,再把中文版写回根目录同一个路径(因为部署需要中文版在根)。

这一步等于把「源」覆盖成了「已折叠的单语页」。下一轮构建再抓快照时,抓到的就是没有 span 的单语页——折叠时无话可选,5 个语种全部输出中文。

关键教训:只要「源」和「产物」共用目录,且构建过程会回写产物,就必须在折叠之前把多语源快照到独立目录。顺序不是习惯问题,是正确性问题。

修法:把顺序固化进脚本

光记住顺序没用——对话会忘,人会错。正确做法是写一个入口脚本,让顺序变成代码的一部分,漏一步就直接构建失败。

# build_all.py —— 唯一构建入口
STEPS = [
    ("i18n_lint.py",      "翻译数据自检"),
    ("gen_content.py",   "生成内容页(带 5 语 span)"),
    # ...
    ("inject_seo.py",    "注入 SEO 头(仅根页)"),
    ("snapshot_src5.py", "快照多语源 ← 必须在折叠之前"),
    ("build_i18n.py",    "折叠成 180 个单语页"),
    ("audit_site.py",    "全站自检,不过则不部署"),
]

验证:别用肉眼看页面

肉眼检查只能覆盖你刚好打开的那一页,而且看不出「源码已退化、产物正常」这种时序问题。可靠做法是让脚本直接报告数量。

# 构建末尾断言
assert span_count(body) > 0, "正文无多语 span(会退化成单语)"
assert footer_count(page) == 1, "页脚重复"
assert len(re.findall(r'rel="alternate" hreflang', head)) == 6

最后一条来自一次真实误判:统计 hreflang 时把语言下拉菜单里的 <a hreflang> 也算了进去,误报「每个 hreflang 出现两次」。<head> 里其实恰好 6 条,完全正常。看到数量不对时,先确认统计范围,再改产品代码。

Advertisement
广告位(AdSense 接入后显示)

相关工具