Skip to content

Spring MVC 中的国际化支持是如何实现的? ​

  • 标签:后端、Spring

🏛 业务架构师 ​

Spring MVC 的国际化(i18n)实现依赖三个组件协作:

  • MessageSource(ResourceBundleMessageSource/ReloadableResourceBundleMessageSource):加载多语言资源文件(messages_zh_CN.properties、messages_en_US.properties),按 code 取文案;
  • LocaleResolver:决定本次请求的语言——默认 AcceptHeaderLocaleResolver(读请求头 Accept-Language),也可换成 Cookie/Session/URL 参数策略;
  • 取值方式:服务端渲染时 #{msg.code} 标签输出;REST 场景下注入 MessageSource,按 LocaleContextHolder.getLocale() 取文案返回。

架构师视角,i18n 的难点从来不是框架用法,而是业务治理:

  1. 文案全部外置:错误提示、枚举描述、邮件/短信模板禁止硬编码——晚了再抽是全库大改造。"什么时候做 i18n"是业务判断题:有出海规划的 Day 1 就抽 key,纯国内工具可以延后,但错误码体系仍建议 key 化(顺便获得文案可运营性);
  2. 翻译是运营流程:文案变更频率高(营销措辞、法务要求),资源文件进 git 的模式改一次文案要发版——生产系统更该把文案放配置中心/DB + 缓存,运营可直接改;
  3. 格式化陷阱:日期、金额、时区、姓名顺序、单复数规则随 locale 变化,用 NumberFormat/DateFormat 体系化处理,金额多币种还要联动汇率与存储精度设计;
  4. 站点级方案:现在更多由前端 i18n 框架承担展示层国际化,后端只保证"返回可翻译的 code + 参数",这是职责分工的演进。

🏗 系统架构师 ​

机制三件套:

  • LocaleResolver:解析语言(Accept-Language 头、Cookie、session),LocaleChangeInterceptor 支持运行时切换;
  • MessageSource:按 basename 加载资源包(messages_zh_CN.properties / messages_en_US.properties),MessageFormat 带参格式化;
  • 使用:getMessage(code, args, locale),页面层用对应模板标签。

架构实践要点(做跨境电商时的经验):

  1. 文案与数据分离:界面文案走资源包;业务数据(商品名)的多语言是数据建模问题(翻译表按 locale 存维度),不要混进资源文件——两者生命周期与变更方完全不同;
  2. 语言与时区是两个维度:服务器统一 UTC 存储,展示层按用户时区转换;金额用最小单位存储加汇率换算——国际化里「格式」问题(日期/货币/数字)常比翻译更难;
  3. 语言影响缓存键:CDN/网关缓存按 locale 维度区分,否则中文用户拿到英文页;
  4. 新语言上线的漏翻检测要自动化(Key 覆盖率扫描),人工排查必漏。

💻 全栈开发专家 ​

三件套:LocaleResolver(决定语言)+ MessageSource(文案库)+ 占位符格式化。Boot 自动装配好,落地:

resources/i18n/messages_zh_CN.properties、messages_en_US.properties:

properties
order.notfound=订单不存在
java
@Autowired
private MessageSource messageSource;

public String msg(String code) {
    return messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
}

Locale 解析策略:AcceptHeaderLocaleResolver 按 Accept-Language 头(默认,API 服务首选);Session/CookieLocaleResolver 记住用户选择;配合 LocaleChangeInterceptor 提供切换接口。

踩过的坑:

  1. 中文 properties 编码:必须 UTF-8,IDEA 勾选 "Transparent native-to-ascii conversion",否则乱码
  2. 文件名与 spring.messages.basename 一致,多模块项目常因为 resources 合并丢失
  3. 业务异常国际化:抛 BizException(code, args) 只带码不带文案,出网前在全局异常处理器按当前 Locale 翻译——文案和异常解耦

现实分工:页面文案归前端 i18n(vue-i18n),后端只管业务消息、邮件、短信模板;文案集中到 Nacos 热更,比发版敏捷。