最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何通过 navigator.language 自动判别访客语言偏好并静默加载对应的国际化 I18n 资源包
时间:2026-06-29 09:44:57 编辑:袖梨 来源:一聚教程网
不能直接用navigator.language加载资源包,因其返回值如"zh-CN"含地区后缀,而语言包通常仅命名为zh.json;须先split("-")[0]提取主语言码,校验是否在支持列表中,否则按localStorage、默认语言逐级fallback。
navigator.language 能直接拿到浏览器首选语言,但直接用它加载资源包大概率会出错——因为返回值如 "zh-CN" 或 "en-US" 很可能不在你的语言列表里,也没做降级 fallback。必须先标准化、再校验、最后加载。
为什么不能直接用 navigator.language 作为资源文件名
浏览器返回的值带地区后缀("zh-CN"、"pt-BR"),而你实际维护的语言包大概率只叫 zh.json、pt.json;更麻烦的是,用户可能只支持 en,但浏览器返回 en-GB,这时不提取主语言码就会加载失败。
常见错误现象:fetch("lang/en-GB.json") 404,页面文本全变成 key(如 "welcome");或者加载了错误语言包导致乱码或缺失翻译。
标准做法是提取主语言码,并按优先级 fallback:
- 先取
navigator.language或navigator.languages[0](后者更准,但 IE 不支持) - 用
.split("-")[0]提取主语言标识,如"zh-CN" → "zh" - 检查该主语言是否在你的
SUPPORTED_LANGS = ["zh", "en", "ja", "es"]列表中 - 不在则 fallback 到 localStorage 存的上次选择 → 再 fallback 到
"en"
fetch 加载语言包时如何避免阻塞首屏渲染
直接在 DOMContentLoaded 里 await fetch(langUrl) 会让整个页面等 JSON 下载完才开始渲染,尤其弱网下明显卡顿。静默加载的关键是「异步 + 缓存 + 非阻塞」。
实操建议:
- 用
fetch(langUrl).then(r => r.json()).catch(() => ({})),失败不抛错,兜底返回空对象 - 加载过程不 await,而是用 Promise 状态控制后续 UI 更新(比如等 DOM 就绪后再替换文案)
- 加
cache: "force-cache"或利用 Service Worker 缓存已加载过的语言包 - 首次访问可先用内联默认语言对象(如
const en = { welcome: "Welcome" }),避免白屏
如何让 document.querySelectorAll("[data-i18n]") 正确更新已有 DOM
很多教程只说“遍历元素设 textContent”,但忽略两个关键点:一是属性值可能是嵌套 key(如 data-i18n="form.login.button"),二是插值参数(如 { name: "Alice" })需要运行时注入。
正确处理方式:
- 把
data-i18n值按.拆解,逐层取值:obj["form"]["login"]["button"] - 允许元素带额外属性传参,例如
data-i18n-params='{"name":"{username}"}',再用正则替换 - 更新前先保存原始 innerHTML(防覆盖 HTML 结构),只替换
textContent或placeholder等安全属性 - 不要在
load事件里批量操作,改用MutationObserver监听新插入节点并自动初始化
localStorage 存语言偏好时容易漏掉的边界情况
用户手动切语言后写入 localStorage.setItem("lang", "ja") 很简单,但以下情况常被忽略:
- 用户清空 localStorage 后,下次仍应 fallback 到
navigator.language,而不是崩成undefined - URL 参数
?lang=fr的优先级应高于 localStorage(运营活动强需求),但刷新后要同步写回 localStorage - 多标签页场景下,一个页面切语言,其他同域页面应响应变化(用
storage事件监听) -
localStorage值必须校验合法性,防止存入"xss<script>"</script>类非法字符串影响后续eval或模板渲染
最易被忽略的其实是语言码标准化时机:不是在加载资源前标准化一次就完事,而是在每次调用 t("key") 时都应基于当前有效语言码查表——因为用户可能在页面生命周期内切换语言,而 JSON 包已全部加载完毕,此时只需换 lookup 行为,无需重复 fetch。