SpringBoot集成国际化实现多种语言切换的完整案例(中/英/日)

 更新时间:2026年07月12日 08:44:46   作者:SimonKing  
国际化从入行之初了解过以后,再也没有碰到过应用场景。近期,公司扩展国际业务,网站需要支持多语言切换,刚好可以试一试Spring框架的国际化I18N。

01 引言

国际化从入行之初了解过以后,再也没有碰到过应用场景。近期,公司扩展国际业务,网站需要支持多语言切换,刚好可以试一试Spring框架的国际化I18N

02 整体的设计

基于Spring Boot 3.5.16 + Thymeleaf + Java 17的技术架构,实现多语言国际化(I18N)。

  • 后端: 通过 MessageSource + LocaleResolver 实现消息的国际化,支持在 Controller/Service/工具类中按当前语言获取消息
  • 前端: 通过 Thymeleaf 模板引擎的 #{...} 表达式,在页面中直接渲染多语言文本
  • 切换方式: 通过 URL 参数 ?lang=zh_CN 切换语言,语言偏好保存在 Session 中

当前支持语言

语言标签语言地区资源文件
zh_CN简体中文中国messages_zh_CN.properties
en_USEnglishUnited Statesmessages_en_US.properties
ja_JP日本語日本messages_ja_JP.properties

03 项目搭建

3.1 依赖引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2 配置

/**
 * I18N 国际化配置
 * <p>
 * 自动根据 {@link SupportedLocale} 枚举构建 LocaleResolver,
 * 添加新语言时无需修改本类。
 */
@Slf4j
@Configuration
public class I18nConfig implements WebMvcConfigurer {

    @Value("${app.i18n.default-locale:zh_CN}")
    private String defaultLocaleTag;

    @Value("${app.i18n.param-name:lang}")
    private String paramName;

    /**
     * Session 存储用户选择的语言
     */
    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver resolver = new SessionLocaleResolver();
        resolver.setDefaultLocale(SupportedLocale.fromLanguageTag(defaultLocaleTag).toLocale());
        log.info("I18N initialized: default-locale={}, supported-locales={}",
                defaultLocaleTag, SupportedLocale.values().length);
        return resolver;
    }

    /**
     * URL 参数切换语言: ?lang=zh_CN / ?lang=en_US / ?lang=ja_JP
     */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName(paramName);
        return interceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor())
                .addPathPatterns("/**");
    }
}

这里要说明的是:我们一定要配置LocaleResolver

LocaleResolver这个是国际化解析的关键类,可以设置默认的地区。可以使用框架自带的解析器,也可以自定义。

LocaleChangeInterceptor拦截器不是必须的,全局使用可以配置拦截器。框架自带LocaleChangeInterceptor我们可以使用,通过参数修改地区的信息。这里的参数默认使用lang

有了拦截器,拦截的配置也必须有,用来拦截需要的国际化的请求。

下面是自定义的国际化参数配置:

# 国际化自定义配置
app:
  i18n:
    # 默认语言
    default-locale: zh_CN
    # 语言参数名(URL参数 ?lang=xxx)
    param-name: lang

3.3 定义语言配置文件

我们将语言文件定义到resources下面的i18n下。

messages.properities是默认配置,其他messages_XX.properities属于语言配置文件。

配置国际化参数:

spring:
  application:
    name: boot-i18n
  # 国际化配置
  messages:
    # 指定语言文件的目录
    basename: i18n/messages
    encoding: UTF-8
    # 设为 false 可避免找不到资源时回退到操作系统语言
    fallback-to-system-locale: false
    # 找不到消息 key 时返回 key 本身而非抛异常
    use-code-as-default-message: true

语言文件合集:

