天天看點

springboot國際化(i18n)

國際化(internationalization)是設計和制造容易适應不同區域要求的産品的一種方式。它要求從産品中抽離所有地域語言,國家/地區和文化相關的元素。換言之,應用程式的功能和代碼設計考慮在不同地區運作的需要,其代碼簡化了不同本地版本的生産。開發這樣的程式的過程,就稱為國際化。

(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在

這篇文章有介紹過,是以這裡就不過多進行介紹了。在這裡我們為之後的講解做點基本準備。

模闆檔案resources/templates/hello.html:

<!doctype html>

<html>

<head>

   <meta charset="utf-8" />

   <title>hello spring boot</title>

</head>

<body>

       <p>歡迎你登入到 阿裡巴巴 網站</p>

</body>

</html>

這裡沒有特殊的代碼,通路就是顯示一些文字,這裡還沒加入國際化的相關東西,之後添加。

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";

       }

}

到這裡準備工作就好了。

       我們觀察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中的字段資訊:

       <p><label th:text="#{welcome}"></label></p>

歡迎你登入到 阿裡巴巴 網站(中文)

(3)spring boot預設國際化原理說明

       在這裡我們先打住下,簡單說下原理:

第一個問題,為什麼命名必須是messages開頭,需要看一個源碼檔案:

這裡提取部分代碼:

