一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何通过 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.jsonpt.json;更麻烦的是,用户可能只支持 en,但浏览器返回 en-GB,这时不提取主语言码就会加载失败。

常见错误现象:fetch("lang/en-GB.json") 404,页面文本全变成 key(如 "welcome");或者加载了错误语言包导致乱码或缺失翻译。

标准做法是提取主语言码,并按优先级 fallback:

  • 先取 navigator.languagenavigator.languages[0](后者更准,但 IE 不支持)
  • .split("-")[0] 提取主语言标识,如 "zh-CN" → "zh"
  • 检查该主语言是否在你的 SUPPORTED_LANGS = ["zh", "en", "ja", "es"] 列表中
  • 不在则 fallback 到 localStorage 存的上次选择 → 再 fallback 到 "en"

fetch 加载语言包时如何避免阻塞首屏渲染

直接在 DOMContentLoadedawait 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 结构),只替换 textContentplaceholder 等安全属性
  • 不要在 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。

热门栏目