國際化 (I18N) ==================== 國際化 (I18N) 是指設計一種應用程式軟體的過程,這種軟體無需做太大的工程改變就能適應不同的語言和地區的需要。 對 Web 應用程式來說,國際化尤為重要,因為潛在的使用者可能來自世界的各個角落。 Yii 在若干方面提供了對 I18N 的支援 - 它為每種可能的語言和變數提供了在地化資料。 - 它提了供訊息和檔案的翻譯服務。 - 它提供了基於在地化的日期和時間格式。 - 它提供了基於本地話的數字格式。 在下面的小節中,我們將對以上幾方面進行詳細說明。 區域和語言 ------------------- 區域是一系列參數,它定義了使用者的語言、使用者所在國家以及使用者所有想要在他們的界面中看到的特殊參數。 它通常由一個包含了語言 ID 和區域 ID 的 ID 來識別。例如, ID `en_US` 表示英語區域和美國。 為保持一致性,Yii 中所有的區域 ID 被規範為小寫的 `語言 ID` 或 `語言 ID_地區 ID`(例如 `en`, `en_us`)。 區域資料由一個 [CLocale] 實體表示。它提供了基於區域的訊息,包括貨幣符號,數字符號, 日期和時間格式以及日期相關的名稱。由於語言訊息已經由區域 ID 實現,因此 [CLocale] 不再提供。 同理,我們通常會變換地使用詞語「區域」和「語言」。 通過一個區域 ID,就可以通過 `CLocale::getInstance($localeID)` 或者 `CApplication::getLocale($localeID)` 取得相應的 [CLocale] 實體。 > Info|訊息: Yii 包含幾乎所有語言和區域的區域化資料。 這些資料來自於 [Common Locale Data Repository](http://unicode.org/cldr/) (CLDR)。在每個區域中, 只提供了 CLDR 中的部分資料,因為原始的 CLDR 資料中包含了大量不太常用的訊息。從版本 1.1.0 起, 使用者也可以使用他們自定義的區域資料。只需要配置 [CApplication::localeDataPath] 屬性為包含了自定義區域資料的目錄即可。 請參考位於 `framework/i18n/data` 目錄中的檔案建立自定義的區域資料檔案。 在一個 Yii 應用程式程式中,我們區分了它的 [目標語言(target language)|CApplication::language] 和 [來源語言(source language)|CApplication::sourceLanguage]。目標語言是應用程式程式的目標使用者的語言(區域), 而來源語言是指在應用程式中所使用的語言(區域)。國際化僅會在這兩種語言不同的情況下發生。 你可以設定 [應用程式設定檔](/doc/guide/basics.application#application-configuration) 中的 [目標語言|CApplication::language] ,或者在發生國際化之前動態設定此參數。 > Tip|提示: 有時候,我們想要設置目標語言為使用者所使用的語言(就是在使用者的瀏覽器選項中指定的那個)。 只需使用 [CHttpRequest::preferredLanguage] 就可以取得到使用者設定的語言。 翻譯 ----------- 在 I18N 中用到的最多的可能就是翻譯了,包括 訊息翻譯 和 視圖翻譯。 前者將一條文字訊息翻譯為期望的語言,後者將整合檔案翻譯為期望的語言。 一個翻譯請求包含要被翻譯的對象,物件所用的來源語言,和物件所需要翻譯到的目標語言。 在 Yii 中,來源語言預設為 [應用程式來源語言|CApplication::sourceLanguage] 而目標語言預設為 [應用程式語言|CApplication::language]。 如果兩者語言相同,翻譯將不會發生。 ### 訊息翻譯 訊息翻譯是通過調用 [Yii::t()|YiiBase::t] 實現的。此方法會將訊息從 [來源語言|CApplication::sourceLanguage] 翻譯為 [目標語言|CApplication::language]。 當翻譯一條訊息時,必須指定它的分類,因為一條訊息在不同的分類或上下文中可能會有 不同的翻譯。分類 `yii` 被保留為僅限 Yii 框架核心使用。 訊息可以包含參數佔位符號,它們將會在調用 [Yii::t()|YiiBase::t] 時被實際的參數值取代。 例如,下面的訊息翻譯請求將會替換原始訊息中的 `{alias}` 佔位符號為實際的別名(alias) 值。 ~~~ [php] Yii::t('app', 'Path alias "{alias}" is redefined.', array('{alias}'=>$alias)) ~~~ > Note|注意: 要翻譯的訊息必須是常量字串。它們不能包含可能會改變訊息內容的變數 (例如 `"Invalid {$message} content."`)。如果一條訊息需要通過一些參數改變,請使用 參數佔位符號。 翻譯過的訊息會儲存在一個叫做 *訊息來源* 的庫中。 訊息來源是一個 [CMessageSource] 或其子類別的實體。當 [Yii::t()|YiiBase::t] 被調用時, 它將從訊息來源中查找相應的訊息,如果找到了,就會返回翻譯後的版本。 Yii 含有如下幾種訊息來源。你也可以擴充 [CMessageSource] 建立自己的訊息來源類型。 - [CPhpMessageSource]: 訊息的翻譯儲存在一個 PHP 的鍵值對陣列中。 原始訊息為鍵,翻譯後的訊息為值。每個陣列表示一個特定訊息分類的翻譯,分別儲存在不同的 PHP 腳本檔案中,檔案名即分類別名。 針對同一種語言的 PHP 翻譯檔案儲存在同一個以區域 ID 命名的目錄中。而所有的這些目錄位於 [basePath|CPhpMessageSource::basePath] 指定的目錄中。 - [CGettextMessageSource]: 訊息的翻譯儲存在 [GNU Gettext](http://www.gnu.org/software/gettext/) 檔案中。 - [CDbMessageSource]: 訊息的翻譯儲存在資料庫的表中。更多細節,請查看 [CDbMessageSource] 的 API 檔案。 訊息來源是作為一個 [應用程式程式元件](/doc/guide/basics.application#application-component) 載入的。 Yii 預定義了一個名為 [messages|CApplication::messages] 的應用程式程式元件以儲存使用者程式中用到的訊息。 預設情況下,此訊息來源的類型是 [CPhpMessageSource] ,而儲存這些 PHP 翻譯檔案的目錄是 `protected/messages`。 總體來說,要實現訊息翻譯,需要執行如下幾步: 1. 在合適的位置調用 [Yii::t()|YiiBase::t] ; 2. 以 `protected/messages/LocaleID/CategoryName.php` 的格式建立 PHP 翻譯檔案。 每個檔案簡單的返回一個訊息翻譯陣列。 注意,這是假設你使用預設的 [CPhpMessageSource] 儲存翻譯訊息。 3. 配置 [CApplication::sourceLanguage] 和 [CApplication::language]。 > Tip|提示: 使用 [CPhpMessageSource] 作為訊息來源時,Yii 中的 `yiic` 工具可用於管理訊息翻譯。 它的 `message` 命令可以自動從所選的源檔案中擷取要翻譯的訊息,並在需要時將其合併為現存的翻譯。 關於使用 `message` 命令的更多訊息,請執行 `yiic help message`。 從版本 1.0.10 起,當使用 [CPhpMessageSource] 管理訊息來源時, 擴充類別(例如一個 widget 小工具,一個模組)中的訊息可以以一種特殊的方式管理並使用。 具體來說,如果一條訊息屬於一個類別名為 `Xyz` 的擴充,那麼分類的名字可以以 `Xyz.categoryName` 的格式指定。 相應的訊息檔案就是 `BasePath/messages/LanguageID/categoryName.php` ,其中 `BasePath` 是指包含此擴充類別檔案的那個目錄。 當使用 `Yii::t()` 翻譯一條擴充訊息時,需要使用如下格式: ~~~ [php] Yii::t('Xyz.categoryName', '要翻譯的訊息'); ~~~ 從 1.0.2 起,Yi 增加了對 [choice format|CChoiceFormat] 的支援。Choice format 是指選擇按照一個給定數字的值選擇一條翻譯。例如,在英語中,視不同的數量,單詞 'book' 可以有一個單數形式或者一個複數形式。而在其他語言中, 這個詞可能就沒有不同的形式(例如漢語)或者有更複雜的複數規則(例如俄語)。 Choice format 以一種簡單而又高效的方式解決了這個問題。 要使用 choice format,翻譯的訊息必須包含一個由 `|` 分割的 「表達式-訊息」 對序列。如下所示: ~~~ [php] 'expr1#message1|expr2#message2|expr3#message3' ~~~ 其中 `exprN` 表示一個有效的 PHP 表達式,它會計算出一個布爾型的值,以確定相應的訊息是否應該被返回。 只有第一個返回值為 true 的表達式對應的訊息會被返回。 一個表達式可以包含一個特殊的變數 `n` (注意,它不是 `$n`),它帶有通過第一個訊息參數傳遞的數字的值。 例如,假設有如下一條翻譯訊息: ~~~ [php] 'n==1#one book|n>1#many books' ~~~ 而我們在調用 [Yii::t()|YiiBase::t] 時在參數陣列中傳遞了數字值 2 , 我們就會得到 `many books` 作為最終的翻譯訊息。 作為一種方便寫法,如果一個表達式是一個數字,它將被視為等同於 `n==Number`。因此,上面的翻譯訊息也可以寫為如下格式: ~~~ [php] '1#one book|n>1#many books' ~~~ ### 檔案翻譯 檔案翻譯是通過調用 [CApplication::findLocalizedFile()] 完成的。 給定一個所要翻譯的檔案的路徑,此方法就會在 `區域 ID` 子目錄中查找相同檔案名的檔案。 如果找到了,就會返回此檔案的路徑;否則,將返回原始檔案的路徑。 檔案翻譯主要用於呈現一個視圖。 當在控制器或小工具中調用任一呈現方法時,視圖檔案將會被自動翻譯。例如,如果 [目標語言|CApplication::language] 是 `zh_cn` 而 [來源語言|CApplication::sourceLanguage] 是 `en_us`,呈現一個名為 `edit` 的視圖時,程式將會查找 `protected/views/ControllerID/zh_cn/edit.php` 視圖檔案。 如果此檔案找到,就會通過此翻譯版本呈現。否則,就會使用檔案 `protected/views/ControllerID/edit.php` 呈現。 檔案翻譯也可以用於其他目的,例如,顯示一個翻譯過的圖片,或者載入一個基於區域的資料檔案。 日期和時間格式化 ------------------------ 日期和時間在不同的國家和地區通常會有不同的格式。 日期和時間格式和的任務就是產生一個符合指定區域格式的日期或時間字串。 為實現此目的,Yii 提供了[CDateFormatter]。 每個 [CDateFormatter] 實體關聯到一個目標區域。要取得關聯到整個應用程式程式的目標區域的格式器(formatter), 只需簡單的存取 應用程式程式的 [dateFormatter|CApplication::dateFormatter] 屬性。 [CDateFormatter] 類主要提供了兩個方法以格式化 UNIX 時間戳記。 - [format|CDateFormatter::format]: 此方法可通過一個自定義的模式格式化給定的 UNIX 時間戳記為一個字串 (例如 `$dateFormatter->format('yyyy-MM-dd',$timestamp)`)。 - [formatDateTime|CDateFormatter::formatDateTime]: 此方法通過一個在目標區域資料中預定義的模式格式化給定的 UNIX 時間戳記為一個字串 (例如日期的 `short` 格式,時間的 `long` 格式)。 數字格式化 ----------------- 與日期和時間類似,數字在不同的國家或地區之間也可能有不同的格式。 數字格式化包括十進制格式化,貨幣格式化和百分比格式化。Yii 提供了 [CNumberFormatter] 以完成這些任務。 要取得關聯到整個應用程式程式的目標區域的格式器(formatter), 只需簡單的存取 應用程式程式的 [numberFormatter|CApplication::numberFormatter] 屬性。 [CNumberFormatter] 提供的如下方法可以用於格式化 integer 或 double 值 - [format|CNumberFormatter::format]: 此方法通過一個自定的模式格式化給定的數字為一個字串 (例如 `$numberFormatter->format('#,##0.00',$number)`)。 - [formatDecimal|CNumberFormatter::formatDecimal]: 此方法通過在目標區域資料中預定的十進制模式格式化給定的數字。 - [formatCurrency|CNumberFormatter::formatCurrency]: 此方法使用目標區域資料中預定的貨幣模式格式化給定的數字。 - [formatPercentage|CNumberFormatter::formatPercentage]: 此方法使用目標區域資料中預定的百分比模式格式化給定的數字。
$Id$