爲了適應經濟的全球一體化,做爲開發者,咱們須要開發出支持多國語言、國際化的Web應用,即一樣的頁面在不一樣的語言環境下須要顯示不一樣的效果,也就是說應用程序在運行時可以根據請求所來自的地域與語言的不一樣而顯示不一樣的用戶界面。這樣,當須要在應用程序中添加對新的語言的支持時,無需修改應用程序的代碼,只須要增長語言包便可實現。javascript
國際化與本地化(Internationalization and localization,一般用i18n和L10N表示),國際化是將針對某個地區設計的程序進行重構,以使它可以在更多地區使用,本地化是指在一個面向國際化的程序中增長對新地區的支持。css
所謂的國際化:就是根據特定的locale信息,提取與之相應的字符串或其它一些東西(好比時間和貨幣的格式)等等。這涉及到三個問題:java
一、如何肯定locale。jquery
二、如何保存與locale相關的字符串或其它信息。git
三、如何根據locale提取字符串和其它相應的信息。github
什麼是Localegolang
Locale是一組描述世界上某一特定區域文本格式和語言習慣的設置的集合。locale名一般由三個部分組成:第一部分,是一個強制性的,表示語言的縮寫,例如"en"表示英文或"zh"表示中文。第二部分,跟在一個下劃線以後,是一個可選的國家說明符,用於區分講同一種語言的不一樣國家,例如"en_US"表示美國英語,而"en_UK"表示英國英語。最後一部分,跟在一個句點以後,是可選的字符集說明符,例如"zh_CN.gb2312"表示中國使用gb2312字符集。web
前面咱們介紹瞭如何設置Locale,設置好Locale以後咱們須要解決的問題就是如何存儲相應的Locale對應的信息呢?這裏面的信息包括:文本信息、時間和日期、貨幣值、圖片、包含文件以及視圖等資源。那麼接下來咱們將對這些信息一一進行介紹,Go語言中咱們把這些格式信息存儲在JSON中,而後經過合適的方式展示出來json
文本信息是編寫Web應用中最經常使用到的,也是本地化資源中最多的信息,想要以適合本地語言的方式來顯示文本信息,可行的一種方案是:創建須要的語言相應的map來維護一個key-value的關係,在輸出以前按需從適合的map中去獲取相應的文本。bootstrap
有些時候僅是key-value替換是不能知足須要的,例如"I am 30 years old",中文表達是"我今年30歲了",而此處的30是一個變量,該怎麼辦呢?這個時候,咱們能夠結合fmt.Printf函數來實現,請看下面的代碼:
en["how old"] ="I am %d years old" cn["how old"] ="我今年%d歲了" fmt.Printf(msg(lang, "how old"), 30)
由於時區的關係,同一時刻,在不一樣的地區,表示是不同的,並且由於Locale的關係,時間格式也不盡相同,例如中文環境下可能顯示:2012年10月24日 星期三 23時11分13秒 CST,而在英文環境下可能顯示:Wed Oct 24 23:11:13 CST 2012。這裏面咱們須要解決兩點:
咱們可能會根據Locale的不一樣來展現視圖,這些視圖包含不一樣的圖片、css、js等各類靜態資源。那麼應如何來處理這些信息呢?首先咱們應按locale來組織文件信息,請看下面的文件目錄安排:
views |--en //英文模板 |--images //存儲圖片信息 |--js //存儲JS文件 |--css //存儲css文件 index.tpl //用戶首頁 login.tpl //登錄首頁 |--zh-CN //中文模板 |--images |--js |--css index.tpl login.tpl
有了這個目錄結構後咱們就能夠在渲染的地方這樣來實現代碼:
s1, _ := template.ParseFiles("views/"+lang+"/index.tpl") VV.Lang=lang s1.Execute(os.Stdout, VV)
而對於裏面的index.tpl裏面的資源設置以下:
// js文件 <script type="text/javascript" src="views/{{.Lang}}/js/jquery/jquery-1.8.0.min.js"></script> // css文件 <link href="views/{{.Lang}}/css/bootstrap-responsive.min.css" rel="stylesheet"> // 圖片文件 <img src="views/{{.Lang}}/images/btn.png">
採用這種方式來本地化視圖以及資源時,咱們就能夠很容易的進行擴展了。
使用及存儲本地資源,有時須要經過轉換函數來實現,有時經過lang來設置,可是最終都是經過key-value的方式來存儲Locale對應的數據,在須要時取出相應於Locale的信息後,若是是文本信息就直接輸出,若是是時間日期或者貨幣,則須要先經過fmt.Printf或其餘格式化函數來處理,而對於不一樣Locale的視圖和資源則是最簡單的,只要在路徑裏面增長lang就能夠實現了。
前面介紹瞭如何處理本地化資源,即Locale一個相應的配置文件,那麼若是處理多個的本地化資源呢?而對於一些咱們常常用到的例如:簡單的文本翻譯、時間日期、數字等若是處理呢?本小節將一一解決這些問題。
在開發一個應用的時候,首先咱們要決定是隻支持一種語言,仍是多種語言,若是要支持多種語言,咱們則須要制定一個組織結構,以方便未來更多語言的添加。在此咱們設計以下:Locale有關的文件放置在config/locales下,假設你要支持中文和英文,那麼你須要在這個文件夾下放置en.json和zh.json。
上面咱們介紹瞭如何自動加載自定義語言包,其實go-i18n庫已經預加載了不少默認的格式信息.
上面實現了多個語言包的管理和加載,而一些函數的實現是基於邏輯層的,例如:"Tr.Translate"、"Tr.Time"、"Tr.Money"等,雖然咱們在邏輯層能夠利用這些函數把須要的參數進行轉換後在模板層渲染的時候直接輸出,可是若是咱們想在模版層直接使用這些函數該怎麼實現呢?不知你是否還記得,在前面介紹模板的時候說過:Go語言的模板支持自定義模板函數,下面是咱們實現的方便操做的mapfunc:
文本信息
文本信息調用Tr.Translate來實現相應的信息轉換,mapFunc的實現以下:
func I18nT(args ...interface{}) string { ok := false var s string if len(args) == 1 { s, ok = args[0].(string) } if !ok { s = fmt.Sprint(args...) } return Tr.Translate(s) }
註冊函數以下:
t.Funcs(template.FuncMap{"T": I18nT})
模板中使用以下:
{{.V.Submit | T}}
如何實現一個多語言包的Web應用,經過自定義語言包咱們能夠方便的實現多語言,並且經過配置文件可以很是方便的擴充多語言,默認狀況下,go-i18n會自定加載一些公共的配置信息,例如時間、貨幣等,咱們就能夠很是方便的使用,同時爲了支持在模板中使用這些函數,也實現了相應的模板函數,這樣就容許咱們在開發Web應用的時候直接在模板中經過pipeline的方式來操做多語言包。