持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
一、springboot的国际化
1-1、通过在application.properties配置spring.message.basename指定国际化资源文件
上篇文章主要介绍了springboot中,MessageSourceAutoConfiguration自动配置类的加载原理及使用方式。得知,如果我们要使用国际化需要在将配置文件放到resource中,并且文件名需要命名为messages。但是在实际项目中,我们一般不会这么做,一般都是在resource中创建i18n文件夹,然后里面放我们的国际化资源文件。
通过上篇文章对源码的解读,有个核心方法getMatchOutcome,如下
这个方法定义了从application.properties中获取配置的key为:spring.messages.basename。因此我们在资源文件中配置这个key指向我们的i18n,这样就可以找到国际化资源文件,只要找到了,那
MessageSourceAutoConfiguration就可以加载了。
1-1-1、在resource中添加i18n文件夹,并且添加国际化配置文件
resource中三个配置文件的配置信息,如下
把resource下的资源文件删除,然后通过在application.properties中配置
spring.messages.basename=i18n.message就可以告诉MessageSourceAutoConfiguration中的@Conditional(ResourceBundleCondition.class)去哪里加载国际化配置文件了。
这样我们就完成了自定义指定国际化配置文件的处理。
1-1-2、小结
一旦匹配成功,自动配置类就会生效,就会帮我们配置一个meesageSource的Bean
这样就有两种方式都可以让国际化配置文件生效:
- 1、将以
messages命名的国际化资源文件放到resource根目录下(文件可以写为messages_zn_CN.properties/messages_en_US.properties)。 - 2、在application.properties中通过配置spring.messages.bashname=i18n.message 告诉自动配置类的生效条件去resource/i18n下找message命名的文件(文件可以写为message_zn_CN.properties/message_en_US.properties)
两者需要注意的是,第一种命名必须为messages,第二种是可以随便自定义的,只要和spring.message.bashname配置一致就可以
实际项目中建议选择第二种,这样代码可读性比较强。
1-2、如何获得accept-language
一般情况下:
1、我们可以去去解析请求头中的accept-language
2、解析url参数中比如local=zn
而springboot中其实WebMvcAutoConfiguration 类也帮我配置了一个解析请求头中的accept-language 的localResolver
1-2-1、WebMvcAutoConfiguration中LocaleResolver的解析
LocaleResolver这个Bean就是帮助我们实现国际化的,首先可以看到这个Bean上加了一个@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)注解,而LOCALE_RESOLVER_BEAN_NAME=localeResolver因此只要我们自己创建了localeResolver的Bean,springboot中的localeResolver就不生效了。
1-2-1-1、判断走配置文件还是请求头获取Local
首先进入getLocaleResolver这个方法
这样就进入了WebProperties类,可以看到这个类的配置信息为spring.web。同时
getLocaleResolver这个方法中的localeResolver最终被LocaleResolver.ACCEPT_HEADER;赋值。
再次进入ACCEPT_HEADER,可以看到LocaleResolver是一个枚举类型,里面有两个值,分别为:
FIXED:使用配置当中的Local配置
ACCEPT_HEADER:使用请求头中的配置
如果走配置文件,那么就会进入if里面
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
}
再次进入getLocale()这个方法,因此我们要通过配置文件来设置的话,就需要在application.properties中配置spring.web.locale=zn_CH,如下:
通过以上的方式就直接吧国际化语言设死了,因此我们要是没有设置,那么就会默认走请求头当中的ACCEPT_HEADER来获取国际化语言的类型了。
1-2-1-2、最终localeResolver方法含义如下
@Override
@Bean
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
public LocaleResolver localeResolver() {
// 当配置spring.mvc.locale-resolver=fiexd
if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {
// 就会使用配置文件中的本地化语言:spring.mvc.locale=en_US 就可以设死本地化语言
return new FixedLocaleResolver(this.webProperties.getLocale());
}
// 默认就是使用AcceptHeaderLocaleResolver 作为本地化解析器
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
//spring.mvc.locale=en_US 作为默认的本地化语言
localeResolver.setDefaultLocale(this.webProperties.getLocale());
return localeResolver;
}
通过上面代码分析,可以得知要在本地设死语言就需要在application.properties中设置
spring.web.locale-resolver=fixed
spring.web.locale=zh_CN
这样就设置本地语言为zh_CN了。
1-2-1-2-1、AcceptHeaderLocaleResolver
其含义为:
public Locale resolveLocale(HttpServletRequest request) {
// 当Accept-Languag为null 才会使用使用配置文件中设置的locale:spring.mvc.locale
Locale defaultLocale = this.getDefaultLocale();
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
} else {
// 就是使用request.getLocale();
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = this.getSupportedLocales();
if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
} else {
return defaultLocale != null ? defaultLocale : requestLocale;
}
} else {
return requestLocale;
}
}
}
1-3、使用messageSource.getMessage获取国际化资源文件
首先通过@Autowrite将MessageSource注入到Handler中,然通过messageSource.getMessage获得国际化里面的值。
1-3-1、messageSource.getMessage()方法详解
可以看到getMessage()有三个方法,一般情况下,使用第二种。
//code代表资源文件里面的key,args如果资源文件中的值可传参,这个地方可以传参,locale就是当前语言
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
1-3-2、传入参数的测试
因为要使用ACCEPT_HEADER获得语言,因此这两行配置一定要注释掉。
1-3-2-1、在配置文件中配置传入的参数位
1-3-2-1、在getMessage()中传入参数
1-3-2-2、访问接口测试
可以看到参数已经成功传入
1-3-2-3、将浏览器切换为英文
1-3-3、使用工具类获取国际化参数值
一般情况下,我们一个项目会创建一个公共帮助类,用来获取国际化的配置,要不还得每个Controller进行单独处理,太过繁琐。
package com.jony.utils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
@Component
public class i18nMessageUtils {
private static MessageSource messageSource;
public i18nMessageUtils(MessageSource messageSource) {
i18nMessageUtils.messageSource = messageSource;
}
/**
* 获取单个国际化翻译值
*/
public static String get(String msgKey,String[] strArr) {
try {
return messageSource.getMessage(msgKey, strArr, LocaleContextHolder.getLocale());
} catch (Exception e) {
return msgKey;
}
}
}
这样在使用的时候就可以直接进行获取,如下
1-4、随意切换本地语言,进行缓存
刚刚我们通过切换浏览器语言来实现国际化的处理,但是这样太麻烦了,还需要重启浏览器,而且一些普通用户想切换语言,对于浏览器的设置,可能还不太了解,因此一般网站系统,会有一个切换语言的功能,来实现国际化的操作。
然而自动配置类中的localeResovler它只会从accept-language中解析,因此我们需要覆盖原有localeResolver
1-4-1、使用cookie设置本地语言
首先在我们自己写的自动配置类中,添加localeResolver方法,这样springboot的localeResolver方法就不起作用了。
同时使用拦截器,对LocaleChangeInterceptor进行拦截,这样就可以将传入的国际化标签存入cookie中。
1-4-1-1、LocaleChangeInterceptor拦截器的处理
这个方法就会获取url传入的参数locale获得国际化标记,然后放入到cookie中。
1-4-2、测试
首次访问链接加上国际,就会将国际化locale的值存入cookie中,如下:
这样后面即使我们在URL未添加locale,也会自动从cookie中获取,得到国际化的值