目录
信息国际化概述
1、国际化主要用于应用跨国时使用,比如在中国时应用为中文,在韩国时,应用显示为韩文,在日本时,应用又显示为日文等,应用跟着系统语言环境自动切换。又或者是用户点击什么语言就可以自动切换什么语言。
准备国际化文件
1、编写国际化配置文件,抽取页面需要显示的国际化消息
2、在类路径下新建一个目录“i18n”(目录名字随意),然后在“i18n”目录下新建 “index.properties”、“index_en_US.properties”、“index_zh_CN.properties” 三个属性文件(名称强制可以与页面名称一致)。
xxx.properties | 存放默认的语言 |
xxx_en_US.properties | 存放英文,en表示语言(英文)缩写,US表示国家(美国)缩写,请按规范格式写即可 |
xxx_zh_CN.properties | 存放中文,zh表示语言(中文)缩写,CN表示国家(中国)缩写,请按规范格式写即可 |
3、当然还可以写更多的语言文件,当它们的命名符合规范时,IDEA 会自动将它们绑定到一起,这样在后面输入值的时候会很方便.
4、为了防止 *. properties 资源文件中文乱码,IDEA设置:
打开:Settings->Editor->File Encodings,"Default encoding for properties files" 设置为 UTF-8,勾选后面的 "Transparent native-to-asci conversion"
https://gitee.com/wangmx1993/thymeleafapp/blob/master/src/main/resources/i18n
Spring Boot 国际化自动配置原理
1、Spring Boot 现在自动配置好了管理国际化资源文件的组件 MessageSourceAutoConfiguration,底层仍然使用的是 ResourceBundleMessageSource。
2、页面使用 fmt:message 获取国际化内容,本文使用 Thymeleaf 模板引擎,所以会用 Thymeleaf 进行取值。
package org.springframework.boot.autoconfigure.context;
@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;
}
......
3、如上所示在它的 MessageSourceProperties 可以看到可以配置的属性,同理可以直接在官网进行查看,可以在全局配置文件中覆盖其默认配置,官方文档查看:Spring Boot Reference Guide.
# 国际化(MessageSourceProperties)
spring.messages.always-use-message-format=false # 是否始终应用MessageFormat规则,甚至解析没有参数的消息
spring.messages.basename=messages # 以逗号分隔的基名列表(基本上是一个完全限定的类路径位置),每个基名都遵循ResourceBundle约定,并放松了对基于斜杠的位置的支持。
spring.messages.cache-duration= #加载的资源包文件缓存持续时间。未设置时,捆绑包将永久缓存。如果未指定持续时间后缀,将使用秒。
spring.messages.encoding=UTF-8 # 消息包编码
spring.messages.fallback-to-system-locale=true # 如果找不到特定区域设置的文件,是否返回到系统区域设置。
spring.messages.use-code-as-default-message=false # 是否将消息代码用作默认消息,而不是引发“NoSuchMessageException”。仅在开发期间推荐。
4、如上所示,spring.messages.basename=messages,就是配置国际化资源文件的基本名路径,默认是“message”,意思是如果没有在全局配置文件中覆盖此配置项的话,它默认会扫描类路径下的“messages.properties”、"messages_en_US.properties"、"messages_zh_CN.properties"等格式的文件作为国际化文件。
5、因为应用会有多个页面,以及其它形式的国际化设置,就会有多套资源文件,这时在 application.yml 文件中覆盖配置,spring.messages.basename 的值用逗号分隔即可。
spring:
#国际化消息配置,多个时用逗号隔开.
messages:
basename: i18n.login,i18n.index
src/main/resources/application.yml · 汪少棠/thymeleafapp - Gitee.com
前端页面获取国际化值
1、因为本文使用的是 Thymeleaf 模板引擎,所以页面上直接使用 Thymeleaf 的方式获取国际化文件的值即可,对于 Thymeleaf 不熟悉的,可以参考《Thymeleaf 简介及入门》
2、th:text="#{xxx}":获取国际化文件中 xxx 的属性值,然后替换标签原来的文本默认值。
3、th:placeholder="#{xxx}":获取国际化文件中 xxx 的属性值,然后替换标签 placeholder 属性原来的默认值,同理可以替换任意属性的默认值。
4、[[#{login_remember}]]:对于 <input xxx />这种自封闭标签得用 Thymeleaf的行内表达式取值。
示例1:<title th:text="#{login_title}">银河系大数据平台</title>
示例2:<div class="message">[[#{login_title}]]</div>
src/main/resources/templates/login.html · 汪少棠/thymeleafapp - Gitee.com
5、下面进行测试,根据浏览器语言设置的信息切换了国际化。
指定语言切换
1、上面是应用根据跟随浏览器语音自动进行语音切换,现在需要改成用户“点击中文”则切换中文,“点击英文”则切换英文。
2、原理是需要使用到 “国际化Locale(区域信息对象)”与 “ LocaleResolver(获取区域信息对象)”两个API
3、应用国际化默认之所以能随着浏览器的语言变化而变化,是因为浏览器Http请求时,会在请求头中携带语言信息,这是后台国际化变换的依据。
4、第一部分中的 “自动语言切换” 之所以能用,是因为在 WebMvcAutoConfiguration 配置类中自动配置好了一个 区域信息解析器组件,如下所示逻辑是如果用户没有自己提供 区域信息解析器 “LocaleResolver”,那么它默认会使用一个叫 “AcceptHeaderLocaleResolver” 进行解析。
5、所以我们只需要自己提供一个 “LocaleResolver” 组件覆盖默认的即可
package org.springframework.boot.autoconfigure.web.servlet;
.....
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
......
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
.......
}
页面修改
1、修改一下首页的“中文”、“英文”按钮,使用 Thymeleaf 的 @{xxx} 取值是会默认带上应用上下文。
2、@{/} 的效果类似 http://localhost:8080/tiger/,其中 titer 是应用名称。
3、@{/(l=zh_CN)} 相当于 @{/?zh_CN},只是 Thymeleaf 不再使用 "?" 的方式为get请求路径带参数,而是使用"()"的方式。
<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_button}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm" th:href="@{/(l=zh_CN)}">中文</a>
<a class="btn btn-sm" th:href="@{/(l=en_US)}">English</a>
</form>
</body>
</html>
页面上点击“中文”后,会跳转:http://localhost:8080/tiger/?l=zh_CN
页面上点击“英文”后,会跳转:http://localhost:8080/tiger/?l=en_US
自定义区域信息解析器
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* Created by Administrator on 2018/7/28 0028.
* 自定义区域信息解析器
*/
public class MyLocaleResolve implements LocaleResolver {
/**
* 解析http请求中地址中的标识,然后设置对应的区域信息值
*
* @param httpServletRequest
* @return
*/
@Override
public Locale resolveLocale(HttpServletRequest request) {
/**
* 如果请求地址中含有l参数,如 http://localhost:8080/tiger/?l=en_US,则设置新的区域对象
* 否则使用默认的区域对象,默认的区域对象不会使国际化再随着浏览器语言的变化而变化的
*/
Locale locale = Locale.getDefault();
String l = request.getParameter("l");
if (!StringUtils.isEmpty(l) && l.split("_").length >= 2) {
String[] ls = l.split("_");
locale = new Locale(ls[0], ls[1]);
}
return locale;
}
/**
* 设置区域信息,一般不做处理
*
* @param httpServletRequest
* @param httpServletResponse
* @param locale
*/
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
import com.lct.component.MyLocaleResolve;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
/**
* Created by Administrator on 2018/7/28 0028.
* 自定义配置类
*/
@Configuration
public class MyMvcConfig {
/**
* 将我们自己的 LocaleResolver 组件交于 Spring 容器管理
* 从而覆盖 Spring Boot默认的区域信息解析器
*
* @return
*/
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolve();
}
}
运行测试
1、和预期的完全一致,因为请求路径中携带了"L"参数,所以不管浏览器 语言 选择的是什么,都不会影响。
2、当请求地址中不带 “L” 参数时,此时后台使用的是默认的 Locale,此时即使浏览器切换了语言,同样国际化也不会生效的。