一、国际化基本原理
在Spring程序中,国际化主要是通过ResourceBundleMessageSource
这个类来实现的,那么下面我们分析一下Spring Boot是如何实现国际化支持的。
Spring Boot通过MessageSourceAutoConfiguration
是为我们自动配置好了管理国际化资源文件的组件的:org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
@Bean
public MessageSource messageSource() {
MessageSourceProperties properties = messageSourceProperties();
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
了解messageSource()这个方法。
MessageSourceProperties properties = messageSourceProperties();
方法中首先声明了MessageSourceProperties这个对象,看一下这个对象包含了什么:
public class MessageSourceProperties {
/**
* Comma-separated list of basenames (essentially a fully-qualified classpath
* location), each following the ResourceBundle convention with relaxed support for
* slash based locations. If it doesn't contain a package qualifier (such as
* "org.mypackage"), it will be resolved from the classpath root.
*/
private String basename = "messages";
/**
* Message bundles encoding.
*/
private Charset encoding = StandardCharsets.UTF_8;
类中声明了一个属性basename,默认值为messages。看其介绍,这是一个以逗号分隔的基本名称列表,如果它不包含包限定符(例如“org.mypackage”),它将从类的根路径解析。它的意思是如果你不在配置文件中指定以逗号分隔开的国际化资源文件名称的话,它默认会去类路径下找messages.properties作为国际化资源文件的基本文件。若是你的国际化资源文件是在类路径某个包(如:i18n)下的话,你就需要在配置文件中指定基本名称了。
#在配置文件中配置basename为i18n.login
spring.messages.basename=i18n.login
其中i18n是存放资源的文件夹名,login是资源文件的基本名称。
上面说了国际化支持主要是通过ResourceBundleMessageSource实现的,这里对它做出实例化操作。
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
}
这里可以看到基本名称的设置了,若是没有在配置文件中设置的话,它默认就是messages
了
二、资源文件的国际化操作
1.准备国际资源文件
2.在配置文件中加入资源文件的basename
spring.messages.basename=i18n.login
其中i18n是存放资源的文件夹名,login是资源文件的基本名称。
3.新建一个login.html登录页面,其中包含了thymeleaf模板引擎的 #{ } 国际化指定语法
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" src="asserts/img/bootstrap-solid.svg" th:src="@{/asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> [[#{login.remember}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2018-2019</p>
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>
</form>
</body>
</html>
4.在@Configuration标注的重写配置文件中配置请求映射
@Configuration
public class MyMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("login.html").setViewName("login");
}
}
5.实现点击按钮更改语言的操作
在login.html页面的a标签中,添加一个请求参数l,将对应的zh_CN或者en_US放入request域中
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>
然后在后台自己写一个国际化解析方法
@Configuration
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String l = httpServletRequest.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] split =l.split("_");
locale = new Locale(split[0],split[1]);
System.out.println("++++++++++++++"+locale);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
6.将该方法加入容器中
写完后还不能生效,要将该方法加入容器中(在自定义的springboot配置文件中加入)
@Configuration
public class MyMvcConfig extends WebMvcConfigurationSupport {
//此处方法返回值和方法名都不能改动,因为是要跟源码中的实现方法一致
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
然后就可实现点击就能切换语言。一定要细心,和思路要清晰。