Locale是一組描述世界上某一特定區(qū)域文本格式和語言習(xí)慣的設(shè)置的集合。locale名通常由三個(gè)部分組成:第一部分,是一個(gè)強(qiáng)制性的,表示語言的縮寫,例如"en"表示英文或"zh"表示中文。第二部分,跟在一個(gè)下劃線之后,是一個(gè)可選的國家說明符,用于區(qū)分講同一種語言的不同國家,例如"en_US"表示美國英語,而"en_UK"表示英國英語。最后一部分,跟在一個(gè)句點(diǎn)之后,是可選的字符集說明符,例如"zh_CN.gb2312"表示中國使用gb2312字符集。
GO語言默認(rèn)采用"UTF-8"編碼集,所以我們實(shí)現(xiàn)i18n時(shí)不考慮第三部分,接下來我們都采用locale描述的前面兩部分來作為i18n標(biāo)準(zhǔn)的locale名。
在Linux和Solaris系統(tǒng)中可以通過
locale -a
命令列舉所有支持的地區(qū)名,讀者可以看到這些地區(qū)名的命名規(guī)范。對(duì)于BSD等系統(tǒng),沒有l(wèi)ocale命令,但是地區(qū)信息存儲(chǔ)在/usr/share/locale中。
有了上面對(duì)locale的定義,那么我們就需要根據(jù)用戶的信息(訪問信息、個(gè)人信息、訪問域名等)來設(shè)置與之相關(guān)的locale,我們可以通過如下幾種方式來設(shè)置用戶的locale。
設(shè)置Locale的辦法這一就是在應(yīng)用運(yùn)行的時(shí)候采用域名分級(jí)的方式,例如,我們采用www.asta.com當(dāng)做我們的英文站(默認(rèn)站),而把域名www.asta.cn當(dāng)做中文站。這樣通過在應(yīng)用里面設(shè)置域名和相應(yīng)的locale的對(duì)應(yīng)關(guān)系,就可以設(shè)置好地區(qū)。這樣處理有幾點(diǎn)好處:
我們可以通過下面的代碼來實(shí)現(xiàn)域名的對(duì)應(yīng)locale:
if r.Host == "www.asta.com" {
i18n.SetLocale("en")
} else if r.Host == "www.asta.cn" {
i18n.SetLocale("zh-CN")
} else if r.Host == "www.asta.tw" {
i18n.SetLocale("zh-TW")
}
當(dāng)然除了整域名設(shè)置地區(qū)之外,我們還可以通過子域名來設(shè)置地區(qū),例如"en.asta.com"表示英文站點(diǎn),"cn.asta.com"表示中文站點(diǎn)。實(shí)現(xiàn)代碼如下所示:
prefix := strings.Split(r.Host,".")
if prefix[0] == "en" {
i18n.SetLocale("en")
} else if prefix[0] == "cn" {
i18n.SetLocale("zh-CN")
} else if prefix[0] == "tw" {
i18n.SetLocale("zh-TW")
}
通過域名設(shè)置Locale有如上所示的優(yōu)點(diǎn),但是我們一般開發(fā)Web應(yīng)用的時(shí)候不會(huì)采用這種方式,因?yàn)槭紫扔蛎杀颈容^高,開發(fā)一個(gè)Locale就需要一個(gè)域名,而且往往統(tǒng)一名稱的域名不一定能申請(qǐng)的到,其次我們不愿意為每個(gè)站點(diǎn)去本地化一個(gè)配置,而更多的是采用url后面帶參數(shù)的方式,請(qǐng)看下面的介紹。
目前最常用的設(shè)置Locale的方式是在URL里面帶上參數(shù),例如www.asta.com/hello?locale=zh或者www.asta.com/zh/hello。這樣我們就可以設(shè)置地區(qū):i18n.SetLocale(params["locale"])
。
這種設(shè)置方式幾乎擁有前面講的通過域名設(shè)置Locale的所有優(yōu)點(diǎn),它采用RESTful的方式,以使得我們不需要增加額外的方法來處理。但是這種方式需要在每一個(gè)的link里面增加相應(yīng)的參數(shù)locale,這也許有點(diǎn)復(fù)雜而且有時(shí)候甚至相當(dāng)?shù)姆爆?。不過我們可以寫一個(gè)通用的函數(shù)url,讓所有的link地址都通過這個(gè)函數(shù)來生成,然后在這個(gè)函數(shù)里面增加locale=params["locale"]
參數(shù)來緩解一下。
也許我們希望URL地址看上去更加的RESTful一點(diǎn),例如:www.asta.com/en/books(英文站點(diǎn))和www.asta.com/zh/books(中文站點(diǎn)),這種方式的URL更加有利于SEO,而且對(duì)于用戶也比較友好,能夠通過URL直觀的知道訪問的站點(diǎn)。那么這樣的URL地址可以通過router來獲取locale(參考REST小節(jié)里面介紹的router插件實(shí)現(xiàn)):
mux.Get("/:locale/books", listbook)
在一些特殊的情況下,我們需要根據(jù)客戶端的信息而不是通過URL來設(shè)置Locale,這些信息可能來自于客戶端設(shè)置的喜好語言(瀏覽器中設(shè)置),用戶的IP地址,用戶在注冊(cè)的時(shí)候填寫的所在地信息等。這種方式比較適合Web為基礎(chǔ)的應(yīng)用。
客戶端請(qǐng)求的時(shí)候在HTTP頭信息里面有Accept-Language
,一般的客戶端都會(huì)設(shè)置該信息,下面是Go語言實(shí)現(xiàn)的一個(gè)簡單的根據(jù)Accept-Language
實(shí)現(xiàn)設(shè)置地區(qū)的代碼:
AL := r.Header.Get("Accept-Language")
if AL == "en" {
i18n.SetLocale("en")
} else if AL == "zh-CN" {
i18n.SetLocale("zh-CN")
} else if AL == "zh-TW" {
i18n.SetLocale("zh-TW")
}
當(dāng)然在實(shí)際應(yīng)用中,可能需要更加嚴(yán)格的判斷來進(jìn)行設(shè)置地區(qū)
IP地址
另一種根據(jù)客戶端來設(shè)定地區(qū)就是用戶訪問的IP,我們根據(jù)相應(yīng)的IP庫,對(duì)應(yīng)訪問的IP到地區(qū),目前全球比較常用的就是GeoIP Lite Country這個(gè)庫。這種設(shè)置地區(qū)的機(jī)制非常簡單,我們只需要根據(jù)IP數(shù)據(jù)庫查詢用戶的IP然后返回國家地區(qū),根據(jù)返回的結(jié)果設(shè)置對(duì)應(yīng)的地區(qū)。
用戶profile
當(dāng)然你也可以讓用戶根據(jù)你提供的下拉菜單或者別的什么方式的設(shè)置相應(yīng)的locale,然后我們將用戶輸入的信息,保存到與它帳號(hào)相關(guān)的profile中,當(dāng)用戶再次登陸的時(shí)候把這個(gè)設(shè)置復(fù)寫到locale設(shè)置中,這樣就可以保證該用戶每次訪問都是基于自己先前設(shè)置的locale來獲得頁面。
通過上面的介紹可知,設(shè)置Locale可以有很多種方式,我們應(yīng)該根據(jù)需求的不同來選擇不同的設(shè)置Locale的方法,以讓用戶能以它最熟悉的方式,獲得我們提供的服務(wù),提高應(yīng)用的用戶友好性。