用Map实现i18n的核心是双层映射:外层Map以词条key为键、内层Map为值,内层Map以语言代码为键、翻译文本为值;支持动态增删语言、运行时加载、fallback机制及热更新。

用 Map 实现国际化(i18n)词条的多语言动态映射,核心思路是:把每条词条的 key 作为 Map 的键,值则是一个子 Map,按语言代码(如 'zh'、'en')映射到对应翻译文本。这种方式比嵌套对象更灵活,支持运行时增删语言、动态加载词条,且天然避免原型污染和 key 类型限制问题。
结构设计:双层 Map 映射
外层 Map 的 key 是词条标识(如 'button.submit'),value 是一个内层 Map,负责存储该词条在各语言下的翻译:
- 外层:
Map—— 词条名 → 语言→翻译> - 内层:
Map—— 如new Map([['zh', '提交'], ['en', 'Submit']])
初始化与词条注册
可封装一个 I18nMap 类,提供 set(key, lang, text) 和批量注册方法:
class I18nMap {
#map = new Map();
set(key, lang, text) {
if (!this.#map.has(key)) {
this.#map.set(key, new Map());
}
this.#map.get(key).set(lang, text);
}
// 批量注册:{ 'button.cancel': { zh: '取消', en: 'Cancel' } }
load(dict) {
Object.entries(dict).forEach(([key, translations]) => {
Object.entries(translations).forEach(([lang, text]) => {
this.set(key, lang, text);
});
});
}
}
const i18n = new I18nMap();
i18n.load({
'button.submit': { zh: '提交', en: 'Submit', ja: '送信' },
'error.required': { zh: '此项为必填', en: 'This field is required' }
});
运行时语言切换与取值
通过 get(key, lang) 获取指定语言的翻译,支持 fallback(如当前语言无翻译,回退到默认语言):
- 直接查:若存在
lang对应值,返回它 - fallback:可传入备用语言列表,例如
['zh', 'en'],依次查找首个命中项 - 未命中时可返回 key 本身(便于发现漏翻译)或空字符串
get(key, lang, fallbacks = ['en']) {
const langMap = this.#map.get(key);
if (!langMap) return key;
if (langMap.has(lang)) return langMap.get(lang);
for (const fallbackLang of fallbacks) {
if (langMap.has(fallbackLang)) return langMap.get(fallbackLang);
}
return key; // 或 throw new Error(`Missing translation for ${key} in ${lang}`);
}
动态扩展与热更新支持
Map 天然支持运行时修改,适合以下场景:
- 用户切换语言后,无需重载页面,只需更新当前
lang状态,后续get()自动生效 - 按需加载语言包:调用
load()注入新语言翻译,不影响已有词条 - 模块级词条隔离:不同组件可各自维护局部
I18nMap实例,再合并到全局实例 - 测试友好:可为单元测试临时注入 mock 翻译,不影响其他用例
不复杂但容易忽略:确保 key 命名规范(推荐用点分隔的路径式,如 'form.login.password'),并统一管理默认语言与 fallback 链,就能让 Map 成为轻量、可靠、可演进的 i18n 基础设施。











