
spring boot 应用中配置了 `localeresolver` 和 `localechangeinterceptor`,也指定了 `spring.messages.basename`,但通过 `?lang=en` 切换语言无效——根本原因常在于资源文件命名不匹配、拦截器未生效、或消息源加载路径错误,而非单纯 url 参数格式问题。
要使 Spring Boot 的国际化(i18n)真正生效,需确保四个核心环节全部正确协同工作:Locale 解析器注册、语言切换拦截器启用、消息资源文件规范命名与位置、以及模板中正确使用消息表达式。以下为经过验证的完整配置指南:
✅ 1. 正确配置 LocaleResolver(推荐使用 SessionLocaleResolver)
你已实现该 Bean,但建议显式指定 setLocaleAttributeName 并确保其在 @Configuration 类中被扫描到(避免因组件扫描遗漏导致未生效):
@Configuration
public class WebConfig {
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver resolver = new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.forLanguageTag("pl")); // 推荐用 forLanguageTag 更安全
resolver.setLocaleAttributeName("session.locale"); // 显式设置属性名,便于调试
return resolver;
}
}⚠️ 注意:@Configuration 类必须被 Spring 容器加载(如主启动类位于同包或子包下,或通过 @ComponentScan 显式引入)。
✅ 2. 正确注册 LocaleChangeInterceptor(关键:必须是 @Bean + addInterceptor)
你当前在 WebMvcConfigurer 实现类中定义了 localeChangeInterceptor() 方法,但该方法未加 @Bean 注解,导致 Spring 不会将其作为 Bean 管理,addInterceptors() 中实际传入的是一个普通对象实例,无法被 Spring AOP 拦截链识别。
✅ 正确写法(推荐统一在 @Configuration 类中声明):
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang"); // 对应 ?lang=en
return interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor()).excludePathPatterns("/resources/**", "/static/**");
}
}? 提示:excludePathPatterns 可避免对静态资源重复触发拦截,提升性能。
✅ 3. 资源文件命名与位置必须严格遵循约定
- 文件必须放在 src/main/resources/ 目录下;
- 基础名(basename)由 spring.messages.basename=labels 指定,则:
- 默认语言(波兰语)→ labels.properties
- 英语 → labels_en.properties(✅ 正确)
- 英国英语 → labels_en_GB.properties(✅ 也有效,但非必需)
- ❌ 错误命名:labels_en_US.properties(若未请求 en_US 则不会匹配)、labels-en.properties(横杠非法)、Labels.properties(大小写敏感,Linux 下失败)
同时确保 application.properties 中配置无拼写错误且已生效:
# application.properties spring.messages.basename=errors-messages,labels spring.messages.encoding=UTF-8 spring.messages.cache-duration=3600
? 验证技巧:启动应用后访问 /actuator/env,搜索 spring.messages.basename,确认值已正确加载。
✅ 4. Thymeleaf 中正确引用国际化消息
在 HTML 模板中使用 #{key} 语法,而非 ${message} 或硬编码文本:
Welcome
© 2024
Welcome
✅ 5. 测试与调试步骤
- 启动应用,访问页面(如 /home),确认初始显示 labels.properties 内容(波兰语);
- 手动追加参数:/home?lang=en → 应切换为 labels_en.properties 内容;
- 若无效,开启 DEBUG 日志定位问题:
logging.level.org.springframework.web.servlet.i18n=DEBUG logging.level.org.springframework.context.support=DEBUG
日志中将输出 Locale resolved to [en] 或 No message found under code... 等关键线索。
? 总结:最易忽略的三大“静默失败”点
- 拦截器未被 Spring 管理:localeChangeInterceptor() 方法缺少 @Bean,导致 addInterceptors() 注册的是临时对象;
- 资源文件未编译进 target/classes:检查构建后 target/classes/labels_en.properties 是否存在(IDE 清理并重新构建);
- Thymeleaf 未启用国际化支持:确认 thymeleaf-extras-java8time 非必需,但 spring-boot-starter-thymeleaf 必须引入,且 TemplateEngine 默认已集成 SpringTemplateEngine。
按以上步骤逐一核对,99% 的 Spring Boot i18n 失效问题可立即解决。










