Proxy 拦截属性读写实现字段自动翻译:通过 Proxy 的 get trap 查表翻译,依赖响应式 locale 信号触发重算,支持 fallback、字段级开关与缓存优化,保持源数据纯净且解耦翻译逻辑。

用 Proxy 拦截属性读写,让字段自动翻译
核心思路是:把原始数据对象包装进 Proxy,当访问某个字段(比如 user.name)时,不直接返回原始值,而是查表翻译成目标语言;写入时也做反向映射或透传,保持源数据纯净。关键不在“翻译逻辑”,而在“何时、对谁、怎么触发翻译”——Proxy 让这个时机完全可控。
翻译规则与语言环境解耦设计
翻译不能硬编码在 Proxy 里。推荐用独立的 Translator 实例管理多语言词典和上下文规则。Proxy 的 get trap 只负责委托查询:
- 传入当前路径(如 "profile.nickname")、原始值、当前 locale
- 支持 fallback:查不到就返回原文,或走兜底策略(如拼音首字母、占位符)
- 允许字段级开关:某些字段(如 ID、时间戳)跳过翻译,靠白名单/注解控制
响应式联动:翻译结果随语言切换实时更新
仅拦截访问还不够——语言切换时,已渲染的字段必须重算。办法是让 Proxy 的 get 依赖一个响应式信号(如一个 ref 或 observable):
- 每次 get 都读取当前 locale 信号(触发依赖收集)
- 切换 locale 时,通知所有订阅该信号的视图重新求值
- Vue 3 的 computed 或 SolidJS 的 createMemo 天然适配这种模式
避免无限递归与性能陷阱
Proxy 默认会代理整个对象树,但深层嵌套+频繁翻译易引发性能问题。实用对策:
立即学习“前端免费学习笔记(深入)”;
- 只对明确标记为“可翻译”的对象启用 Proxy(例如加 $$translatable: true 属性)
- get trap 中缓存翻译结果(Map
),避免重复查表 - 对数组等集合类型,不递归代理每一项,改为按需代理(访问 item.name 时才代理该 item)
- 禁止在 get 中触发副作用(如发请求、改 DOM),保持纯函数语义
实际落地一小步:一个最小可用示例
不用框架也能跑通核心链路:
const i18n = {
zh: { "user.name": "用户名", "btn.submit": "提交" },
en: { "user.name": "User Name", "btn.submit": "Submit" }
};
function createI18nProxy(obj, localeRef) {
return new Proxy(obj, {
get(target, key) {
const path = `${target.$$ns || ''}.${key}`.replace(/^\./, '');
const translated = i18n[localeRef.value]?.[path] || target[key];
return typeof translated === 'object' && translated !== null
? createI18nProxy(translated, localeRef)
: translated;
}
});
}
// 使用
const locale = { value: 'zh' };
const data = createI18nProxy({ name: '张三', $$ns: 'user' }, locale);
console.log(data.name); // → "用户名"
locale.value = 'en';
console.log(data.name); // → "User Name"(需配合响应式系统触发重读)
真正工程化时,再补上词典热加载、命名空间自动推导、编译期静态分析剔除无用翻译键等能力。不复杂但容易忽略。


















