data-i18n必须显式覆盖placeholder、alt、title等所有可翻译属性并加对应后缀,lang属性须逐节点设置不可继承,动态dom需手动触发翻译,含html文案须用可信纯html片段且与lang同步更新。

data-i18n 属性必须覆盖所有可翻译的属性,不只是 textContent
只给元素加 data-i18n,但没处理 placeholder、alt、title、aria-label 等属性,切换语言后这些文本依然卡在旧语言里。常见错误是:<input placeholder="Search"> 用 data-i18n 标记后仍显示英文,因为默认逻辑只改 textContent。
正确做法是显式声明对应后缀:
data-i18n-placeholder="search_hint"data-i18n-alt="avatar_desc"data-i18n-title="tooltip_info"data-i18n-aria-label="close_modal"
value 属性一般不翻译(属于用户输入数据),但 <button></button> 和 <input type="submit"> 的显示文案建议统一走 textContent 更新,避免提交时意外带出多语言值。
lang 属性必须逐个显式设置,不能依赖 documentElement.lang 继承
只改 document.documentElement.lang = 'zh-Hans' 是无效操作。浏览器和屏幕阅读器按每个元素自身的 lang 属性决定标点宽度、连字规则、字体回退链和语音朗读方式——它不继承父级。
这意味着:
-
<p>欢迎</p>必须写成<p lang="zh-Hans">欢迎</p> -
<pre class="brush:php;toolbar:false;" lang="bash"></pre>这类已有lang的代码块要保留原值,这是合法混排场景 -
<img alt="logo">的alt文本必须配lang="zh-Hans",否则会被读作英文 -
<script></script>和<style></style>内部不用设lang,它们不参与文本渲染
漏设 lang 比不设更糟:错误值(如 lang="cn")会导致字体回退失效、标点间距错乱、屏幕阅读器发音错误。
多语言 code 命名必须分层且带服务前缀,避免全局冲突
直接用 "save" 或 "error" 这类泛化 key,上线后必然撞车。规范要求 code 分两段:[服务名].[功能名] + [类型].[含义],例如:
-
hpfm.event.model.event.code(模型字段) -
hzero.common.view.button.save(平台通用按钮) -
hpfm.user.view.validation.required(业务校验提示)
其中:
- 第一段
hpfm是服务标识,全小写、项目唯一、不可省略 - 第二段严格区分
model.和view.,禁止混用 - 含冒号或花括号的内容需转义:
"abc : "测试:冒号""
跨模块引用时,不要复制 key,而是在当前模块声明依赖:@formatterCollections({ code: ['hpfm.event'] }),由构建工具自动合并语言包。
动态插入的 DOM 必须手动触发翻译,不会自动监听
AJAX 加载的弹窗、分页表格新行、懒加载模块插入后,里面的 data-i18n 不会自动生效。常见现象:<modal><h2 data-i18n="modal_title"></h2></modal> 打开后仍是原始 key 名。
解决方案不是靠 MutationObserver 监听——它无法判断哪些节点需要翻译,也无法处理嵌套结构中的属性更新。而是:
- 插入后立即调用翻译函数,如
i18n.translate(el) - 确保该函数能递归处理子元素,并识别所有
data-i18n-*属性 - 对含 HTML 结构的文案(如“请阅读服务条款”),语言包中对应值必须是可信纯 HTML 片段,且不做
innerHTML以外的执行
真正容易被忽略的是:lang 属性和 data-i18n 的同步时机。两者必须在同一次 DOM 更新中完成,否则屏幕阅读器可能读错语言,而视觉文案已切换——这种错位在无障碍测试中极难复现。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











