Revel使用文本文件提供國際化翻譯支持。Revel 支持語言翻譯文件化, 自動區域查詢, cookie重寫、嵌套的消息與參數。
#### 詞匯表
* Locale(語言環境): 包含?*語言*?和?*區域*兩個部分,指示用戶的語言偏好,例如?`en-US`。
* Language(語言): locale 的語言部分, 例如?`en`。 語言標識符請參考?[ISO 639-1 codes](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)。
* Region(區域): locale 的區域部分, 例如?`US`。 區域標識符請參考?[ISO 3166-1 alpha-2 codes](http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)。
## 示例程序
Revel 處理消息文件和國際化的方法與其他框架類似。如果你想立馬上手, 可以參考示例程序?`revel/samples/i18n`,里面包含所有的基礎知識。
## 消息文件
國際化消息在消息文件中定義。這些消息在渲染視圖模板(或程序的其他地方)時使用。當創建新的消息文件時,需要遵循幾個規則:
* 所有的消息文件應存放在應用程序根目錄的`messages`目錄中。
* 文件擴展名與?*language*?一致,并且應為?[ISO 639-1 code](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)。
* 消息文件應該是 UTF-8 編碼。雖然不是強制規定, 最好還是遵循這個約定。
* 消息文件必須是?[goconfig 文件](https://github.com/revel/config)?支持多有的 goconfig 特性
### 組織消息文件
消息文件的文件名??沒有任何限制; 只要擴展名合法就行。每種語言的文件數量也沒有限制。當應用程序啟動時,Revel會解析`messages`語言目錄中所有的擴展名合法的消息文件,并根據語言將它們合并。這意味著你可以自由組織你的消息文件。
例如,您可能希望采取傳統的方法,在一個文件中定義所有的:
~~~
/app
/messages
messages.en
messages.fr
...
~~~
或者是為每種語言創建多個文件,并根據分類組織他們:
~~~
/app
/messages
labels.en
warnings.en
labels.fr
warnings.fr
...
~~~
**重要注意事項:**?在同一語言的多個文件中,雖然技術上可以定義相同的消息key,但是這將導致不可預知的行為。當每種語言定義了多個文件時,請注意保持您的key唯一,這樣文件合并后,key將不會被覆蓋!
### 消息 key 和 值
消息文件是一個?[goconfig 文件](https://github.com/revel/goconfig)。這意味著,消息應按照key-value格式定義:
~~~
key=value
~~~
舉個栗子:
~~~
greeting=Hello
greeting.name=Rob
greeting.suffix=, welcome to Revel!
~~~
### 段
goconfig 文件被分成多個?*sections*.?*默認的段*?總是存在, 并且包含未指定段時定義的消息。例如:
~~~
key=value
[SECTION]
key2=value2
~~~
`key=value`?消息消息被隱式放置在默認段中,因為它沒有定義在一個指定的段中。
消息文件的所有消息應在定義默認的段中,除非它們是用于某個特定區域(見[Regions](http://gorevel.cn/docs/manual/i18n-messages.html#regions)獲取更多消息)。
**注意:**?段是?*goconfig*?功能.
### 區域
特定區域的消息應當在相同的段中定義。Region-specific messages should be defined in sections with the same name. 例如,假設我們要對所有講英語的用戶顯示?`"Hello"`, 對英國用戶顯示?`"Hey"`?,對講美國用戶顯示?`"Howdy"`。 為了做到這一點,我們可以定義下面的消息文件?`greeting.en`:
~~~
greeting=Hello
[GB]
greeting=Hey
[US]
greeting=Howdy
~~~
對于定義了英語 (`en`) 作為他們的首選語言時,Revel 會將`greeting`?解析成?`Hello`。只有在用戶的區域被明確定義的情況下,比如`en-GB`?或?`en-US`?,Revel 才會用對應段中的消息去解析?`greeting`。
**重要提示:**?如果定義了一個不合法的區域,技術上是允許的,但是它們永遠不會被解析。
### 引用 和 參數
#### 引用
文件中的消息也可以引用其他消息。這使得用戶可以從一個或多個其它的消息組成一個單一的消息。引用消息的語法是?`%(key)s`. 例如:
~~~
greeting=Hello
greeting.name=Rob
greeting.suffix=, welcome to Revel!
greeting.full=%(greeting)s %(greeting.name)s%(greeting.suffix)s
~~~
**注意:**
* 引用是?*goconfig*?的功能.
* 因為消息文件可以合并,多以只要它們被定義為同一種語言,就可以引用其他文件中的消息。
#### 參數
消息支持一個或多個參數。在消息中參數使用與?`fmt`?包相同的規則去解析。 例如:
~~~
greeting.name_arg=Hello %s!
~~~
參數按照給定的順序進行解析,參考?[解析消息](http://gorevel.cn/docs/manual/i18n-messages.html#resolving_messages).
## 解析客戶端語言環境(locale)
為了找出用戶喜歡的語言環境,Revel會在以下地方查找一個可用的語言環境:
1. 語言 cookie
對于每次請求,框架會查找應用程序配置 (`i18n.cookie`)。如果找到了,它的值被假定為當前的語言環境。當一個cookie已經發現,所有其他解析方法將被跳過。
2. `Accept-Language`?HTTP 頭
對于每次請求,Revel 會自動解析 HTTP 頭信息的?`Accept-Language`。其中的每個語言環境根據?[HTTP 規范](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)在當前`Request`實例中獲取和存儲。此信息用來為稍后的消息解析函數確定當前語言環境。
更多信息請參考?[Parsed Accept-Language HTTP header](http://gorevel.cn/docs/manual/i18n-messages.html#parsed_acceptlanguage_http_header).
3. 默認語言
當以上所有方法都沒有找到可用的客戶端語言環境時,框架將使用配置文件中定義的默認語言`i18n.default_language`。
如果有的消息解析失敗,則返回一個包含原始消息名的特殊格式的字符串。
**注意:**?`Accept-Language`?頭信息?**總是**?被解析并保存到當前?`Request`中, 即使它已經存在。在這種情況下,頭信息中的值即使從未被消息解析功能使用,但是仍可以在需要他們的時候使用。
### 檢查當前語言環境
應用程序可以從`Request`內部使用?`Request.Locale`?屬性訪問當前語言環境。例如:
~~~
func (c App) Index() revel.Result {
currentLocale := c.Request.Locale
c.Render(currentLocale)
}
~~~
在模板中, 就可以從?`renderArgs`?中的?`currentLocale`?變量中訪問當前語言環境。 例如:
~~~
<p>Current preferred locale: {{.currentLocale}}</p>
~~~
### 解析 Accept-Language HTTP 頭信息
如果程序需要訪問?`Accept-Language`?HTTP 頭信息, 可以從?`Controller`?實例的?`Request`中獲取。?`AcceptLanguages`?字段(`AcceptLanguage`實例的切片)包含所有從各自的頭信息中解析的值, 最合適的值是切片中的第一個。例如:
~~~
func (c App) Index() revel.Result {
// 獲取所有解析到的AcceptLanguage的字符串表示形式
c.RenderArgs["acceptLanguageHeaderParsed"] = c.Request.AcceptLanguages.String()
// 返回最合適AcceptLanguage實例
c.RenderArgs["acceptLanguageHeaderMostQualified"] = c.Request.AcceptLanguages[0]
c.Render()
}
~~~
更多信息請參考?[HTTP 規范](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4).
## 解析消息
消息可以在?*控制器*?或?*模板*中解析。
### 控制器
控制器中使用?`Message(message string, args ...interface{})`?函數使用當前語言環境解析消息:
~~~
func (c App) Index() revel.Result {
c.RenderArgs["controllerGreeting"] = c.Message("greeting")
c.Render()
}
~~~
### 模板
在模板中使用?*模板函數*?`msg`?解析當前語言環境的消息。例如:
~~~
<p>Greetings without arguments: {{msg . "greeting"}}</p>
<p>Greetings: {{msg . "greeting.full.name" "Tommy Lee Jones"}}</p>
~~~
**注意:**?`msg`?函數的簽名是?`msg . "message name" "argument" "argument"`. 如果沒有參數, 可以忽略。
## 配置
| 文件 | 選項 | 描述 |
| --- | --- | --- |
| `app.conf` | `i18n.cookie` | 語言cookie的名稱。應使用Revel cookie的前綴,以避免cookie名稱沖突。 |
| `app.conf` | `i18n.default_language` | 默認的語言環境,在沒有首選區域的情況下使用。 |