本文轉載自http://blog.csdn.net/linxingliang/article/details/52350238
國際化(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; importorg.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @RequestMapping("/hello") public String hello(){ return "/hello"; } }
這里就是訪問http://127.0.0.1:8080/hello就跳轉到hell.html進行訪問。
到這里准備工作就好了。
(2) 頁面元素國際化;
我們觀察hello.html里面的信息直接就是中文顯示,所以我們現在的需求是當訪問語言是zh的時候顯示為中文,當語言為en的時候顯示為英文,那么怎么操作呢?
首先我們先定義國際化資源文件,springboot默認就支持國際化的,而且不需要你過多的做什么配置,只需要在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 alibabawebsite(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開頭,需要看一個源碼文件:
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration: 這里提取部分代碼: /** * {@link EnableAutoConfiguration Auto-configuration} for {@linkMessageSource}. * * @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, eachfollowing the ResourceBundle convention. * Essentially a fully-qualified classpath location. If itdoesn'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 cacheexpiration, in seconds. When set to -1, bundles * are cached forever. */ private int cacheSeconds = -1; /** * Set whether to fall back to the systemLocale if no files for a specific Locale * have been found. if this is turned off, theonly fallback will be the default file * (e.g. "messages.properties" forbasename "messages"). */ privateboolean fallbackToSystemLocale = 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
回車進入一個警告頁面,然后點擊按鈕【我保證會小心】(注:由於版本不一樣,可能會有些不一樣,但是操作是一樣的)。
在搜索框輸入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瀏覽器就稍微麻煩點了。
第一種方案就是下載插件:QuickLanguage Switcher,下載完插件之后,默認選項的比較少,你可以在擴展程序中,打開別的語言選項或者添加自定義的語言。這個只要插件下來來操作就很簡單了,切換語言就會自動刷新頁面,就能看到效果了,特別方便。注意的是:默認有一個English,這個使用的配置文件是:messages_en.properties,所以需要添加一個配置文件才能看到效果。
第二種方案是修改本地的一個配置文件,參考如下地址
http://stackoverflow.com/questions/7769061/how-to-add-custom-accept-languages-to-chrome-for-pseudolocalization-testing
但是我這里不管怎么修改,重啟瀏覽器之后,就被重置回來了,也就是這種方案我這里沒有配置成功。第一種方案肯定是可以的。
別的瀏覽器就自行嘗試了,因為這不是我們這不是我們實際使用的重點,那么接下來才是重點哦。
(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 alibabawebsite(English-en)--i18n
中文:
歡迎你登錄到 阿里巴巴 網站(中文)--i18n
(7) 代碼中如何獲取國際化信息;
以上講的是在模板文件進行國際化,那么在代碼中如何獲取到welcome呢,這個比較簡單,只要在需要的地方注入類:
@Autowired
privateMessageSource messageSource;
需要注意的是messageSource是
org.springframework.context.MessageSource
下的類。
那么怎么使用了,在使用前我們需要先知道一個知識點,如何得到當前請求的Locale
那么怎么獲取呢,有兩種獲取方式:
第一種方式是:
Locale locale = LocaleContextHolder.getLocale();
第二種方式是:
Localelocale1= RequestContextUtils.getLocale(request);
個人喜好第一種方式,因為不需要什么參數就可以獲取到,第二種方式依賴於當前的request請求對象。
有了當前請求的Locale剩下的就簡單了:
String msg = messageSource.getMessage("welcome", null,locale); Stringmsg2= messageSource.getMessage("welcome", null,locale1);
通過以上代碼的其中一種方式就可以獲取到messages_xxx.properties文件配置的welcome屬性值了。切換區域獲取的信息也是不一樣的,打印信息如下:
msg=歡迎你登錄到 阿里巴巴 網站(中文)--i18n msg2歡迎你登錄到 阿里巴巴 網站(中文)--i18n msg=welcome to login to alibabawebsite(English-en)--i18n msg2welcometo login to alibaba website(English-en)--i18n
(8) 優化代碼獲取國際化信息;
學習是永無止境的,活到老學到老。查看上面的代碼你會發現這個是實際中使用起來的時候還是不是很方面,ok,沒有關系,這個小節我們就對上面的代碼優化下,
自定義我們自己的MessageSource,具體代碼如下:
package com.kfit.base.service; import Java.util.Locale; importjavax.annotation.Resource; importorg.springframework.context.MessageSource; importorg.springframework.context.i18n.LocaleContextHolder; importorg.springframework.stereotype.Component; /** * 國際化工具類 * @author Angel --守護天使 * @version v.0.1 * @date 2016年8月5日下午2:44:03 */ @Component public classLocaleMessageSourceService { @Resource private MessageSource messageSource; /** * @param code :對應messages配置的key. * @return */ public StringgetMessage(String code){ return this.getMessage(code,new Object[]{}); } public StringgetMessage(String code,String defaultMessage){ return this.getMessage(code, null,defaultMessage); } public StringgetMessage(String code,String defaultMessage,Locale locale){ return this.getMessage(code, null,defaultMessage,locale); } public StringgetMessage(String code,Locale locale){ return this.getMessage(code,null,"",locale); } /** * * @param code :對應messages配置的key. * @param args : 數組參數. * @return */ public StringgetMessage(String code,Object[] args){ return this.getMessage(code, args,""); } public StringgetMessage(String code,Object[] args,Locale locale){ return this.getMessage(code, args,"",locale); } /** * * @param code :對應messages配置的key. * @param args : 數組參數. * @param defaultMessage : 沒有設置key的時候的默認值. * @return */ public StringgetMessage(String code,Object[] args,String defaultMessage){ //這里使用比較方便的方法,不依賴request. Locale locale =LocaleContextHolder.getLocale(); return this.getMessage(code, args, defaultMessage, locale); } /** * 指定語言. * @param code * @param args * @param defaultMessage * @param locale * @return */ public StringgetMessage(String code,Object[]args,String defaultMessage,Locale locale){ return messageSource.getMessage(code, args, defaultMessage,locale); } }
在這個代碼中我封裝了3個常用的方法,那么應該怎么調用呢?也很簡單,在需要的地方使用如下代碼進行注入:
@Resource
privateLocaleMessageSourceService localeMessageSourceService;
在需要的地方使用如下代碼進行調用:
Stringmsg3 = localeMessageSourceService.getMessage("welcome");
這個代碼比之前的代碼使用起來爽多了,還有很多神妙之處,大家自己發現吧。
(9) 區域解析器之AcceptHeaderLocaleResolver;
看到上面,大家會認為國際化也就到此了,但是我告訴大家這之后才是spring的強大之處呢,考慮的多么周到呢。
我們在之前說過,我們只所以可以看到國際化的效果是因為有一個區域解析器在進行處理。默認的區域解析器就是AcceptHeaderLocaleResolver。我們簡單說明這個解析器:
Spring采用的默認區域解析器是AcceptHeaderLocaleResolver。它通過檢驗HTTP請求的accept-language頭部來解析區域。這個頭部是由用戶的web瀏覽器根據底層操作系統的區域設置進行設定。請注意,這個區域解析器無法改變用戶的區域,因為它無法修改用戶操作系統的區域設置。
好了,這個默認的介紹到這里,因為這個我們無法改變,所以這種默認的設置在實際中使用的比較少。所以你如果看到當前還無法滿足的需求的話,那么接着往下看,博主已經幫你都想到了。
(10) 會話區域解析器之SessionLocaleResolver;
會話區域解析器也就是說,你設置完只針對當前的會話有效,session失效,還原為默認狀態。那么這個具體怎么操作呢?具體操作起來也是很簡單的,我們需要在我們的啟動類App.java(按你的實際情況進行修改)配置區域解析器為SessionLocaleResolver,具體代碼如下:
@Bean public LocaleResolverlocaleResolver() { SessionLocaleResolver slr = newSessionLocaleResolver(); //設置默認區域, slr.setDefaultLocale(Locale.CHINA); return slr; }
其實到這里我們就完事了,你可以通過setDefaultLocale()設置默認的語言,啟動就訪問http://127.0.0.1:8080/hello進行查看,是不是已經實現國際化了。
到這里當然還不是很完美,還需要在進一步的優化了,那么怎么在頁面中進行切換呢?那么假設頁面上有兩個按鈕【切換為中文】、【切換為英文】就可以進行切換了。接下來一起來實現下:在hello.html添加如下代碼:
<form action="/changeSessionLanauage" method="get"> <input name="lang"type="hidden" value="zh" /> <button>切換為中文</button> </form> <form action="/changeSessionLanauage"method="get"> <input name="lang"type="hidden" value="en"/> <button>切換為英文</button> </form>
這里就是兩個表單,切換語言,那么/changeSessionLanauage怎么編寫呢,看如下代碼:
@RequestMapping("/changeSessionLanauage") public StringchangeSessionLanauage(HttpServletRequest request,String lang){ System.out.println(lang); if("zh".equals(lang)){ //代碼中即可通過以下方法進行語言設置 request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME,new Locale("zh", "CN")); }else if("en".equals(lang)){ //代碼中即可通過以下方法進行語言設置 request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME,new Locale("en", "US")); } return "redirect:/hello"; }
這部分代碼最核心的部分就是如何設置會話的區域,也就是如下代碼:
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, newLocale("en", "US"));
這個代碼就可以把當前會話的區域進行切換了,是不是很簡單。以上代碼你會發現只針對會話的設置,我們在這里在優化下,針對下面講的Cookie也會作用到,這樣這個代碼就很智能了,代碼修改為如下:
@RequestMapping("/changeSessionLanauage") public StringchangeSessionLanauage(HttpServletRequest request,HttpServletResponse response,String lang){ System.out.println(lang); LocaleResolver localeResolver =RequestContextUtils.getLocaleResolver(request); if("zh".equals(lang)){ localeResolver.setLocale(request, response, new Locale("zh", "CN")); }else if("en".equals(lang)){ localeResolver.setLocale(request, response, new Locale("en", "US")); } return "redirect:/hello"; }
在這里使用:
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
獲取當前使用的區域解析器LocaleResolver 調用里面的方法
setLocale設置即可,這樣的代碼就是不管是會話還是cookie區域解析器都是一樣的代碼了。
(11)Cookie區域解析器之CookieLocaleResolver;
Cookie區域解析器也就是說,你設置完針對cookie生效,session失效。那么這個具體怎么操作呢?我們需要在我們的啟動類App.java(按你的實際情況進行修改)配置區域解析器為CookieLocaleResolver(SessionLocaleResolver部分請注釋掉),具體代碼如下:
@Bean public LocaleResolverlocaleResolver() { CookieLocaleResolverslr = newCookieLocaleResolver(); //設置默認區域, slr.setDefaultLocale(Locale.CHINA); slr.setCookieMaxAge(3600);//設置cookie有效期. return slr; }
其實到這里我們就完事了,你可以通過setDefaultLocale()設置默認的語言,啟動就訪問http://127.0.0.1:8080/hello進行查看,是不是已經實現國際化了。
到這里當然還不是很完美,還需要在進一步的優化了,那么怎么在頁面中進行切換呢?
這里主要是用到了,這個部分我們在(10)中已經進行配置了,所以到這里已近是可以進行使用了,點擊頁面中的按鈕進行體驗。
(12)固定的區域解析器之FixedLocaleResolver ;
一直使用固定的Local, 改變Local 是不支持的。既然無法改變,那么不…好了,還是簡單介紹下如何使用吧,還是在App.java進行編碼:
/** * cookie區域解析器; * @return */ @Bean public LocaleResolverlocaleResolver() { FixedLocaleResolver slr = newFixedLocaleResolver (); //設置默認區域, slr.setDefaultLocale(Locale.US); return slr; }
好了,這個就這么簡單,沒有別的知識了。
@Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor lci = newLocaleChangeInterceptor(); // 設置請求地址的參數,默認為:locale // lci.setParamName(LocaleChangeInterceptor.DEFAULT_PARAM_NAME); return lci; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); }
(13)使用參數修改用戶的區域;
除了顯式調用LocaleResolver.setLocale()來修改用戶的區域之外,還可以將LocaleChangeInterceptor攔截器應用到處理程序映射中,它會發現當前HTTP請求中出現的特殊參數。其中的參數名稱可以通過攔截器的paramName屬性進行自定義。如果這種參數出現在當前請求中,攔截器就會根據參數值來改變用戶的區域。
只需要在App.java中加入:
@Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptorlci = newLocaleChangeInterceptor(); // 設置請求地址的參數,默認為:locale // lci.setParamName(LocaleChangeInterceptor.DEFAULT_PARAM_NAME); returnlci; } @Override publicvoid addInterceptors(InterceptorRegistryregistry) { registry.addInterceptor(localeChangeInterceptor()); }
注意這個是可以和會話區域解析器以及Cookie區域解析器一起使用的,但是不能和FixedLocaleResolver一起使用,否則會拋出異常信息。
好了,國際化就到此為主了,博主也是累了,這部分知識在國內還真沒有,博主也是各種收集資料才總結出了這么一篇文章,絕對原創,大家都都點贊評論。