springboot 之 i18n国际化 (展示信息国际化)一

Spring Boot 的国际化(i18n,internationalization)机制基于 Spring Framework 的 MessageSource 接口和 LocaleResolver 组件,能够根据用户语言环境动态返回对应语言的文本。下面从原理使用示例两个维度进行详细解析。


一、核心原理

1. 核心组件

组件 作用
MessageSource 消息源接口,负责加载 .properties 国际化资源文件,并根据 key 和 Locale 返回对应语言的消息。默认实现是 ResourceBundleMessageSource
LocaleResolver 解析当前请求的区域(Locale),决定使用哪种语言。Spring Boot 默认使用 AcceptHeaderLocaleResolver,即从 HTTP 请求头 Accept-Language 中读取。
LocaleChangeInterceptor(可选) 拦截器,允许通过 URL 参数(如 ?lang=zh_CN)动态切换语言。

2. 工作流程

  1. 启动时:Spring Boot 自动配置 MessageSource,扫描 classpath:i18n/messages*.properties 文件。
  2. 请求到达时
    • LocaleResolver 从请求中(Header / Cookie / Session / Parameter)获取当前 Locale
    • 控制器调用 messageSource.getMessage(key, args, locale)
    • MessageSource 根据 basename + Locale 定位到具体 .properties 文件(如 messages_zh_CN.properties),返回对应值。
  3. 若未匹配到 Locale:回退到默认文件(如 messages.properties)或系统默认语言(可通过配置关闭)。

二、使用示例(完整步骤)

步骤 1:创建国际化资源文件

src/main/resources 下创建目录 i18n,并添加以下文件:

resources/
└── i18n/
    ├── messages.properties          # 默认(兜底)
    ├── messages_zh_CN.properties    # 简体中文
    ├── messages_zh_TW.properties    # 繁体中文
    └── messages_en_US.properties    # 英文(美国)

内容示例:

# messages.properties(默认)
greeting=Hello, {0}!
user.login=Login

# messages_zh_CN.properties
greeting=你好,{0}!
user.login=登录

# messages_en_US.properties
greeting=Hello, {0}!
user.login=Login

⚠️ 注意:.properties 文件需保存为 UTF-8 编码,并在 IDE 中启用 Transparent native-to-ascii conversion(如 IDEA 设置中勾选),避免中文乱码。


步骤 2:配置 application.yml

spring:
  messages:
    basename: classpath:i18n/messages   # 资源文件前缀(不带 .properties)
    encoding: UTF-8
    fallback-to-system-locale: false    # 禁用系统语言回退
    default-locale: zh_CN               # 默认语言
    cache-duration: 3600s               # 缓存时间(生产建议开启)

步骤 3:自定义 Locale 解析方式(支持 URL 参数切换)

默认只支持 Accept-Language Header。若想通过 ?lang=zh_CN 切换,需自定义 LocaleResolver 并注册拦截器。

// config/I18nConfig.java
package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import java.util.Locale;

@Configuration
public class I18nConfig implements WebMvcConfigurer {

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver resolver = new SessionLocaleResolver();
        resolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); // 默认简体中文
        return resolver;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang"); // 通过 ?lang=zh_CN 切换
        return interceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }
}

步骤 4:在 Controller 中使用

// controller/I18nController.java
@RestController
public class I18nController {

    @Autowired
    private MessageSource messageSource;

    @GetMapping("/hello")
    public String hello(@RequestParam String name) {
        // 获取当前 Locale(由 LocaleResolver 设置)
        Locale locale = LocaleContextHolder.getLocale();
        // 获取国际化消息,支持参数占位符 {0}, {1}...
        return messageSource.getMessage("greeting", new Object[]{name}, locale);
    }

    @GetMapping("/login-text")
    public String loginText() {
        return messageSource.getMessage("user.login", null, LocaleContextHolder.getLocale());
    }
}

步骤 5:测试

  1. 默认语言(zh_CN)

    GET /hello?name=张三
    # 返回:你好,张三!
    
  2. 切换为英文

    GET /hello?name=Tom&lang=en_US
    # 返回:Hello, Tom!
    
  3. 切换为繁体中文

    GET /login-text?lang=zh_TW
    # 返回:登錄
    

三、高级用法

1. 支持数据库动态国际化(运行时修改)

  • 实现自定义 MessageSource,从数据库加载键值对。
  • 配合缓存(如 Caffeine/Redis)提升性能。

2. 校验注解国际化

@NotBlank(message = "{validate.required.name}")
private String name;

配合 ValidationMessages.properties 实现校验提示多语言。

3. 前端集成(前后端分离)

  • 后端提供 /api/i18n/{lang} 接口返回 JSON 格式的语言包。
  • 前端(Vue/React)根据用户选择加载对应语言包。

四、常见问题

问题 解决方案
中文乱码 确保 .properties 文件为 UTF-8 编码,并开启 IDE 的 ASCII 转换选项
语言不切换 检查是否注册了 LocaleChangeInterceptor,且参数名匹配(如 lang
找不到资源文件 检查 basename 路径是否正确(classpath:i18n/messages 对应 resources/i18n/messages_xx.properties
生产环境缓存失效 设置 spring.messages.cache-duration,避免频繁读取文件

总结

Spring Boot 国际化 = 资源文件 + MessageSource + LocaleResolver
通过简单配置即可支持多语言,结合 LocaleChangeInterceptor 实现灵活的语言切换,适用于单体应用或前后端分离架构。对于复杂场景(如动态语言包),可扩展 MessageSource 实现数据库驱动的国际化方案。

posted @ 2026-01-21 10:54  蓝迷梦  阅读(57)  评论(0)    收藏  举报