页面国际化
有的时候,我们的网站会去涉及中英文甚至多语言的切换,这时候我们就需要学习国际化了!
1.准备工作
先在IDEA中统一设置properties的编码问题!
编写国际化配置文件,抽取页面需要显示的国际化页面消息。我们可以去登录页面查看一下,哪些内容我们需要编写国际化的配置!
2.配置文件编写
1、我们在resources资源文件下新建一个i18n目录,存放国际化配置文件
什么是i18n?
- 类似的还有K8S
2、建立一个login.properties文件,还有一个login_zh_CN.properties;
其中新建三个配置文件,用来配置语言:
-
login.properties:无语言配置时候生效
-
login_en_US.properties:英文生效
-
login_zh_CN.properties:中文生效
命名方式是下划线的组合:文件名_语言_国家.properties;
发现IDEA自动识别了我们要做国际化操作;文件夹变了!
绑定在一起后,我们想要添加更过语言配置,只需要在大的资源包右键添加到该绑定配置文件即可
弹出如下页面:我们再添加一个英文的;
此时只需要输入区域名即可创建成功,比如输入en_US,就会自动识别,这样就快捷多了!
然后打开英文或者中文语言的配置文件,点击Resource Bundle进入可视化编辑页面
进入到可视化编辑页面后,点击加号,添加属性,首先新建一个login.tip代表首页中的提示
然后对该提示分别做三种情况的语言配置,在三个对应的输入框输入即可(注意:IDEA2020.1可能无法保存,建议直接在配置文件中编写)
双击点开 login.tip
我们可以发现 可视化配置十分的方便,一次性就可以配置3种
接下来再配置所有要转换语言的变量(注意:IDEA2020.1可能无法保存,建议直接在配置文件中编写)
然后打开三个配置文件的检查 查看其中的文本内容,可以看到已经做好了全部的配置
然后去查看我们的配置文件;
login.properties :默认
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
英文:
login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username
中文:
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
OK,配置文件步骤搞定!
3.配置文件生效探究
在Spring程序中,国际化主要是通过 ResourceBundleMessageSource
这个类来实现的
Spring Boot通过 MessageSourceAutoConfiguration
为我们自动配置好了管理国际化资源文件的组件
我们在IDEA中查看以下MessageSourceAutoConfiguration类
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, 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) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
//他可以设置我们Basenames 基本的名字
messageSource.setBasenames(StringUtils
//然后他会从properties.getBasename(),我们的配置文件去找
.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()这个方法:
public MessageSource messageSource(MessageSourceProperties properties);
可以看到,它的参数为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;
我们翻译其注释:
/**
* 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.
*/
-
逗号分隔的基名列表(本质上是完全限定的类路径位置)
-
每个都遵循ResourceBundle约定,并轻松支持于斜杠的位置
-
如果不包含包限定符(例如"org.mypackage"),它将从类路径根目录中解析
意思是:
-
如果你不在springboot配置文件中指定以.分隔开的国际化资源文件名称的话
-
它默认会去类路径下找messages.properties作为国际化资源文件
这里我们自定义了国际化资源文件,因此我们需要在SpringBoot配置文件application.properties
中加入以下配置指定我们配置文件的名称
# 我们的配置文件的真实位置
spring.messages.basename=i18n.login
其中i18n是存放资源的文件夹名,login是资源文件的基本名称。
4.首页获取显示国际化值
去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}。我们去页面测试下:
IDEA还有提示,非常智能的!
利用#{…} 消息表达式,去首页index.html获取国际化的值,没在<>内的,使用#[[#{ }]]
<!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>登录首页</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" th:src="@{/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">Username</label>
<input type="text" class="form-control" th:text="#{login.username}" placeholder="Username..." required="" autofocus="">
<label class="sr-only">Password</label>
<input type="password" class="form-control" th:text="#{login.password}" placeholder="Password..." required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" th:text="#{login.remember}"> Remeember me
</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">© 2020-2021</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>
</body>
</html>
重启项目,访问首页,发现已经自动识别为中文的了!
但是我们想要更好!可以根据按钮自动切换中文英文!
5.配置国际化解析 实现中英文切换
在Spring中有一个国际化的Locale (区域信息对象);里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!
思考:
html lang="en"或html lang="en-US"分别代表什么
HTML的lang属性是用来声明语言类型,,
, , ,
, , 以及
<html lang="en"></html>//英文
<html lang="zh-CN"></html>//中文
<html lang="ja"></html>//日文
<html lang="en-US"></html>//美式英文
<div lang="en">this is English .</div>//英文
写在html标签中的lang属性是声明当前页面的语言类型,这些对于搜索引擎、网页翻译、屏幕阅读浏览器有指导意义。
1.添加中英文切换标签链接
上述实现了登录首页显示为中文,我们在index.html页面中可以看到两个标签
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
也就对应着视图中的
那么我们怎么通过这两个标签实现中英文切换呢?
首先在这两个标签上加上跳转链接并带上相应的参数
<!--这里传入参数不需要使用?使用key=value-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
2.自定义地区解析器组件
怎么实现我们自定义的地区解析器呢?我们首先来分析一波源码
在Spring中有关于国际化的两个类:
- Locale:代表地区,每一个
Locale
对象都代表了一个特定的地理、政治和文化地区 - LocaleResolver:地区解析器
首先搜索WebMvcAutoConfiguration
,可以在其中找到关于一个方法localeResolver()
@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;
}
该方法就是获取LocaleResolver
地区对象解析器:
- 如果用户配置了则使用用户配置的地区解析器;
- 如果用户没有配置,则使用默认的地区解析器
我们可以看到默认地区解析器的是AcceptHeaderLocaleResolver
对象,我们点入该类查看源码
可以发现它继承了LocaleResolver接口,实现了地区解析
因此我们想要实现上述自定义的国际化资源生效,只需要编写一个自己的地区解析器,继承LocaleResolver接口,重写其方法即可。
我们在config包下新建MyLocaleResolver,作为自己的国际化地区解析器
我们在index.html中,编写了对应的请求跳转
-
如果点击中文按钮,则跳转到/index.html(l=‘zh_CN’)页面
-
如果点击English按钮,则跳转到/index.html(l=‘en_US’)页面
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
因此我们自定义的地区解析器MyLocaleResolver中,需要处理这两个带参数的链接请求
package com.cy.config;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
//获取请求中的国际化参数
String language = request.getParameter("l");
//默认的地区
Locale locale = Locale.getDefault();
//如果请求的链接参数不为空,携带了国际化参数
if (!StringUtils.isEmpty(language)){
//split分隔
String[] split = language.split("_");
//zh_CN(语言_地区)
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
为了让我们的区域化信息能够生效,我们需要再配置一下这个组件!在自己的MvcConofig
配置类下添加bean;
//自定义的国际化组件生效
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
我们重启项目,来访问一下,发现点击按钮可以实现成功切换!
点击中文按钮,跳转到http://localhost:8080/index.html?l=zh_CN,显示为中文
点击English
按钮,跳转到http://localhost:8080/index.html?l=en_US,显示为英文: