应逐项标准化并匹配 navigator.languages 中的语言候选,优先选用 supported_langs 中首个匹配项,失败则回退 localstorage 或默认语言,动态生成小写路径并容错加载。

直接用 navigator.languages[0] 当作语言标识去加载资源,看似合理,实则忽略了一个关键事实:用户可能配置了多个偏好语言(比如 ["zh-CN", "en-US", "ja"]),而你的项目只支持 zh 和 en。这时若只查第一个,就可能错过更匹配的选项;若硬套完整标签,又大概率 404。真正可靠的方案,是把 navigator.languages 当作一个有序候选队列,逐项归一化、校验、映射,动态生成一组可尝试的资源路径。
提取并标准化每项语言标签
浏览器返回的语言项可能是大小写混杂、带地区后缀、甚至空值,必须统一清洗:
- 对每一项调用
.toLowerCase(),避免因大小写导致文件系统或 CDN 匹配失败 - 用
.split("-")[0]剥离地区信息,得到主语言码("zh-cn"→"zh","en-us"→"en") - 过滤掉无效值:空字符串、
"und"(未识别)、长度超过 3 的异常码(如"zh-hans"不应直接使用)
按优先级顺序匹配支持的语言列表
假设你维护的 SUPPORTED_LANGS = ["zh", "en", "ja", "es"],不能只看第一个候选,而应遍历整个 navigator.languages 数组:
- 从索引 0 开始,对每一项执行标准化处理
- 检查标准化后的语言码是否在
SUPPORTED_LANGS中 - 一旦命中,立即终止遍历,选定该语言作为本次加载目标
- 若全部遍历完无匹配,则 fallback 到 localStorage 记录的上次选择,再 fallback 到默认语言(如
"en")
动态生成资源路径与加载策略
选定语言码(例如 "zh")后,不直接拼接 lang/zh.json 就完事——还要考虑版本、缓存和降级容错:
- 路径格式统一为小写、无后缀:
lang/${lang}.json - fetch 时加
{ cache: "force-cache" },复用已有响应,避免重复请求 - 同时预设一个内联默认对象(如
const en = { welcome: "Welcome" }),确保首次渲染不白屏 - 加载失败时返回空对象
{},而非抛错,防止t("key")执行中断
兼容性兜底与用户控制权保留
navigator.languages 在 IE 中不可用,需有降级路径;更重要的是,它反映的是“浏览器设置”,不等于“用户当前意愿”:
- IE 或旧版 Safari 下,回退到
navigator.language || navigator.userLanguage - 始终提供手动语言切换器,并将选择结果存入
localStorage,下次优先读取 - 切换后更新
document.documentElement.lang属性,辅助屏幕阅读器与 SEO










