原文地址: https://www.sitepoint.com/localization-demystified-understanding-php-intl/
大多數應用程式執行場可以識別類似處理文本,日期,時區等的操作。而 PHP Intl 的擴充功能可提供一個良好的 API ,用以串連廣為人知的 ICU 庫的功能。
安裝
此擴充功能預設安裝在 PHP 5.3 及以上的版本,你可以通過以下命令進行尋找:
php -m | grep 'intl'
如果此擴充功能不存在,你可以按照 安裝指南 手動進行安裝。如果你使用 Ubuntu,你可以直接使用以下命令安裝:
sudoapt-getupdatesudoapt-getinstallphp5-intl
如果你使用的是 PHP 7,你需要添加 PPA ( ppa:ondrej/php ),升級你的系統並且安裝擴充功能 Intl。
# 添加 PPAsudoadd-apt-repositoryppa:ondrej/php-7.0# 升級索引庫sudoapt-getupdate# 安裝擴充功能sudoapt-getinstallphp7.0-intl
訊息格式化
大多數現代化應用在搭建的時候非常注意本地。有時候,這些訊息是一個簡單的擁有變數預留位置的字串,有時卻是一個複雜的多元化的字串。
簡單資訊
我們會從一個包含預留位置的簡單資訊開始。預留位置是被封閉在花括弧中的字元。這裡有一個樣本:
var_dump( MessageFormatter::formatMessage( "en_US", "I have {0, number, integer} apples.", [ 3 ] )); // output string(16) "I have 3 apples."
傳遞提要給 MessageFormatter::formatMessage 的類函數如下:
預留位置 {0, number, integer} 會鍵入一個數——整數作為該資料庫陣列的第一個項目(看看下面列出選項的表格)我們還可以在預留位置中使用具名引數。下面的樣本會輸出同樣的結果。
var_dump( MessageFormatter::formatMessage( "en_US", "I have {number_apples, number, integer} apples.", [ 'number_apples' => 3 ] ));
不同的語言有不同的數字寫法,比如阿拉伯語、印度語等等。
先前的樣本指向 en_US 環境,讓我們換成 ar 環境並看看有什麼不同。
var_dump( MessageFormatter::formatMessage( "ar", "I have {number_apples, number, integer} apples.", [ 'number_apples' => 3 ] )); string(17) "I have ٣ apples."
讓我們再換成孟加拉語情景( bn ).
var_dump( MessageFormatter::formatMessage( "bn", "I have {number_apples, number, integer} apples.", [ 'number_apples' => 3 ] )); string(18) "I have ৩ apples."
到目前為止,我們只說明了數字。現在讓我們看看其他可以使用的類型。
$time = time();var_dump( MessageFormatter::formatMessage( "en_US", "Today is {0, date, full} - {0, time}", array( $time )) ); string(47) "Today is Wednesday, April 6, 2016 - 11:21:47 PM"
var_dump( MessageFormatter::formatMessage( "en_US", "duration: {0, duration}", array( $time )) ); string(23) "duration: 405,551:27:58"
我們也可以表示分數。
var_dump( MessageFormatter::formatMessage( "en_US", "I have {0, spellout} apples", array( 34 )) ); string(25) "I have thirty-four apples"
這對不同的語言環境也適用。
var_dump( MessageFormatter::formatMessage( "ar", "لدي {0, spellout} تفاحة", array( 34 )) ); string(44) "لدي أربعة و ثلاثون تفاحة"
多元化
本地化應用程式的一個重要組成部分是管理多元資訊使得使用者介面儘可能直觀。上面蘋果的樣本就能說明這一點。下面是這個樣本中的資訊表現:
- (number_apples = 0) : 沒有蘋果。
- (number_apples = 1) : 一個蘋果。
- (number_apples > 1) : 多個蘋果。
var_dump( MessageFormatter::formatMessage( "en_US", 'I have {number_apples, plural, =0{no apples} =1{one apple} other{# apples}}', array('number_apples' => 10)) );
// number_apples = 0string(16) "I have no apples" // number_apples = 1string(16) "I have one apple" // number_apples = 10string(16) "I have 10 apples"
這種文法真的很簡單直接,並且大多數包都包含這種文法。跟多細節請見 此檔案 。
{data, plural, offsetValue =value{message}... other{message}}
- data :價值指數
- plural :事件參數類型
- offsetValue :可選的( offset:value )。它從值中減去位移量。
- =value{message} :測試等價性,資訊在花括弧之內。我們可以重複多次 ( =0{no apples} =1{one apple} =2{two apple} )。
- other{message} :預設情況,比如在 switch - case 聲明。 # 符號可用於鍵入 data 值。
選項
有時候,我們需要列出每一個範圍的不同資訊。比如下面的樣本:
var_dump( MessageFormatter::formatMessage( "en_US", 'The value of {0,number} is {0, choice, 0 # between 0 and 19 | 20 # between 20 and 39 | 40 # between 40 and 59 | 60 # between 60 and 79 | 80 # between 80 and 100 | 100 < more than 100 }', array(60)) ); string(38) "The value of 60 is between 60 and 79 "
argType 在這裡是為 choice 設定的,文法如下:
{value, choice, choiceStyle}
ICU 檔案 的官方定義如下:
choiceStyle = numberseparatormessage ('|' numberseparatormessage)* number = normal_number | ['-'] ∞ (U+221E, infinity)normal_number = double value (unlocalizedASCIIstring) separator = less_than | less_than_or_equalless_than = '<'less_than_or_equal = '#' | ≤ (U+2264)
注意: ICU 開發人員不鼓勵使用選擇類型。
選擇項
有時我們需要選擇選項UI組件。設定檔頁使用這種方法根據使用者的性別等等更新 UI 資訊。這裡有一個例子:
var_dump( MessageFormatter::formatMessage( "en_US", "{gender, select, ". "female {She has some apples} ". "male {He has some apples.}". "other {It has some apples.}". "}", array('gender' => 'female')) );string(19) "She has some apples"
模式定義如下:
{value, select, selectStyle} // selectStyleselectValue {message} (selectValue {message})*
message 提要會包括類似選項和複數的其他模式。下一個部分會解釋一個被我們結合了多個模式的例子。
複雜情況
到目前為止,我們已經看過例如選擇、多元化等等的簡單樣本。但很多情況會複雜的多。 ICU 文檔 有一個很好的例子來說明這一點。為了便於理解,我們一段一段來看。
var_dump( MessageFormatter::formatMessage( "en_US", "{gender_of_host, select, ". "female {She has a party} ". "male {He has some apples.}". "other {He has some apples.}". "}", array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )) );
這是我們之前用的一個相同的例子,不同於之前使用簡單資訊,我們依賴 num_guests 值定製了下(討論的是多元化的案例)。
var_dump( MessageFormatter::formatMessage( "en_US", "{gender_of_host, select, ". "female {". "{num_guests, plural, offset:1 ". "=0 {{host} does not have a party.}". "=1 {{host} invites {guest} to her party.}". "=2 {{host} invites {guest} and one other person to her party.}". "other {{host} invites {guest} and # other people to her party.}}}". "male {He has some apples.}". "other {He has some apples.}}", array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )) );
需要注意我們使用了 offset:1 從 num_guests 中移除一個 guest。
string(53) "Hanae invites Younes and 4 other people to her party."
下面是樣本的完整段。
var_dump( MessageFormatter::formatMessage( "en_US", "{gender_of_host, select, ". "female {". "{num_guests, plural, offset:1 ". "=0 {{host} does not have a party.}". "=1 {{host} invites {guest} to her party.}". "=2 {{host} invites {guest} and one other person to her party.}". "other {{host} invites {guest} and # other people to her party.}}}". "male {". "{num_guests, plural, offset:1 ". "=0 {{host} does not have a party.}". "=1 {{host} invites {guest} to his party.}". "=2 {{host} invites {guest} and one other person to his party.}". "other {{host} invites {guest} and # other people to his party.}}}". "other {". "{num_guests, plural, offset:1 ". "=0 {{host} does not have a party.}". "=1 {{host} invites {guest} to their party.}". "=2 {{host} invites {guest} and one other person to their party.}". "other {{host} invites {guest} and # other people to their party.}}}}", array('gender_of_host' => 'female', "num_guests" => 5, 'host' => "Hanae", 'guest' => 'Younes' )) );
改變客人的數量來測試所有的資訊類型:
// num_guests = 2string(55) "Hanae invites Younes and one other person to her party." // num_guests = 1string(34) "Hanae invites Younes to her party." // num_guests = 0string(28) "Hanae does not have a party."
訊息解析
對於解析資訊沒有太多可以說;我們使用之前的模式從輸出資訊中來格式化額外資訊。
$messageFormater = new MessageFormatter("en_US", 'I have {0, number}');var_dump( $messageFormater->parse("I have 10 apples") ); array(1) { [0]=> int(10)}
查看 文檔 以擷取更多關於資訊解析的內容。
結論
在這篇介紹性的文章中,我們瞭解了使用 PHP Intel 的擴充功能來本地化我們的資訊。接下來的部分會涉及格式化數字和日期,以及日曆的使用。如果你對以上內容有任何疑惑,請給我們留言。