有时候网站会涉及中英文甚至多语言的切换,这时候我们需要学习国际化
准备工作
-
先设置properties的编码为utf-8
-
编写国际化配置文件,在resources资源路径下新建i18n目录,存放国际化配置文件
3.建立一个login.properties文件,还有一个login_zh_CN.properties,发现IDEA自动识别了我们要做国际化操作,文件夹改变了
4.可以在这个文件夹下面新建一个文件
- 可以添加一个存放英文的资源配置文件
方便快捷
6.当我们随便打开一个配置文件编写时,发现idea有一个操作
-
点击视图的+号就可以直接添加属性了,新建一个login.tip,发现右边有三个文件框可以输入对应的属性值
-
添加首页内容、对应页面值为
- 依次添加其他页面值与配置文件的属性对应
查看我们的配置文件:
login.properties:它是默认设置
login.passWord=密码
login.remember=记住我
login.submit=登录
login.tip=请登录
login.userName=用户名
英文:
login.passWord=Password
login.remember=Remember me
login.submit=Sign in
login.tip=Please sign in
login.userName=Username
中文:
login.passWord=密码
login.remember=记住我
login.submit=登录
login.tip=请登录
login.userName=用户名
探究配置文件生效问题
- 查找一下springboot对国际化的自动配置,有一个类叫MessageSourceAutoConfiguration,里面有一个方法,SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource
// 获取 properties 传递过来的值进行判断
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
// 设置国际化文件的基础名(去掉语言国家代码的)
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils
.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
发现还有一个类
protected static class ResourceBundleCondition extends SpringBootCondition {
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<>();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取配置文件的位置
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
//添加做为候选
ConditionOutcome outcome = cache.get(basename);
if (outcome == null) {
outcome = getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
在配置文件中如何配置spring.messages.basename值呢?
private Resource[] getResources(ClassLoader classLoader, String name) {
//帮我们把.转换为/
String target = name.replace('.', '/');
try {
//并从类路径下查找,拼接xxx/xx.properties文件
return new PathMatchingResourcePatternResolver(classLoader)
.getResources("classpath*:" + target + ".properties");
}
catch (Exception ex) {
return NO_RESOURCES;
}
}
- 所有我们在i18n目录下,配置这个messages的路径
spring.messages.basename=i18n.login
在HTML页面配置国际化值
- 查看Thymeleaf的文档,发现message取值操作为#{…}
- 使用Thymeleaf表达式修改HTML页面
3.启动项目测试:访问主页面,已经自动被识别为中文了
配置国际化解析
根据按钮自动切换中文英文
- 我们在WebMvcAutoConfiguration类中发现有一个国际化Locale (区域信息对象)里面有一个叫做LocaleResolver (获取区域信息对象)的解析器
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
@SuppressWarnings("deprecation")
public LocaleResolver localeResolver() {
//如果webProperties配置文件中有配置,则用固定的国际化解析器
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
}
//如果mvcProperties配置文件中有配置,则用固定的国际化解析器
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
//接收头国际化分解
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
//如果配置文件为null则用默认的配置
Locale locale = (this.webProperties.getLocale() != null) ? this.webProperties.getLocale()
: this.mvcProperties.getLocale();
localeResolver.setDefaultLocale(locale);
return localeResolver;
}
- AcceptHeaderLocaleResolver实现了一个接口LocaleResolver,并且重写了resolveLocale()方法
public Locale resolveLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
默认的就是根据请求头带来的区域信息获取Locale进行国际化
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
}
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = getSupportedLocales();
if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
return requestLocale;
}
Locale supportedLocale = findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
}
return (defaultLocale != null ? defaultLocale : requestLocale);
}
-
如果我们想点击链接让我们自己的国际化资源生效,就必须实现LocaleResolver接口,重写resolveLocale方法,让我们的Locale生效,我们可以写一个自己的LocaleResolver,可以在链接上携带区域信息
-
修改一下页面的跳转链接
<!-- 这里传入参数不需要使用 ?使用 (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>
- 写一个配置类组件,作为webMVC拓展配置类
//可以在链接上携带区域信息
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
//解析请求传参
String language = request.getParameter("lang");
//获取当地默认的语言,如果解析失败则用默认的国际化语言
Locale locale = Locale.getDefault();
//如果请求链接不为空
if (!StringUtils.isEmpty(language)){
//分割请求参数
String[] split = language.split("_");
//将分割的字符串代表国家语言和地区,创建一个新locale对象并赋值
locale=new Locale(split[0],split[1]);
}
//将得到的国际化语言对象返回
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
- 为了让我们的区域化信息能够生效,需要在我们自定义配置类中(即实现WebMvcConfigurer接口,以及添加注解@Configuration)将上面的类注册bean交给SpringIOC管理
//自定义webMVC配置类,拓展webMVC的配置
@Configuration
public class MyConfiguration implements WebMvcConfigurer {
//添加视图控制器
public void addViewControllers(ViewControllerRegistry registry) {
//当访问/或者/index.html都会跳转到首页
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
@Bean("localeResolver")
public LocaleResolver LocaleResolver(){
return new MyLocaleResolver();
}
}
注意:在自定义配置类中的LocaleResolver()方法名必须为这个,因为springboot会自动调用这个方法,而且注入的bean要指定名称(localeResolver),如果不指定名称默认是注入myLocaleResolver,springIOC容器找不到该localeResolver的bean则无法实现国际化转换
浏览器访问: