应采用「data-i18n属性+json语言包」分离文案与结构,所有可见文本须显式声明键名(如),禁用innerhtml硬替换和html内联中文,键名须符合^[a-z][a-z0-9.-]*$正则,配合ci校验、模块化语言文件及英文注释保障协作一致性。

HTML中如何安全嵌入多语言文本而不破坏结构
直接在<div>里写中文或英文,等于把翻译逻辑硬编码进模板,后续换语言时得逐行改HTML——这是协作中最容易被忽略的“静态陷阱”。真正可维护的做法,是让所有文案脱离DOM结构本身。<p>常见错误现象:团队成员在<code><h2>用户中心</h2>里直接写中文,导致i18n工具无法提取、无法校验、无法做缺失检查。
- 所有可见文案必须通过
data-i18n属性声明,例如<h2 data-i18n="user.profile.title"></h2> - 禁用
innerHTML拼接多语言内容,尤其避免document.querySelector('...').innerHTML = langMap[key]这种JS侧硬替换 - 带变量的文案(如“欢迎,{name}”)必须用
data-i18n-params传参,而不是字符串模板:<span data-i18n="welcome.message" data-i18n-params='{"name": "张三"}'></span> - HTML注释里禁止出现待翻译文字,比如
<!-- 用户登录表单 -->——这类注释不会被提取,但会误导翻译人员
团队如何同步管理语言包与HTML结构变更
当设计师改了按钮文案、PM新增一个弹窗、前端重构了某个<section></section>,如果没人通知翻译组,语言包就会和HTML脱节。这不是流程问题,是技术链路断点。
使用场景:多人并行开发时,HTML模板频繁提交,语言键名却没人核对是否还存在、是否拼写一致。
- 所有
data-i18n键名必须符合^[a-z][a-z0-9.-]*$正则(小写字母开头,只含字母、数字、点、短横),禁止出现userProfileTitle或user_profile_title - 每次提交HTML前,运行脚本自动扫描新增/删除的
data-i18n键,并生成diff报告(可用node scripts/scan-i18n-keys.js) - 语言JSON文件按模块拆分(如
auth.json、profile.json),与HTML文件路径对应:src/pages/auth/login.html→lang/en/auth.json - CI流程中加入校验:若HTML引用了lang/en.json里不存在的key,构建失败
为什么Prettier默认配置会破坏i18n属性顺序
data-i18n必须紧挨着语义化标签(如<button></button>),否则屏幕阅读器可能跳过它;而Prettier默认按字母排序属性,会把data-i18n排到class后面甚至onclick前面,造成可访问性风险。
参数差异:prettier不支持按业务语义定制属性顺序,它只认class→id→data-这类基础规则,但data-i18n属于高优先级数据绑定属性,不能混在普通data-里。
- 必须在
.prettierrc中关闭属性重排:"htmlWhitespaceSensitivity": "css"+ 禁用htmlOptions相关插件 - 改用
prettyhtml替代Prettier处理HTML,它支持自定义attributeGroups,可强制data-i18n排第一 - VS Code中为
.html文件单独指定格式化工具,避免全局Prettier误触 - 在团队
.vscode/settings.json里锁定:"[html]": { "editor.defaultFormatter": "mechatroner.rainbow-csv" }(示例,实际用prettyhtml)
HTML注释里哪些内容会影响国际化协作
中文注释看起来无害,但会卡住自动化流程:i18n提取工具通常跳过注释,但翻译平台(如Crowdin)导入时会把中文注释当成待翻译内容,结果导出一堆空翻译键,污染语言包。
容易踩的坑:开发者写<!-- 该区域展示用户头像和昵称 -->,结果翻译组收到一条“该区域展示用户头像和昵称”的待译项,没人知道该删还是该翻。
- 所有HTML注释必须用英文,且只描述结构意图,不描述文案内容:
<!-- user avatar and display name section --> - 禁止在注释里写待办事项,如
<!-- TODO: 把这里改成多语言 -->——应直接改成data-i18n并提PR - 关键
data-i18n旁必须跟注释说明上下文,例如:<button data-i18n="form.submit"></button><!-- submit button in login form, not signup --> - 模板文件(如
_header.html)头部注释需注明语言包路径:<!-- @i18n: lang/en/header.json -->
最常被忽略的点:语言包里的键名和HTML里写的data-i18n值,哪怕只差一个点(user.profile vs user.profile.),都会静默失败——没有报错,只是显示为空白。必须靠CI里的键名校验环节兜底,不能靠人眼比对。











