必须卡在ci里——否则语言包漏更新、键名不一致、bcp 47格式错误等必漏;需用jq校验json结构、键名一致性及值类型,htmlhint检查data-i18n属性,puppeteer验证lang属性同步。

纯 HTML 项目做国际化持续集成,核心不是“能不能做”,而是“要不要把翻译流程卡在 CI 里”。答案很明确:必须卡——否则语言包漏更新、键名不一致、BCP 47 格式错误、甚至 lang 属性写成 zh_CN 这种低级错误,全靠人工 review 几乎必漏。
怎么用 GitHub Actions 检查语言包结构一致性
语言包 JSON 文件一旦键名不齐、嵌套过深或字段缺失,前端 t() 调用就会返回 undefined,页面直接留白。CI 必须在 PR 阶段就拦截这类问题。
- 用
jq校验所有./locales/*.json是否为扁平对象:jq -e 'to_entries | all(.key | test("^[a-z0-9_.]+$"))' ./locales/en-US.json - 比对各语言文件键名是否完全一致:用
jq -r 'keys_unsorted[]' ./locales/en-US.json | sort > en.keys,再对zh-CN.json做同样操作,最后diff en.keys zh.keys - 禁止空值以外的
null或object类型值:jq -e 'all(.[] | type == "string" or . == "")' ./locales/zh-CN.json
为什么 HTMLHint + 自定义规则必须检查 data-i18n 属性
只靠人肉加 data-i18n 极易遗漏:title、placeholder、aria-label 这些属性不会被 textContent 替换覆盖,但又是辅助技术最常读的内容。CI 不该放过。
- 在
.htmlhintrc中启用attr-value-not-empty并自定义规则,强制要求:input[placeholder]必须同时有data-i18n-placeholder;img[alt]必须有data-i18n-alt - 禁止在
<script></script>、<pre class="brush:php;toolbar:false;"></pre>、<style></style>内部出现data-i18n—— 这些节点不渲染文本,加了纯属误导 - 用正则扫描所有
data-i18n-*属性值,确保后缀仅限placeholder、title、alt、aria-label四种,避免拼错成data-i18n-titel
如何在 CI 中验证 lang 属性是否正确同步
只改 document.documentElement.lang 是最大幻觉。屏幕阅读器、字体 fallback、标点间距全看每个元素自己的 lang。CI 得确认 DOM 中的 lang 不是摆设。
- 用 Puppeteer 启动无头 Chrome,加载页面后执行:
document.querySelectorAll('[data-i18n]').forEach(el => { if (!el.hasAttribute('lang')) console.warn('missing lang on', el); }) - 检查是否存在硬编码的
lang="chinese"或lang="zh_CN":CI 脚本中 greplang="[^"]*[^a-z][^"]*"并拒绝提交 - 对已带
lang的特殊节点(如<pre class="brush:php;toolbar:false;" lang="bash"></pre>)做白名单校验,确保它们没被误覆盖——CI 应记录这些节点路径,切换语言时跳过它们
真正难的不是写这些检查脚本,而是让团队接受:语言包提交和 HTML 修改必须走同一次 PR。否则,data-i18n="form_email_required" 加进去了,但 en-US.json 里没这行键,CI 就得立刻红掉——不能等 QA 测到才报。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











