国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发这样的程序的过程,就称为国际化。
那么当我们使用Spring Boot如何进行国际化呢?那么当你读完这篇文章你会学到如下知识:
(1) spring boot 加入thymeleaf;
(2) 页面元素国际化;
(3) spring boot默认国际化原理说明;
(4) firefox浏览器修改区域语言;
(5)chrome浏览器修改区域语言;
(6)修改默认messages配置前缀;
(7) 代码中如何获取国际化信息;
(8) 优化代码获取国际化信息;
(9) 区域解析器之AcceptHeaderLocaleResolver;
(10) 会话区域解析器之SessionLocaleResolver;
(11) Cookie区域解析器之CookieLocaleResolver;
(12)固定的区域解析器之FixedLocaleResolver ;
(13)使用参数修改用户的区域;
接下里我们看看这些具体应该怎么操作。
(1) spring boot 加入thymeleaf;
Spring boot集成thymeleaf在
(18)使用模板(thymeleaf-freemarker)【从零开始学Spring Boot】
这篇文章有介绍过,所以这里就不过多进行介绍了。在这里我们为之后的讲解做点基本准备。
模板文件resources/templates/hello.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>hello spring boot</title>
</head>
<body>
<p>欢迎你登录到阿里巴巴网站</p>
</body>
</html>
这里没有特殊的代码,访问就是显示一些文字,这里还没加入国际化的相关东西,之后添加。
编写访问地址:com.kfit.controller.HelloController:
package com.kfit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclass HelloController {
@RequestMapping("/hello")
public String hello(){
return"/hello";
}
}
这里就是访问http://127.0.0.1:8080/hello就跳转到hell.html进行访问。
到这里准备工作就好了。
(2) 页面元素国际化;
我们观察hello.html里面的信息直接就是中文显示,所以我们现在的需求是当访问语言是zh的时候显示为中文,当语言为en的时候显示为英文,那么怎么操作呢?
首先我们先定义国际化资源文件,spring boot默认就支持国际化的,而且不需要你过多的做什么配置,只需要在resources/下定义国际化配置文件即可,注意名称必须以messages开发。
我们定义如下几个文件:
messages.properties (默认,当找不到语言的配置的时候,使用该文件进行展示)。
messages_zh_CN.properties(中文)
messages_en_US.properties(英文)
具体的代码如下:
messages.properties:
welcome = 欢迎你登录到 阿里巴巴 网站(default)
messages_zh_CN.properties:
welcome = \u6b22\u8fce\u4f60\u767b\u5f55\u5230 \u963f\u91cc\u5df4\u5df4 \u7f51\u7ad9\uff08\u4e2d\u6587\uff09
对应的信息是:
welcome = 欢迎你登录到 阿里巴巴 网站(中文)
messages_en_US.properties:
welcome = welcome to login to alibaba website(English)
配置信息就这么简单,那么在前端展示怎么修改呢,修改hello.html文件,使用#{key}的方式进行使用messages中的字段信息:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>hello spring boot</title>
</head>
<body>
<p><label th:text="#{welcome}"></label></p>
</body>
</html>
重新访问:http://127.0.0.1:8080/hello 应该显示:
欢迎你登录到 阿里巴巴 网站(中文)
(3) spring boot默认国际化原理说明
在这里我们先打住下,简单说下原理:
第一个问题,为什么命名必须是messages开头,需要看一个源码文件:
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" alt="Open Declaration" style='width:12pt;height:12pt' o:button="t"> <v:imagedata src="file:///C:\Users\ADMINI~1.ANG\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png" o:href="file:///D:\Workspaces\workspace_eclipse_mars_64\.metadata\.plugins\org.eclipse.jdt.ui\jdt-images\0.png"/> </v:shape><![endif]--><!--[if !vml]--><!--[endif]-->org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration:
这里提取部分代码:
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Eddú Meléndez
*/
@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
/**
* Comma-separated list of basenames, each following the ResourceBundle convention.
* Essentially a fully-qualified classpath location. 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 = Charset.forName("UTF-8");
/**
* Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles
* are cached forever.
*/
private int cacheSeconds = -1;
/**
* Set whether to fall back to the system Locale if no files for a specific Locale
* have been found. if this is turned off, the only fallback will be the default file
* (e.g. "messages.properties" for basename "messages").
*/
privatebooleanfallbackToSystemLocale = true;
看到没有,如果我们没有在application.properties中配置spring.messages属性,那么使用默认的messages,好了这个问题就这么简单解决了。
第二问题:为什么我看到的是中文(或者英文)呢?
为了让web应用程序支持国际化,必须识别每个用户的首选区域,并根据这个区域显示内容。在Spring MVC应用程序中,用户的区域是通过区域解析器来识别的,它必须是实现LocaleResolver接口。Spring MVC提供了几个LocaleResolver实现,让你可以按照不同的条件来解析区域。初次之外,你还可以实现这个接口创建自己的区域解析器。如果没有做特殊的处理的话,Spring 采用的默认区域解析器是AcceptHeaderLocaleResolver。它通过检验HTTP请求的头部信息accept-language来解析区域。这个头部是由用户的wb浏览器底层根据底层操作系统的区域设置进行设定的。请注意,这个区域解析器无法改变用户的区域,因为它无法修改用户操作系统的区域设置。
既然无法修改,那么我们的代码怎么测试呢?请看如下内容?
(4) firefox浏览器修改区域语言;
打开firefox浏览器访问http://127.0.0.1:8080/hello (计算机系统语言是中文的),应该是看到如下信息:
欢迎你登录到 阿里巴巴 网站(中文)
那么我们修改我们的语言呢,在浏览器地址栏输入如下信息:
about:config
回车进入一个警告页面,然后点击按钮【我保证会小心】(注:由于版本不一样,可能会有些不一样,但是操作是一样的)。
<!--[endif]-->
在搜索框输入accept,然后找到intl.accept_languages修改对应的值,我这里原本是:
zh-cn, zh, en-us, en
为了看到效果,修改为:
en-us, en
修改完之后,刷新http://127.0.0.1:8080/hello ,可以看到信息:
welcome to login to alibaba website(English)
好了,没有什么特殊的需求的,记得把intl.accept_languages修改为原来的值。
(5)chrome浏览器修改区域语言;
我觉得firefox修改起来真是简单,chrome浏览器就稍微麻烦点了。
第一种方案就是下载插件:Quick Language Switcher,下载完插件之后,默认选项的比较少,你可以在扩展程序中,打开别的语言选项或者添加自定义的语言。这个只要插件下来来操作就很简单了,切换语言就会自动刷新页面,就能看到效果了,特别方便。注意的是:默认有一个English,这个使用的配置文件是:messages_en.properties,所以需要添加一个配置文件才能看到效果。
第二种方案是修改本地的一个配置文件,参考如下地址
但是我这里不管怎么修改,重启浏览器之后,就被重置回来了,也就是这种方案我这里没有配置成功。第一种方案肯定是可以的。
别的浏览器就自行尝试了,因为这不是我们这不是我们实际使用的重点,那么接下来才是重点哦。
(6)修改默认messages配置前缀;
我们在上面说了,默认的文件名称前缀是messages_xx.properties,那么如何修改这个名称和路径呢?
这个也很简单,只需要修改application.properties文件即可加入如下配置:
########################################################
### i18n setting.
########################################################
#指定message的basename,多个以逗号分隔,如果不加包名的话,默认从classpath路径开始,默认: messages
spring.messages.basename=i18n/messages
#设定加载的资源文件缓存失效时间,-1的话为永不过期,默认为-1
spring.messages.cache-seconds= 3600
#设定Message bundles的编码,默认: UTF-8
#spring.messages.encoding=UTF-8
上面各个参数都注释很清楚了,这里不多说了,那么我们这里是把文件放到了i18n下,那么我们在resources下新建目录i18n,然后复制我们创建的messages_xxx.properties文件到此目录下。为了区分这是读取了新的文件,我们可以在每个文件中—i18n以进行区分。
重新访问http://127.0.0.1:8080/hello 可以看到最新的效果了。
英文:
welcome to login to alibaba website(English-en)--i18n
中文:
欢迎你登录到阿里巴巴网站(中文)--i18n
(7) 代码中如何获取国际化信息;
以上讲的是在模板文件进行国际化,那么在代码中如何获取到welcome呢,这个比较简单,只要在需要的地方注入类:
@Autowired
private MessageSource messageSource;
需要注意的是messageSource是
org.springframework.context.MessageSource
下的类。
那么怎么使用了,在使用前我们需要先知道一个知识点,如何得到当前请求的Locale
那么怎么获取呢,有两种获取方式:
第一种方式是:
Locale locale = LocaleContextHolder.getLocale();
第二种方式是:
Locale locale1= RequestContextUtils.getLocale(request);
个人喜好第一种方式,因为不需要什么参数就可以获取到,第二种方式依赖于当前的request请求对象。
有了当前请求的Locale剩下的就简单了:
String msg = messageSource.getMessage("welcome", null,locale);
String msg2= messageSource.getMessage("welcome", null,locale1);
通过以上代码的其中一种方式就可以获取到messages_xxx.properties文件配置的welcome属性值了。切换区域获取的信息也是不一样的,打印信息如下:
msg=欢迎你登录到阿里巴巴网站(中文)--i18n
msg2欢迎你登录到阿里巴巴网站(中文)--i18n
msg=welcome to login to alibaba website(English-en)--i18n
msg2welcome to login to alibaba website(English-en)--i18n
(8) 优化代码获取国际化信息;
学习是永无止境的,活到老学到老。查看上面的代码你会发现这个是实际中使用起来的时候还是不是很方面,ok,没有关系,这个小节我们就对上面的代码优化下,
自定义我们自己的MessageSource,具体代码如下:
package com.kfit.common;
import java.util.Locale;
import javax.annotation.Resource;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
@Component
public class LocaleMessageSourceService {
@Resource
private MessageSource messageSource;
/**
* @param code :对应messages配置的key.
* @return
*/
public String getMessage(String code){
return getMessage(code,null);
}
/**
*
* @param code :对应messages配置的key.
* <