HTML页面内容国际化与动态注入技术最佳实践
国际化需注意细节:data-i18n标记必须覆盖alt、title、aria-label、placeholder等属性;JSON语言包加载失败时应降级加载en json或默认对象;切换语言时需同步所有lang属性并更新动态DOM;外部文本注入需用textContent,含结构文案需经DOMPurify过滤防XSS。
国际化这事儿,说到底,看着简单,真要在页面上跑得顺、不出错,其实到处是细节。很多团队把翻译文件一丢、切换按钮一挂就觉得完事了,结果上线后问题一个接一个:有地方没翻译到、切换时页面闪一下、读屏软件读出奇怪的东西来——今天就挨个把这些“坑”挑明了说。

data-i18n标记必须覆盖所有可翻译属性,不只是textContent
只给 加个属性,转头把 给忘了,结果切换语言后那个 placeholder 纹丝不动,还是英文——这不是漏翻译,是标记根本没打全。
常见的“漏网之鱼”有哪些?alt、title、aria-label、placeholder,这些属性靠 textContent 更新逻辑是触达不到的。必须为它们单独加后缀:
data-i18n-placeholder="search_hint"data-i18n-alt="user_a vatar"data-i18n-title="tooltip_info"data-i18n-aria-label="close_button"
至于 value 属性,一般不需要动,那是用户输入的数据。但 和 这种带显示文案的,最好还是用 textContent 来更新,别不小心把英文值给提交上去了。
JSON语言包加载失败时页面留白,怎么兜底
fetch() 去加载 ./locales/zh.json,结果网络一抖没拉下来,或者某个 key 在 zh.json 里压根没定义——比如 "na v_home" 缺失。默认行为就是留空,用户看到的不是“未翻译”,而是白板一块。
怎么办?加载和查找两个环节都得兜底:
- fetch 外面包一层
try/catch,失败了就降级去加载en.json,或者直接给一个内置的默认对象 - 查 key 的时候写成
langPack[key] ?? langPack.fallback ?? "MISSING_KEY",不能直愣愣地写langPack[key],否则查不到就是undefined - 所有语言包的字段必须对齐。哪怕某个语言暂时没翻译,也要保留键,值设成空字符串
"btn_submit": "",至少结构不能缺 - HTTP 响应的
Content-Type必须是application/json,不然response.json()会静默抛错,你都不知道问题出在哪
切换语言时页面闪动或语音读错,根源在lang属性没同步
很多人只写了 document.documentElement.lang = "zh-Hans",却忘了页面里可能还有 或 。结果呢?屏幕阅读器依然按旧的 lang 朗读,中文顿号的停顿全乱了,英文字体回退也不生效——不是 JS 没跑完,是浏览器根本不认根节点继承这套逻辑。
切换语言时,必须做两件事:
- 遍历所有带
lang属性的元素(document.querySelectorAll("[lang]")),除了那些明确要保留原语言的(比如),其余一律改成当前语言码 - 所有新插入的动态 DOM(弹窗、分页表格行)插入后必须立即调用翻译函数,否则
data-i18n标记只是个普通字符串,不会自动生效 - BCP 47 格式一定要严格,用
zh-Hans而非zh_CN或chinese,否则浏览器会直接忽略,甚至触发 fallback 失败
外部文本注入与国际化混用时 XSS 风险高发点
举个例子:用 加载一个文本文件,里面是变量声明,然后把这个内容塞进 。如果这个文本来自 CMS 或日志生成,而语言包里又恰好用了 innerHTML 渲染带链接的文案(比如 "terms_link": "请阅读服务条款"),XSS 就藏在这条链路的中间。
安全边界必须划清楚:
- 纯文本内容一律用
textContent注入,不许走 HTML 解析那条路 - 含结构的文案(比如带
或链接的)必须走innerHTML,条件是语言包对应的值必须是可信的纯 HTML 片段——不能拼接用户输入,不能执行 JS - 动态注入的 HTML 片段(比如弹窗内容)一律过
DOMPurify.sanitize(),就算来源是内部系统也别掉以轻心 和内部不要写data-i18n——它们不参与渲染,JS 替换无效,还可能被误解析
最容易被忽略的其实是:语言包里的 HTML 片段一旦包含了用户可控内容(比如评论摘要),就必须过滤;而外部 .txt 文件如果被攻击者篡改,let text = '...' 就成了执行入口。这两条链路的安全水平,必须保持一致。

