文章目录

  • 目的
  • 怎么做到的
  • 依赖
  • 自动装配
  • 18n配置文件
  • messages.properties
  • messages_us_US.properties
  • messages_zh_CN.properties
  • index.html
  • 控制器接口
  • application.properties配置
  • 启动程序
  • 为什么
  • LocaleResolve国际化解析器
  • MessageSource国际化消息源
  • 主要参数配置
  • 结尾

前段时间我们跟韩国的客户谈一个项目,自然而然的就遇到了国际化的问题,所以针对国际化的学习,记录一下便于后期使用。

目的

假如我有一个网站,默认是中文的,如下图所示:

【SpringMVC】面向全球的用户,我们该怎么办_i18n


点击English网站语言切换成英文的,如下所示:

【SpringMVC】面向全球的用户,我们该怎么办_spring_02

怎么做到的

细心的网友可能通过上边的图片能发现点细节。就是路径后边带着lang参数。没错我这个示例就是通过这个参数控制的。我们一步步解刨下怎么实现的。
新建一个简单的web工程,使用springboot初始化功能就行。

依赖

<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>

自动装配

package com.example.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()
    {
        // 指定Session解析器
        SessionLocaleResolver slr = new SessionLocaleResolver();
        // 默认中文语言
        slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return slr;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor()
    {
        // 拦截请求参数,确定其国际化参数
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        // 参数名,根据lang进行切换国际化解析器
        lci.setParamName("lang");
        return lci;
    }

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

18n配置文件

messages.properties

#表单
login.email=email
login.pwd=password
login.btn=login

messages_us_US.properties

#表单
login.email=email
login.pwd=password
login.btn=login

messages_zh_CN.properties

#表单
login.email=邮箱
login.pwd=密码
login.btn=登录

index.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form>
    <a href="./index?lang=zh_CN">中文</a>
    <a href="./index?lang=us_US">English</a>
    <br>
    <br>
    <span th:text="#{login.email}"></span>
    <input type="text" name="email">
    <span th:text="#{login.pwd}"></span>
    <input type="password" name="pwd">
    <input type="button" th:value="#{login.btn}">
</form>
</body>
</html>

控制器接口

package com.example.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Locale;

@Controller
public class IndexController {

    @Autowired
    private MessageSource messageSource;

    @GetMapping("/index")
    public String index(){

        // 演示后台怎么获取
        Locale locale = LocaleContextHolder.getLocale();
        String email = messageSource.getMessage("login.email", null, locale);
        String pwd = messageSource.getMessage("login.pwd", null, locale);
        return "index";
    }
}

application.properties配置

server.port=8080
server.servlet.context-path=/i18n
# 国际化文件名,最后的messages是指的文件名不是目录,否则会报错
spring.messages.basename=static/i18n/messages

启动程序

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringI18nApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringI18nApplication.class, args);
    }

}

启动后,使用浏览器访问就是开头的界面了,做起来很简单。

为什么

见其外还得见其内,强大的SpringMVC是怎么做到的呢?
首先我们在\org\springframework\web\servlet\DispatcherServlet.properties文件中可以看到,默认的国际化配置LocaleResolver为AcceptHeaderLocaleResolver。

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

LocaleResolve国际化解析器

LocaleResolver用来确定用户的国际化区域,其具体实现如下:

【SpringMVC】面向全球的用户,我们该怎么办_国际化_03

MessageSource国际化消息源

除了国际化解析器的以外,国际化还牵扯到一个MessageSource接口,用来装载国际化消息。
主要配置如下:

【SpringMVC】面向全球的用户,我们该怎么办_spring_04

主要参数配置

public class MessageSourceProperties {

	/**
	 * 国际化文件名称,默认是messages在resources路径下
	 * 可以配置全路径
	 */
	private String basename = "messages";

	/**
	 * 配置文件的编码格式
	 */
	private Charset encoding = StandardCharsets.UTF_8;

	/**
	 * 消息的缓存时间,默认永久有效
	 */
	@DurationUnit(ChronoUnit.SECONDS)
	private Duration cacheDuration;

	/**
	 * 查找区域配置文件的选项
	 * 如果禁用此选项,那么查找不到配置文件只能退到默认的配置文件
	 */
	private boolean fallbackToSystemLocale = true;

	/**
	 * 是否始终应用MessageFormat规则,甚至在没有参数的情况下解析消息
	 */
	private boolean alwaysUseMessageFormat = false;

	/**
	 * 是否采用消息代码替代抛出的NoSuchMessageException异常信息,
	 * 推荐在开发期间使用
	 */
	private boolean useCodeAsDefaultMessage = false;
    ......

}

结尾

以后的国际化项目是不是都可以搞定了<_>。

源码分享