# ==========================================
# messages_zh_CN.properities:中文-中国 国际化资源
# ==========================================
app.name=国际化示例应用
app.description=基于Spring Boot的多语言国际化方案
# 通用
common.success=操作成功
common.fail=操作失败
common.not_found=资源不存在
# 用户模块
user.welcome=欢迎您,{0}!
user.login.success=登录成功
user.login.fail=登录失败,账号或密码错误
# 区别其他文件的特殊配置,验证use-code-as-default-message=true的配置
test.ws=i18n
# ==========================================
# messages_en_US.properities:English (United States) i18n resources
# ==========================================
app.name=I18N Demo Application
app.description=Multi-language internationalization solution based on Spring Boot
# Common
common.success=Operation successful
common.fail=Operation failed
common.not_found=Resource not found
# User Module
user.welcome=Welcome, {0}!
user.login.success=Login successful
user.login.fail=Login failed, incorrect username or password
# ==========================================
# messages_ja_JP.properities:日本語 (日本) 国際化リソース
# ==========================================
app.name=国際化デモアプリケーション
app.description=Spring Bootに基づく多言語国際化ソリューション
# 共通
common.success=操作が成功しました
common.fail=操作が失敗しました
common.not_found=リソースが見つかりません
# ユーザーモジュール
user.welcome=ようこそ、{0}!
user.login.success=ログイン成功
user.login.fail=ログイン失敗、アカウントまたはパスワードが間違っています

