前段时间我们跟韩国的客户谈一个项目,自然而然的就遇到了国际化的问题,所以针对国际化的学习,记录一下便于后期使用。
假如我有一个网站,默认是中文的,如下图所示:
点击English网站语言切换成英文的,如下所示:
细心的网友可能通过上边的图片能发现点细节。就是路径后边带着lang参数。没错我这个示例就是通过这个参数控制的。我们一步步解刨下怎么实现的。
新建一个简单的web工程,使用springboot初始化功能就行。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
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());
}
}
#表单
login.email=email
login.pwd=password
login.btn=login
#表单
login.email=email
login.pwd=password
login.btn=login
#表单
login.email=邮箱
login.pwd=密码
login.btn=登录
DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form>
<a href="./index?lang=zh_CN">中文a>
<a href="./index?lang=us_US">Englisha>
<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";
}
}
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
LocaleResolver用来确定用户的国际化区域,其具体实现如下:
除了国际化解析器的以外,国际化还牵扯到一个MessageSource接口,用来装载国际化消息。
主要配置如下:
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;
......
}
以后的国际化项目是不是都可以搞定了<_>。