/**

 * {@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").

       private boolean fallbacktosystemlocale = true;

看到沒有,如果我們沒有在application.properties中配置spring.messages屬性,那麼使用預設的messages,好了這個問題就這麼簡單解決了。

第二問題:為什麼我看到的是中文(或者英文)呢?

歡迎你登入到阿裡巴巴 網站(中文)

那麼我們修改我們的語言呢,在浏覽器位址欄輸入如下資訊:

about:config

回車進入一個警告頁面,然後點選按鈕【我保證會小心】(注:由于版本不一樣,可能會有些不一樣,但是操作是一樣的)。

在搜尋框輸入accept,然後找到intl.accept_languages修改對應的值,我這裡原本是:

zh-cn, zh, en-us, en

為了看到效果,修改為:

en-us, en

welcome to login to alibaba website(english)

好了,沒有什麼特殊的需求的,記得把intl.accept_languages修改為原來的值。

       我覺得firefox修改起來真是簡單,chrome浏覽器就稍微麻煩點了。

第一種方案就是下載下傳插件:quicklanguage switcher,下載下傳完插件之後,預設選項的比較少,你可以在擴充程式中,打開别的語言選項或者添加自定義的語言。這個隻要插件下來來操作就很簡單了,切換語言就會自動重新整理頁面,就能看到效果了,特别友善。注意的是:預設有一個english,這個使用的配置檔案是:messages_en.properties,是以需要添加一個配置檔案才能看到效果。

第二種方案是修改本地的一個配置檔案,參考如下位址

<a href="http://stackoverflow.com/questions/7769061/how-to-add-custom-accept-languages-to-chrome-for-pseudolocalization-testing" target="_blank">http://stackoverflow.com/questions/7769061/how-to-add-custom-accept-languages-to-chrome-for-pseudolocalization-testing</a>

但是我這裡不管怎麼修改,重新開機浏覽器之後,就被重置回來了,也就是這種方案我這裡沒有配置成功。第一種方案肯定是可以的。

       别的浏覽器就自行嘗試了,因為這不是我們這不是我們實際使用的重點,那麼接下來才是重點哦。

       我們在上面說了,預設的檔案名稱字首是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以進行區分。

英文:

welcome to login to alibabawebsite(english-en)--i18n

中文:

歡迎你登入到 阿裡巴巴 網站(中文)--i18n

       以上講的是在模闆檔案進行國際化,那麼在代碼中如何擷取到welcome呢,這個比較簡單,隻要在需要的地方注入類:

@autowired

private messagesource messagesource;

需要注意的是messagesource是

org.springframework.context.messagesource

下的類。

那麼怎麼使用了,在使用前我們需要先知道一個知識點,如何得到目前請求的locale

那麼怎麼擷取呢,有兩種擷取方式:

第一種方式是:

locale locale = localecontextholder.getlocale();

第二種方式是:

localelocale1= requestcontextutils.getlocale(request);

個人喜好第一種方式,因為不需要什麼參數就可以擷取到,第二種方式依賴于目前的request請求對象。

有了目前請求的locale剩下的就簡單了:

string msg = messagesource.getmessage("welcome", null,locale);

string msg2= 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

       學習是永無止境的,活到老學到老。檢視上面的代碼你會發現這個是實際中使用起來的時候還是不是很方面,ok,沒有關系,這個小節我們就對上面的代碼優化下,

自定義我們自己的messagesource,具體代碼如下:

package com.kfit.base.service;

import javax.annotation.resource;

import org.springframework.context.messagesource;

import org.springframework.context.i18n.localecontextholder;

import org.springframework.stereotype.component;

 * 國際化工具類

 * @author angel --守護天使

 * @version v.0.1

 * @date 2016年8月5日下午2:44:03

@component

public class localemessagesourceservice {

    @resource

    private messagesource messagesource;

    /**

     * @param code :對應messages配置的key.

     * @return

     */

    public string getmessage(string code){

       return this.getmessage(code,new object[]{});

    }

    public string getmessage(string code,string defaultmessage){

       return this.getmessage(code, null,defaultmessage);

    public string getmessage(string code,string defaultmessage,locale locale){

       return this.getmessage(code, null,defaultmessage,locale);

    public string getmessage(string code,locale locale){

       return this.getmessage(code,null,"",locale);

     *

     * @param args : 數組參數.

    public string getmessage(string code,object[] args){

       return this.getmessage(code, args,"");

    public string getmessage(string code,object[] args,locale locale){

       return this.getmessage(code, args,"",locale);

     * @param defaultmessage : 沒有設定key的時候的預設值.

    public string getmessage(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

    public string getmessage(string code,object[]args,string defaultmessage,locale locale){

       return messagesource.getmessage(code, args, defaultmessage,locale);

在這個代碼中我封裝了3個常用的方法,那麼應該怎麼調用呢?也很簡單,在需要的地方使用如下代碼進行注入:

@resource

private localemessagesourceservice localemessagesourceservice;

在需要的地方使用如下代碼進行調用:

string msg3 = localemessagesourceservice.getmessage("welcome");

這個代碼比之前的代碼使用起來爽多了,還有很多神妙之處,大家自己發現吧。

       看到上面,大家會認為國際化也就到此了,但是我告訴大家這之後才是spring的強大之處呢,考慮的多麼周到呢。

       我們在之前說過,我們隻是以可以看到國際化的效果是因為有一個區域解析器在進行處理。預設的區域解析器就是acceptheaderlocaleresolver。我們簡單說明這個解析器:

       spring采用的預設區域解析器是acceptheaderlocaleresolver。它通過檢驗http請求的accept-language頭部來解析區域。這個頭部是由使用者的web浏覽器根據底層作業系統的區域設定進行設定。請注意,這個區域解析器無法改變使用者的區域,因為它無法修改使用者作業系統的區域設定。

       好了,這個預設的介紹到這裡,因為這個我們無法改變,是以這種預設的設定在實際中使用的比較少。是以你如果看到目前還無法滿足的需求的話,那麼接着往下看,部落客已經幫你都想到了。

       會話區域解析器也就是說,你設定完隻針對目前的會話有效,session失效,還原為預設狀态。那麼這個具體怎麼操作呢?具體操作起來也是很簡單的,我們需要在我們的啟動類app.java(按你的實際情況進行修改)配置區域解析器為sessionlocaleresolver,具體代碼如下:

  @bean

       public localeresolver localeresolver() {

           sessionlocaleresolver lr = newsessionlocaleresolver();

           //設定預設區域,

           lr.setdefaultlocale(locale.china);

           return lr;

       到這裡當然還不是很完美,還需要在進一步的優化了,那麼怎麼在頁面中進行切換呢?那麼假設頁面上有兩個按鈕【切換為中文】、【切換為英文】就可以進行切換了。接下來一起來實作下:在hello.html添加如下代碼:

&lt;form action="/changesessionlanauage" method="get"&gt;

              &lt;input name="lang"type="hidden" value="zh"  /&gt;

              &lt;button&gt;切換為中文&lt;/button&gt;

       &lt;/form&gt;

       &lt;form action="/changesessionlanauage"method="get"&gt;

              &lt;input name="lang"type="hidden" value="en"/&gt;

              &lt;button&gt;切換為英文&lt;/button&gt;

這裡就是兩個表單,切換語言,那麼/changesessionlanauage怎麼編寫呢,看如下代碼:

@requestmapping("/changesessionlanauage")

       public string changesessionlanauage(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")); 

       public string changesessionlanauage(httpservletrequest request,httpservletresponse response,string lang){

                            system.out.println(lang);

              localeresolver localeresolver =requestcontextutils.getlocaleresolver(request);

                     localeresolver.setlocale(request, response, new locale("zh", "cn"));

                     localeresolver.setlocale(request, response, new locale("en", "us"));

在這裡使用:

localeresolver localeresolver = requestcontextutils.getlocaleresolver(request);

擷取目前使用的區域解析器localeresolver  調用裡面的方法

setlocale設定即可,這樣的代碼就是不管是會話還是cookie區域解析器都是一樣的代碼了。

(11)cookie區域解析器之cookielocaleresolver;

       cookie區域解析器也就是說,你設定完針對cookie生效,session失效。那麼這個具體怎麼操作呢?我們需要在我們的啟動類app.java(按你的實際情況進行修改)配置區域解析器為cookielocaleresolver(sessionlocaleresolver部分請注釋掉),具體代碼如下:

@bean

              cookielocaleresolver lr = newcookielocaleresolver();

           lr.setcookiemaxage(3600);//設定cookie有效期.

       到這裡當然還不是很完美,還需要在進一步的優化了,那麼怎麼在頁面中進行切換呢?

這裡主要是用到了,這個部分我們在(10)中已經進行配置了,是以到這裡已近是可以進行使用了,點選頁面中的按鈕進行體驗。

       一直使用固定的local, 改變local 是不支援的。既然無法改變,那麼不…好了,還是簡單介紹下如何使用吧,還是在app.java進行編碼:

        * cookie區域解析器;

        * @return

       @bean

              fixedlocaleresolver lr = newfixedlocaleresolver ();

           lr.setdefaultlocale(locale.us);

好了,這個就這麼簡單,沒有别的知識了。

       除了顯式調用localeresolver.setlocale()來修改使用者的區域之外,還可以将localechangeinterceptor攔截器應用到處理程式映射中,它會發現目前http請求中出現的特殊參數。其中的參數名稱可以通過攔截器的paramname屬性進行自定義。如果這種參數出現在目前請求中,攔截器就會根據參數值來改變使用者的區域。

       隻需要在app.java中加入:

        public localechangeinterceptor localechangeinterceptor() {

               localechangeinterceptor lci = new localechangeinterceptor();

               // 設定請求位址的參數,預設為:locale

//            lci.setparamname(localechangeinterceptor.default_param_name);

               return lci;

   @override

  public void addinterceptors(interceptorregistry registry) {

      registry.addinterceptor(localechangeinterceptor());

   }

注意這個是可以和會話區域解析器以及cookie區域解析器一起使用的,但是不能和fixedlocaleresolver一起使用,否則會抛出異常資訊。

原文連結:[http://wely.iteye.com/blog/2381461]