核心原则:谁生成文案,谁负责国际化。前端生成的前端翻,后端生成的后端翻,避免跨层翻译带来的维护混乱。
在项目中,除了前端 JS 配置的国际化(如 vue-i18n、react-intl 等),对于 JS 没覆盖到的文本(如后端返回的动态错误消息、数据库中的提示文案、后端接口直接返回的纯文本等),需要从后端国际化 和前端兜底策略两个层面来解决。
一、后端负责返回已国际化的文本
最常用的方案:所有需要展示给用户的文字(尤其是动态/错误消息)由后端根据请求头 Accept-Language 返回对应语言的版本。
1. 后端如何实现国际化?
- Spring Boot 示例 :使用
MessageSource+LocaleResolver
java
// 定义多语言资源文件 messages_zh_CN.properties / messages_en_US.properties
// 前端请求携带 Accept-Language: zh-CN 或 en
@RestController
public class ErrorController {
@Autowired
private MessageSource messageSource;
@GetMapping("/errorMsg")
public String getErrorMsg(HttpServletRequest request) {
Locale locale = RequestContextUtils.getLocale(request);
return messageSource.getMessage("error.login.failed", null, locale);
}
}
2. 前端如何处理后端返回的国际化文本?
-
后端直接返回已经翻译好的字符串,前端原样展示,无需再通过 JS 映射。
-
例如:
json
{
"code": 400,
"message": "用户名或密码错误" // 中文环境下直接返回中文;英文环境下返回 "Invalid username or password"
}
3. 优点/适用场景
-
错误提示、业务校验提示、动态通知等非前端硬编码的文本。
-
避免前端维护大量后端文案的映射表。
二、前端兜底策略(针对 JS 未配置的 key)
如果某些前端展示的文本没有在 JS 国际化配置文件中定义(例如遗漏的硬编码),可以设计降级逻辑:
1. 使用默认语言
javascript
// i18n 实例配置 fallbackLocale
const i18n = createI18n({
locale: 'zh-CN',
fallbackLocale: 'zh-CN', // 找不到 key 时回退到默认语言
messages: { ... }
})
2. 显示 key 本身或开发环境警告
javascript
// 自定义 t 函数
function t(key, defaultText) {
const translated = i18n.global.t(key);
if (translated === key && defaultText) return defaultText;
if (translated === key && process.env.NODE_ENV === 'development') {
console.warn(`[i18n] missing: ${key}`);
}
return translated;
}
3. 动态从后端拉取缺失的翻译
对于运行时动态出现的国际化 key(例如用户自定义的菜单名),可以设计接口:
text
GET /api/i18n/missing?keys=aaa,bbb&lang=en
返回缺失 key 的翻译,然后合并到前端语言包中。
三、数据库内容的国际化
如果数据库中存储的字段(如商品名称、文章标题)需要多语言:
方案 A:多语言字段存储
sql
CREATE TABLE product (
id INT,
name_zh VARCHAR(255),
name_en VARCHAR(255),
...
);
后端根据 Accept-Language 返回对应字段,前端直接展示。
方案 B:单独的多语言表
sql
product (id, default_name)
product_i18n (product_id, locale, name)
后端查询时 join 多语言表,返回当前语言对应的值。
四、总结:一般项目推荐实践
| 文本来源 | 国际化实现方式 |
|---|---|
| 前端静态 UI 文案(按钮、标签) | JS 配置(vue-i18n 等) |
| 后端返回的业务错误/提示 | 后端 MessageSource 翻译后直接返回 |
| 后端返回的动态内容(如用户昵称) | 避免国际化(昵称无需翻译);如需翻译则用数据库多语言表 |
| JS 配置遗漏的 key | 前端 fallback 显示默认语言或 key,配合开发期警告 |
| 第三方服务返回的文本 | 前端或后端映射为国际化文本(例如状态码 1→"成功") |
核心原则:谁生成文案,谁负责国际化。前端生成的前端翻,后端生成的后端翻,避免跨层翻译带来的维护混乱。