如果我们在SoringMVC 写国际化 ,那么肯定是 编写国际化配置文件 然后 使用ResourceBundleMessageSource管理国际化资源文件 ,在JSP页面使用fmt:message取出国际化内容.
我们的目标是把上面国际化
现在用SpringBoot写,我们先写 国际化配置文件properties ,,,SpringBoot 很方便写:
在response文件夹下新建 i18n,我们在里面写吧,新建3个文件: 【记住!!! properties编码要改变! 不然前功尽弃!】
我们第一个做为默认 第二个 是en_US 美国 表示英语 ,第三个 zh_CN 表示中国。 【这里login 和 国家区域代码 是用 _ 分开的。 】
当SpringBoot 会自动识别出 国家区域代码 然后可以很方便的 Add 添加。
点击 Resoucre Bundle 可以快速编辑 这里自己来吧!
编辑好之后 即可。
SpringBoot 自动配置好了管理国际化资源文件的组件,我们查找看下主要源码 然后才知道怎么配置:
搜一下 MessageSourceAutoConfiguration 自动配置文件 可以看到里面配置:
主要配置1: MessageSourceAutoConfiguration 自动配置中特性:
/** * 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.
* 这个注释说的是 如果你要使用你自己的国际化配置文件properties,那么你就得在配置文件中设置,如果没设置任何指定【指定的时候注意基础名】,
* 那么他就自动在resouce中寻找! */ public class MessageSourceAutoConfiguration { private static final Resource[] NO_RESOURCES = new Resource[0]; private String basename = "messages"; //我们的配置文件可以直接放在类路径下叫messages.properties,他会自动读取。
////主要配置2 :添加了个组件进入,其中这里设置的是 基础名,结合上面 一起配置国际化功能
@Bean public MessageSource messageSource() { //全称 ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(this.basename)) { //这里是设置国际化文件的基础名(就是_和国家区域代码分开的前一个 比如我们的 login_zh_CN 基础名就是login) 他这里默认就是message了,所以他会自动去找message.... messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(this.basename))); } if (this.encoding != null) { messageSource.setDefaultEncoding(this.encoding.name()); } messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale); messageSource.setCacheSeconds(this.cacheSeconds); messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat); return messageSource; }
所以我们现在去 配置文件中 配置下 基础名:
最后在HTML 直接用Thynelemaf模板代码 #{...}:进行获取国际化内容:(确保你配置了Thymeleaf!和 properties的编码 不然出现乱码!) 如果都配置了 还是乱码,那么你看你html文件缺少默认编码头meta (<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>)没。
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>Signin Template for Bootstrap</title> <!-- Bootstrap core CSS --> <!-- @{} 这个是 根路径 servlet 的 getCountextPath 那个差不多 --> <link href="asserts/css/bootstrap.min.css" rel="stylesheet" th:href="@{/webjars/bootstrap/4.0.0/dist/css/bootstrap.css}" /> <!-- Custom styles for this template --> <link href="asserts/css/signin.css" rel="stylesheet" th:href="@{/asserts/css/signin.css}" /> </head> <body class="text-center"> <form class="form-signin" action="dashboard.html"> <img class="mb-4" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72"> <!-- 这一个 直接用th:text 配合 #{...}进行取出国际化数据 --> <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.title}">Please sign in</h1> <label class="sr-only" >Username</label> <!-- 这一个 直接用th:text 配合 #{...}进行取出国际化数据 --> <input type="text" class="form-control" th:placeholder="#{login.username}" placeholder="Username" required="" autofocus=""> <label class="sr-only" th:text="#{login.passwprd}" >Password</label> <!-- 这一个 直接用th:text 配合 #{...}进行取出国际化数据 --> <input type="password" class="form-control" th:placeholder="#{login.passwprd}" placeholder="Password" required=""> <div class="checkbox mb-3"> <label> <!-- 这一个 因为是行内 所以用行内标签解析 + #{...}取出 --> <input type="checkbox" value="remember-me"> [[#{login.Remember}]] </label> </div> <!-- 这一个 直接用th:text 配合 #{...}进行取出国际化数据 --> <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.sign}" >Sign in</button> <p class="mt-5 mb-3 text-muted">© 2017-2018</p> <a class="btn btn-sm">中文</a> <a class="btn btn-sm">English</a> </form> </body> </html>
然后运行 打开浏览器 把语言设置成中文 ,然后就是中文的了:
如果设置英文:
那么他的原理就是根据国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);但我们想通过 链接来切换,那么就要:
WebMvcAutoConfiguration 里面配置了 LocaleResolver ,看下他代码即可:
@Bean @ConditionalOnMissingBean @ConditionalOnProperty( prefix = "spring.mvc", name = {"locale"} ) public LocaleResolver localeResolver() { if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebMvcProperties.LocaleResolver.FIXED) { return new FixedLocaleResolver(this.mvcProperties.getLocale()); } else { AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver; } }
所以可以看出 他默认的就是根据请求头带来的区域信息获取Locale进行国际化,⭐⭐⭐⭐而且看下@ConditionalOnMissingBean这个注解 说明没 localeResolver 这个组件的时候 默认配置才生效,那么我们自定义一个,这里注意 自定义时 加入组件的ID 一定要是 localeResolver(方法名) 因为注解只判断 这个 localeResolver 是否存在决定默认生效否。那么我们思路就可以是:
首先写连接请求 可以携带参数(区域码):
然后自己配置一个 localeResolver :
package com.bihu.component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.LocaleResolver; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Locale; /*自己定义一个 LocaleResolver解析器,要实现 LocaleResolver 接口*/ public class MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest httpServletRequest) { String l = httpServletRequest.getParameter("l"); Locale locale = Locale.getDefault(); //如果获取的参数为空 那么获取默认区域代码 if ( l != null && !l.isEmpty()){ //参数不是null 且 长度不为空 String[] c = l.split("_"); //分隔后 第一个是语言代码 第二个是国家代码 locale = new Locale(c[0],c[1]); //请求参数不是空 locale更新。 } return locale; //返回Locale对象 } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { } }
最后把自己写的localeResolve加入到组件中生效:
package com.bihu.config; import com.bihu.component.MyLocaleResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class mConfig extends WebMvcConfigurerAdapter { @Bean //因为全部的 WebMvcConfigurerAdapter 会一起用 所以这里加入组件即可。 public WebMvcConfigurerAdapter addView(){ WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/index").setViewName("index"); } }; return webMvcConfigurerAdapter; } ================================ 上面那个别看 下面这个才是! //把自己的区域解析器 加入到 自动配置中 ,注意组件ID一定要是localeResolver 因为生效否决定在@ConditionalOnMissingBean注解。 @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); } }
然后运行:
可以发现成功了...