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 的难点从来不是框架用法,而是业务治理:
- 文案全部外置:错误提示、枚举描述、邮件/短信模板禁止硬编码——晚了再抽是全库大改造。"什么时候做 i18n"是业务判断题:有出海规划的 Day 1 就抽 key,纯国内工具可以延后,但错误码体系仍建议 key 化(顺便获得文案可运营性);
- 翻译是运营流程:文案变更频率高(营销措辞、法务要求),资源文件进 git 的模式改一次文案要发版——生产系统更该把文案放配置中心/DB + 缓存,运营可直接改;
- 格式化陷阱:日期、金额、时区、姓名顺序、单复数规则随 locale 变化,用
NumberFormat/DateFormat体系化处理,金额多币种还要联动汇率与存储精度设计; - 站点级方案:现在更多由前端 i18n 框架承担展示层国际化,后端只保证"返回可翻译的 code + 参数",这是职责分工的演进。
🏗 系统架构师
机制三件套:
- LocaleResolver:解析语言(Accept-Language 头、Cookie、session),LocaleChangeInterceptor 支持运行时切换;
- MessageSource:按 basename 加载资源包(messages_zh_CN.properties / messages_en_US.properties),MessageFormat 带参格式化;
- 使用:
getMessage(code, args, locale),页面层用对应模板标签。
架构实践要点(做跨境电商时的经验):
- 文案与数据分离:界面文案走资源包;业务数据(商品名)的多语言是数据建模问题(翻译表按 locale 存维度),不要混进资源文件——两者生命周期与变更方完全不同;
- 语言与时区是两个维度:服务器统一 UTC 存储,展示层按用户时区转换;金额用最小单位存储加汇率换算——国际化里「格式」问题(日期/货币/数字)常比翻译更难;
- 语言影响缓存键:CDN/网关缓存按 locale 维度区分,否则中文用户拿到英文页;
- 新语言上线的漏翻检测要自动化(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 提供切换接口。
踩过的坑:
- 中文 properties 编码:必须 UTF-8,IDEA 勾选 "Transparent native-to-ascii conversion",否则乱码
- 文件名与
spring.messages.basename一致,多模块项目常因为 resources 合并丢失 - 业务异常国际化:抛
BizException(code, args)只带码不带文案,出网前在全局异常处理器按当前 Locale 翻译——文案和异常解耦
现实分工:页面文案归前端 i18n(vue-i18n),后端只管业务消息、邮件、短信模板;文案集中到 Nacos 热更,比发版敏捷。