直接用 data-i18n 标记 + 外部 json 语言包 + 同步更新 document.documentelement.lang 即可实现跨平台 html 国际化,但需规避 webview 兼容性问题:改 fetch 路径为 'locales/en.json'、旧 android 用 response.text().then(json.parse)、加 crossorigin="anonymous"、fallback navigator.language 为空时的 localstorage 语言、手动为每个翻译元素设置 lang 属性、特殊节点(input/select/svg)需对应 data-i18n-* 属性、动态 dom 插入后立即翻译、避免 innerhtml 导致状态丢失、intl 实例需重建。

直接用 data-i18n 标记 + 外部 JSON 语言包 + 同步更新 document.documentElement.lang,就能在 HTML 里跑通跨平台国际化——不依赖构建工具、不卡 SSR、不崩 WebView,iOS Safari、Android Chrome、Electron、Capacitor 封装后都认。
怎么让 data-i18n 在 Cordova/Capacitor 里不丢翻译
WebView 环境(尤其旧版 Android)常因 file:// 协议禁 fetch 或 CORS 静默失败,导致语言包加载不出。
- 别用
fetch('./locales/en.json')—— 改成fetch('locales/en.json')(去掉开头的点),否则 Capacitor 的 asset server 路径解析会错 - Android WebView 6.x–7.x 不支持
response.json()的 Promise 链式调用,得用response.text().then(JSON.parse)兜底 - 加
crossorigin="anonymous"到<script></script>标签上,避免某些 WebView 因缺少 CORS header 拒绝加载内联 JS 中的 fetch - 首次启动时若
navigator.language返回空字符串(常见于安卓隐私模式),立刻 fallback 到localStorage.getItem('lang') || 'en',别等用户点按钮
为什么 lang 属性必须手动同步到每个元素
只设 document.documentElement.lang = 'ja-JP',iOS VoiceOver 还是读英文、Android TalkBack 把顿号当西文间距、Electron 渲染器把中文标点撑开——因为浏览器和辅助技术查的是每个节点自己的 lang,不是继承来的。
-
<p data-i18n="intro"></p>翻译完,必须紧接着执行el.setAttribute('lang', 'ja-JP') - 已带
lang的特殊节点(如<pre class="brush:php;toolbar:false;" lang="bash"></pre>、<code lang="sql">)要跳过,它们属于多语言混排,不该被主语言覆盖 - 动态插入的 DOM(比如 Capacitor 插件弹出的 toast、Cordova 的 camera 成功回调生成的
<img>)插入后必须立即调用翻译函数,否则data-i18n是死字符串 - BCP 47 必须严格:写
zh-Hans,别写zh_CN;iOS 对ja支持弱,得写ja-JP
表单控件和 SVG 文本怎么打 data-i18n 才生效
input、select、button、<svg><text></text></svg> 这些节点的文本不走 textContent,硬标 data-i18n 没用。
-
<input placeholder="Search">→ 改成<input data-i18n-placeholder="search_hint"> -
<select><option>Yes</option></select>→ 给select加data-i18n-options="confirm.choices",语言包里对应值是数组:"confirm.choices": ["是", "否"] -
<button>Submit</button>→ 同时设data-i18n="form.submit"和data-i18n-text="form.submit"(有些老 WebView 不识别无后缀的data-i18n) -
<svg><text>Download</text></svg>→ 加<text data-i18n="btn.download"></text>,JS 里单独识别SVGTextElement类型并调用textContent
切换语言时页面闪动或状态丢失怎么办
直接 innerHTML = translatedHTML 会清掉 input.value、销毁事件监听器、重置第三方组件(比如日期选择器),在跨平台 WebView 里尤其明显。
- 永远优先用
el.textContent = value更新纯文本,仅当语言包值含可信 HTML(如"terms.link": "请阅读<strong>服务条款</strong>")才用el.innerHTML,且必须提前白名单过滤 - 切换前用
window.scrollY记位置,更新完用window.scrollTo(0, y)恢复,否则 Capacitor 页面会跳顶 - 表单输入框的
value属性绝对不翻译(那是用户数据),但label文字必须标data-i18n;button的value(用于提交)也不动,只改textContent - 如果用了原生
Intl.DateTimeFormat,切换语言后必须重建实例:new Intl.DateTimeFormat(lang, options),旧对象不会自动更新
最易被忽略的点:动态内容插入后没触发翻译、lang 属性没同步到子元素、WebView 下 fetch 路径写错。这三个问题在真机调试时才暴露,模拟器里往往一切正常。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











