开源地址: https://github.com/chennlang/easy-lang · 觉得不错的话,欢迎 ⭐ Star
原文地址: https://juejin.cn/post/7673359458647179315
tips: 由于平台字数限制,让 AI 进行二次总结,如需查看完整内容,可点击上面链接。
传统 i18n 的痛点
不知道大家在前端国际化开发中有没有遇到这些问题:
[ol]
[/ol]
传统 i18n 方案示例
一个登录页面,传统方案翻译前是这样的:
用户登录
用户名:
登录
翻译后变成:
{t('login.title')}
{t('login.username.label')}:
{t('login.submit.text')}
同时需要维护多个语言文件( en-US 、zh-CN 、zh-TW 、ja-JP……),每个文件都要按模块组织嵌套结构,维护成本极高。
核心问题总结
[td]问题[/td]
[td]说明[/td]
变量命名
每个中文都要想英文 key ,浪费精力
可读性
代码中全是 t('xxx.xxx.xxx'),难以直观理解
检索能力
复制页面中文无法搜到组件,只能搜到翻译文件
高侵入性
国际化代码重构了业务逻辑,去不掉
流程复杂
命名→改代码→翻译→写入多个文件
复用性差
"确认""取消"等通用词在各模块重复定义
开发应该只关注功能和业务,为什么要消耗这么多时间在国际化上?
Easy Lang:回归本质
我理解的国际化翻译原理其实很简单:
const translations = {
"退出登录": { "zh_CN": "退出登录", "en": "Logout" }
}
function t(text) { return translations[text][currentLang] }
Easy Lang 正是基于这个理念开发的——中文即 Key ,所见即所得。
安装
pnpm add easy-lang
快速上手
1. 新建翻译文件 locales/translation.json:
{
"用户登录": { "zh-CN": "用户登录", "en-US": "User Login" },
"登录失败: {error}": { "zh-CN": "登录失败: {error}", "en-US": "Login failed: {error}" },
"密码": { "zh-CN": "密码", "en-US": "Password" }
}
2. 创建实例 locales/index.ts:
import { createI18nTool } from "easy-lang";
import translations from "./translation.json";
export const i18nTool = createI18nTool({
defaultLang: 'zh-CN',
langs: ['zh-CN', 'en-US'],
translations,
});
export const $t = i18nTool.$t;
3. 在代码中使用:
function LoginForm() {
return (
{$t('用户登录')}
{$t('密码')}:
{$t('登录')}
{$t('您还可以尝试 {count} 次', { count: 3 })}
);
}
对应的翻译文件只有 translation.json,所有语言集中管理,不用再在多个文件间切换。
对比传统方案
[td]对比项[/td]
[td]传统 i18n[/td]
[td]Easy Lang[/td]
代码写法
t('login.title')
$t('用户登录')
变量命名
需要先想英文变量名
不需要
翻译文件
每个语言一个文件
一个文件,中文即 key
可读性
通篇英文变量
中文原样保留
全局搜索
只能搜到翻译文件
直接搜中文定位组件
模块化翻译(适用于大型项目)
const translations = {
default: { '你好': { "zh-CN": "你好", "en-US": "Hello" } },
custom: { '欢迎 {name}': { "zh-CN": "欢迎 {name}", "en-US": "Welcome {name}" } }
};
const i18n = createI18nTool({ defaultLang: "zh-CN", langs: ["zh-CN", "en-US"], translations });
// 指定模块
i18n.$t('欢迎 {name}', { name: '张三', module: 'custom' });
// 或创建专用函数
const $t_custom = i18n.$module('custom');
$t_custom('测试');
类型安全:不带 module 时只允许 default 模块的 key ,带 { module: "xxx" } 时自动限定对应模块,享受完整类型提示。
React 集成
pnpm add @easy-lang/react zustand
// locales/index.ts
import { createI18nTool } from "easy-lang";
import { createReactI18nTool } from "@easy-lang/react";
import translations from "./translation.json";
const reactI18nTool = createReactI18nTool(
createI18nTool({ defaultLang: "zh_CN", langs: ["zh_CN", "en"], translations })
);
export const useTranslate = reactI18nTool.useTranslate();
// App.tsx
function App() {
const { $t, changeLang, currentLang } = useTranslate();
return (
changeLang("en")}>English
{$t("用户登录")}
);
}
changeLang 默认刷新页面;若只需响应式更新,设置 autoReload: false。
变量替换
// translation.json: { "欢迎 {name}": { "en": "Welcome, {name}!" } }
$t("欢迎 {name}", { name: "Tom" }); // => "Welcome, Tom!"
强制指定语言
$t("保存", {}, "zh_HK"); // 强制使用繁体中文
运行时配置 configure()
i18n.configure({
defaultLang: "zh_CN",
autoReload: false, // 不刷新页面,响应式更新
storageKey: "tenant-lang", // 自定义存储 key
});
自定义语言存储
默认使用 localStorage,也支持从 query 参数、cookie 等来源读取:
const i18n = createI18nTool({
// ...其他配置
storage: {
getLang({ defaultLang, langs, storageKey }) {
const stored = localStorage.getItem(storageKey);
return stored && langs.includes(stored) ? stored : defaultLang;
},
setLang(lang, { storageKey }) {
localStorage.setItem(storageKey, lang);
},
},
});
SSR 场景下自动安全降级。
Easy Lang 解决了哪些问题?
1. 不需要变量命名
直接使用中文原文,不改变代码结构,只需用 $t() 包裹:
$t("你好");
$t("欢迎 {name}", { name: "Tom" });
翻译文本原样保留,兼具可读性和搜索能力。
2. 自带 TS 类型检测
未翻译的文本会标红提示,排查更方便。
3. 适应 AI 编辑器
翻译文件结构简单,所有语言的翻译集中在同一个 key 下,Cursor 等工具的自动补全更加高效。
4. 极简翻译流程
所有未翻译文本会被收集到 i18n.untranslatedList,开发完成后打印出来,通过 AI 统一翻译后写回文件:
console.log(i18n.untranslatedList); // ['暂无数据', '更新时间']
5. 一词多意( context 支持)
同一中文词在不同场景翻译不同:
{
"模型管理": {
"zh-CN": "模型管理",
"en-US": "Model Management",
"contexts": {
"sidebar": { "zh-CN": "模型", "en-US": "Models" }
}
}
}
$t('模型管理', { context: 'sidebar' }); // => "Models"
6. 模块化隔离
大型项目中各模块翻译独立,避免互相影响。
VSCode 插件:翻译流程再简化
配合 VSCode 插件,实现一键翻译未覆盖文本。
安装
从 GitHub Releases 下载 .vsix 文件,在 VSCode 中执行 Extensions: Install from VSIX... 安装。
配置 .vscode/easy-lang.json
{
"translationPath": "locales/translation.json",
"translateMode": "google",
"targetLangs": ["en-US", "zh-CN", "zh-HK"]
}
功能
也可使用仓库自带的 Codex skill 自动生成配置。
开发中遇到的问题及解决
问题一:切换语言不刷新页面,如何响应式更新?
最直接的方案是切换语言后刷新页面——实际场景中切换语言并不频繁,这是可接受的。
若追求无感切换,配合 @easy-lang/react 的 hook 使用:
export const useVARS = () => {
const { $t } = useTranslate();
return [$t('常量 1'), $t('常量 2')];
};
问题二:闭包中的翻译函数未更新
闭包内的函数不会因 state 变化而重新生成,需要监听 $t 重新设置:
useEffect(() => {
setPagination({
...pagination,
showTotal: (total) => $t(`总共 {total} 条`, { total }),
});
}, [$t]);
AI/Codex Skill
可通过以下提示词让 AI 自动接入或配置:
应用接入 easy-lang 国际化:
请安装 GitHub 仓库 chennlang/easy-lang 中的 Codex skill ,路径为 skills/easy-lang-app-i18n ,使用 $easy-lang-app-i18n 帮我在应用中接入 easy-lang 国际化。
配置 VSCode 插件:
请安装 GitHub 仓库 chennlang/easy-lang 中的 Codex skill ,路径为 skills/easy-lang-vscode-config ,使用 $easy-lang-vscode-config 帮我生成 easy-lang-vscode 插件所需的配置文件。
使用体验
切换到 Easy Lang 后最明显的感受:定位 BUG 效率大幅提升,直接搜索界面文字就能定位到组件。相较之前,节省了大量定位时间。
最后
如果 Easy-Lang 对你有帮助,欢迎到 GitHub 点个 ⭐ Star ,你的支持是我持续迭代的动力!也欢迎提交 Issue 和 PR ,一起让前端国际化这件事变得简单。
Easy-Lang 使用 MIT 许可证开源,可以放心用到你的项目中。


