极简前端多语言方案基于纯 JS + 模板字面量,无需框架、构建或运行时依赖;通过 t(key, data) 函数实现键值查找与安全插值,语言包为扁平 JS 对象,缺失翻译返回 key,HTML 中零配置直用,支持快速切换语言与动态渲染。

用字符串模板实现极简前端多语言,核心是“不引入框架、不打包构建、不依赖运行时”,靠纯 JavaScript + 原生模板字面量(``)就能跑通。它适合轻量项目、原型验证、嵌入式页面或 legacy 系统改造——不是替代 i18next 或 vue-i18n,而是解决“就两三个页面、三种语言、明天就要上线”的真实场景。
把文案抽成键值对,存成纯 JS 对象
别碰 JSON 文件加载或异步请求,直接定义语言包为模块导出对象:
```js
// locales.js
export const messages = {
en: {
greeting: `Hello, ${'name'}!`,
cart: `You have ${'count'} item(s)`,
submit: `Submit`
},
zh: {
greeting: `你好,${'name'}!`,
cart: `购物车中有 ${'count'} 件商品`,
submit: `提交`
}
};
```
注意:这里用 ${'name'} 而不是 ${name},是为了让模板字符串本身可序列化、可静态分析,避免执行时变量污染;实际渲染时再做安全替换。
立即学习“前端免费学习笔记(深入)”;
写一个 20 行以内的 t() 函数
这个函数负责取键、插值、兜底,不处理复数、RTL 或日期格式,只干一件事:把 t('greeting', { name: 'Alice' }) 渲染成 “Hello, Alice!”
```js
let currentLang = 'en';
export function t(key, data = {}) {
const langPack = messages[currentLang] || messages.en;
let text = langPack[key] || key;
// 安全插值:只替换 ${xxx} 形式,不 eval
return text.replace(/\$\{([^}]+)\}/g, (_, prop) => {
return data[prop] !== undefined ? String(data[prop]) : '';
});
}
```
- 支持嵌套键?不用——保持扁平结构,如
form_submit而非form.submit - 缺失翻译怎么办?直接返回 key 名,方便 QA 快速定位漏翻项
- 中文引号、空格、标点已预置在语言包里,无需运行时判断 locale
在 HTML 中零配置使用
不改构建流程,不加 loader,直接在 script 标签里调用:
```html
<script type="module"><br> import { t, currentLang } from './locales.js';<br> document.getElementById('submitBtn').textContent = t('submit');<br> <br> // 切换语言只需改变量+重渲染<br> window.switchToZh = () => {<br> currentLang = 'zh';<br> document.getElementById('submitBtn').textContent = t('submit');<br> };<br></script>
```
如果用在动态内容中(比如列表),可封装一个微小的 render 函数:
```js
function renderCart(count) {
document.querySelector('.cart-text').innerHTML = t('cart', { count });
}
```
补充一点实用细节
这种方案不是银弹,但胜在可控和透明:
-
变量名即翻译键:写
t('user_name')就等于告诉所有人,“这串文字需要被翻译”,比注释更可靠 - 无运行时解析开销:没有正则反复匹配、没有 AST 构建,插值逻辑就是一次字符串 replace
- 可与任意框架共存:React/Vue 组件里照样 import 和调用,只是把它当普通工具函数用
-
RTL 支持靠 CSS:语言切换后手动加
dir="rtl"和 class 切换,不混进 t() 逻辑里


