3.4 页面以及服务

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="#{app.name}">国际化示例应用</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
               background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
               min-height: 100vh; display: flex; align-items: center; justify-content: center; }
        .card { background: #fff; border-radius: 16px; padding: 40px; box-shadow: 0 20px 60px rgba(0,0,0,0.3);
                max-width: 520px; width: 90%; }
        h1 { color: #333; margin-bottom: 8px; font-size: 24px; }
        .desc { color: #666; margin-bottom: 24px; }
        .section { margin-bottom: 20px; }
        .section h3 { color: #764ba2; margin-bottom: 8px; font-size: 16px; border-bottom: 2px solid #eee;
                      padding-bottom: 4px; }
        .lang-switch { display: flex; gap: 10px; margin-bottom: 24px; flex-wrap: wrap; }
        .lang-switch a { text-decoration: none; padding: 8px 20px; border-radius: 8px;
                         font-size: 14px; transition: all 0.2s; border: 2px solid #ddd; color: #555; }
        .lang-switch a:hover { border-color: #667eea; color: #667eea; }
        .lang-switch a.active { background: #667eea; color: #fff; border-color: #667eea; }
        .msg { background: #f5f7fa; border-radius: 8px; padding: 12px 16px; margin: 6px 0;
               font-size: 14px; color: #333; }
    </style>
</head>
<body>
<div class="card">
    <h1 th:text="#{app.name}">国际化示例应用</h1>
    <p class="desc" th:text="#{app.description}">描述</p>
    <!-- 语言切换 -->
    <div class="lang-switch">
        <a th:classappend="${#locale.language == 'zh'} ? 'active'"
           th:href="@{/(lang='zh_CN')}" rel="external nofollow" >🇨🇳 简体中文</a>
        <a th:classappend="${#locale.language == 'en'} ? 'active'"
           th:href="@{/(lang='en_US')}" rel="external nofollow" >🇺🇸 English</a>
        <a th:classappend="${#locale.language == 'ja'} ? 'active'"
           th:href="@{/(lang='ja_JP')}" rel="external nofollow" >🇯🇵 日本語</a>
    </div>
    <!-- 通用消息 -->
    <div class="section">
        <h3 th:text="|${#messages.msg('lang.current', #locale)}|">当前语言</h3>
        <div class="msg" th:text="#{common.success}">操作成功</div>
        <div class="msg" th:text="#{common.fail}">操作失败</div>
        <div class="msg" th:text="#{common.not_found}">资源不存在</div>
    </div>
    <!-- 用户消息 -->
    <div class="section">
        <h3>用户模块演示</h3>
        <div class="msg" th:text="#{user.welcome('Jack')}">欢迎您</div>
        <div class="msg" th:text="#{user.login.success}">登录成功</div>
        <div class="msg" th:text="#{user.login.fail}">登录失败</div>
    </div>
</div>
</body>
</html>

页面的调用需要注意。通过#{}获取语言文件的参数,通过${}服务参数。

服务就比较简单了,直接找打页面即可。

@Controller
public class PageController {

    @GetMapping("/")
    public String index() {
        return "index";
    }
}

3.5 测试

访问:http://localhost:8080/

对比图切换之后,会发现use-code-as-default-message=true参数是有效的,没有配置的Key,默认显示Key。

04 扩展

上面介绍了三种语言,如果还要增加起亚语言,着急有需要增加枚举的类型和语言文件即可。枚举上面的案例没有说明,这里补充一下:

我们已增加韩语为例.

4.1 增加条目

// SupportedLocale.java
public enum SupportedLocale {
    ZH_CN("zh", "CN", "简体中文"),
    EN_US("en", "US", "English"),
    JA_JP("ja", "JP", "日本語"),
    // 新增韩语
    KO_KR("ko", "KR", "한국어");
    // ...
}

4.2 创建语言文件

src/main/resources/i18n/ 下创建 messages_ko_KR.properties

# 한국어 (대한민국) 국제화 리소스
app.name=국제화 데모 애플리케이션
app.description=Spring Boot 기반 다국어 국제화 솔루션
common.success=작업 성공
common.fail=작업 실패
common.not_found=리소스를 찾을 수 없습니다
user.welcome=환영합니다, {0}!
user.login.success=로그인 성공
user.login.fail=로그인 실패, 계정 또는 비밀번호가 잘못되었습니다

参数只要传递lang=ko_KR即可。

以上就是SpringBoot集成国际化实现多种语言切换的完整案例(中/英/日)的详细内容,更多关于SpringBoot国际化多种语言切换的资料请关注脚本之家其它相关文章!

相关文章

  • Java面试题冲刺第二十一天--JVM

    Java面试题冲刺第二十一天--JVM

    这篇文章主要为大家分享了最有价值的三道关于JVM的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • java计算任意位水仙花数示例(回文数)

    java计算任意位水仙花数示例(回文数)

    这篇文章主要介绍了java计算任意位水仙花数示例(回文数),需要的朋友可以参考下
    2014-05-05
  • spring-logback引用外部文件实现方式

    spring-logback引用外部文件实现方式

    本文介绍了如何在Spring微服务开发中实现统一的日志配置,包括使用logback的继承方式和spring-logback.xml配置,以及如何解决logback-include.xml文件在jar包中的位置问题,通过这种方式,可以在统一的日志格式和存储方式下,给予服务一定程度的自主控制
    2025-11-11
  • Idea运行单个main方法,不编译整个工程的问题

    Idea运行单个main方法,不编译整个工程的问题

    这篇文章主要介绍了Idea运行单个main方法,不编译整个工程的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • 基于Java实现Word转EPUB的实现方案详解

    基于Java实现Word转EPUB的实现方案详解

    EPUB作为一种开放标准的电子书格式,已成为数字出版领域的主流选择,本文将介绍一种基于 Java 的实现方案,供有类似需求的朋友参考,希望对大家有所帮助
    2026-04-04
  • Java调用C#动态库的三种方法详解

    Java调用C#动态库的三种方法详解

    在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们就来探讨一下Java调用C#动态库的三种方法,需要的朋友可以参考下
    2025-06-06
  • mybatisPlus返回Map类型的集合

    mybatisPlus返回Map类型的集合

    本文主要介绍了mybatisPlus返回Map类型的集合,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Java线程池的分析和使用详解

    Java线程池的分析和使用详解

    本篇文章主要介绍了Java线程池的分析和使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • SpringBoot多环境配置踩坑指南

    SpringBoot多环境配置踩坑指南

    这篇文章主要为大家详细介绍了SpringBoot多环境配置的相关方法和避坑指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2026-03-03
  • SpringMVC请求的路径变量里面写正则表达式的方法

    SpringMVC请求的路径变量里面写正则表达式的方法

    这篇文章主要介绍了SpringMVC请求的路径变量里面写正则表达式的相关知识,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09

最新评论