Spring Boot 国际化(i18n)失效的常见原因与完整解决方案

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

© 2025

Welcome

✅ 5. 测试与调试步骤

  1. 启动应用,访问页面(如 /home),确认初始显示 labels.properties 内容(波兰语);
  2. 手动追加参数:/home?lang=en → 应切换为 labels_en.properties 内容;
  3. 若无效,开启 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 失效问题可立即解决。