PHP中針對區域語言标記資訊的操作
相信大家對 zh_CN 這個東西絕對不會陌生,不管是 PHP 中,還是在我們的網頁上,都會見到它的身影。其實這就是指定我們的顯示編碼是什麼國家或者地區的,使用何種語言。對于這種區域語言的标記來說,PHP 中也有很多好玩的内容。今天,我們要學習的 Locale 類就是操作區域語言相關内容的,它無法被執行個體化,所有全部功能方法都是靜态的。
擷取及設定目前的區域語言資訊
首先就是我們可以動态地擷取和設定相應的區域語言資訊。
// # echo $LANG;
// en_US.UTF-8
// php.ini
// intl.default_locale => no value => no value
echo Locale::getDefault(), PHP_EOL; // en_US_POSIX
ini_set('intl.default_locale', 'zh_CN');
echo Locale::getDefault(), PHP_EOL; // zh_CN
Locale::setDefault('fr');
echo Locale::getDefault(), PHP_EOL; // fr
複制
預設情況下,使用 getDefault() 方法獲得的是 php.ini 檔案中的 intl.default_locale 配置的内容。如果在 php.ini 中也沒有配置的話,就會取作業系統的 $LANG 值裡面的内容,也就是我們上面例子中輸出的 en_US_POSIX ,POSIX 表示的就是來自作業系統的配置。
使用 ini_set() 直接修改 ini 的配置或者使用 setDefault() 方法都是可以動态地修改目前的區域語言設定的。
關于語言标記的規則
在繼續學習下面的内容之前,我們先來學習一下語言标記的規範。對于大多數人來說,可能隻接觸過 en_US 、 zh_CN 這類的标記,但其實它的完整定義是很長的,隻是我們使用這種簡寫的方式時,很多内容會以預設的形式提供。完整的标記規則是:
language-extlang-script-region-variant-extension-privateuse
語言文字種類-擴充語言文字種類-書寫格式-國家和地區-變體-擴充-私有
複制
也就是說,我們的 zh_CN 可以這樣寫:
zh-cmn-Hans-CN-Latn-pinyin
複制
代表的是:zh 語言文字種類,Hans 書寫格式為簡體中文,cmn 國語,CN 國家和地區,Latn 變體拉丁字母,pinyin 變體拼音。
是不是感覺突然一下這麼簡單的東西一下子變得高大上了。另外,zh- 這個字首現在已經不是推薦使用的了,zh- 現在已經不是語言 code 了,而是 macrolang 也就是宏語言,我們直接使用 cmn 、 yue(粵語)、wuu(吳語)、hsn(湘語,湖南話)這類的就可以當做 language 來使用了。是以,上面的那一段也可以這麼寫:
cmn-Hans-CN-Latn-pinyin
複制
在上篇文章中,我們講 NumberFormatter 時說過可以直接獲得中文的數字格式的輸出,現在我們想要繁體的結果呢?很簡單,加上 Hant 辨別書寫格式為繁體中文即可。
關于語言标記規則的内容,大家可以看看文末知乎的參考連結,介紹的更為詳盡。
$fmt = new NumberFormatter('zh-Hant', NumberFormatter::SPELLOUT);
echo $fmt->format(1234567.891234567890000), PHP_EOL;
// 一百二十三萬四千五百六十七點八九一二三四五六七九
複制
擷取指定語言标記規則中的各類資訊
學習了語言标記的規則之後能幹什麼呢?Locale 類最主要的功能就在于可以分析擷取這些屬性資訊。
單獨擷取各種屬性資訊
echo Locale::getDisplayLanguage('cmn-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // cmn
echo Locale::getDisplayLanguage('zh-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 中文
echo Locale::getDisplayName('cmn-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // cmn(簡體,中國,LATN_PINYIN)
echo Locale::getDisplayName('zh-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 中文(簡體,中國,LATN_PINYIN)
echo Locale::getDisplayRegion('cmn-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 中國
echo Locale::getDisplayRegion('zh-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 中國
echo Locale::getDisplayScript('cmn-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 簡體中文
echo Locale::getDisplayScript('zh-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // 簡體中文
echo Locale::getDisplayVariant('cmn-Hans-Latn-pinyin', 'zh_CN'), PHP_EOL; // LATN_PINYIN
echo Locale::getDisplayVariant('zh-Hans-CN-Latn-pinyin', 'zh_CN'), PHP_EOL; // LATN_PINYIN
複制
我們分别使用兩種标記方式來測試代碼,可以看到結果的對比。
- getDisplayLanguage() 方法用于擷取顯示的語言資訊,也就是規則中的 language 内容。
- getDisplayName() 方法用于擷取标準的語言名稱,可以看到内容更加地豐富。
- getDisplayRegion() 方法很明顯地就是擷取到了國家資訊。
- getDisplayScript() 擷取到的是書寫格式的資訊。
- getDisplayVariant() 擷取到的就是變體資訊
批量擷取屬性資訊
當然,我們也可以批量地擷取到一些語言相關的資訊。
$arr = Locale::parseLocale('zh-Hans-CN-Latn-pinyin');
if ($arr) {
foreach ($arr as $key => $value) {
echo "$key : $value ", PHP_EOL;
}
}
// language : zh
// script : Hans
// region : CN
// variant0 : LATN
// variant1 : PINYIN
複制
使用 parseLocale() 方法就能擷取到一個語言标記中的各類資訊并儲存在數組中,鍵為标記規則名,值為對應的内容,看看是不是和我們上面介紹的内容是一樣的。
擷取所有變體資訊
從上面的代碼中可以看出,我們有兩個變體資訊,這個也可以通過一個 getAllVariants() 方法來直接獲得語言标記中的所有變體資訊的數組。
$arr = Locale::getAllVariants('zh-Hans-CN-Latn-pinyin');
var_export($arr);
echo PHP_EOL;
// array (
// 0 => 'LATN',
// 1 => 'PINYIN',
// )
複制
擷取字元集相關資訊
echo Locale::canonicalize('zh-Hans-CN-Latn-pinyin'), PHP_EOL; // zh_Hans_CN_LATN_PINYIN
$keywords_arr = Locale::getKeywords('zh-cn@currency=CMY;collation=UTF-8');
if ($keywords_arr) {
foreach ($keywords_arr as $key => $value) {
echo "$key = $value", PHP_EOL;
}
}
// collation = UTF-8
// currency = CMY
複制
canonicalize() 方法用于規範化地顯示語言标記資訊,可以看到它把我們的中劃線變成了下劃線并且将後面的各種屬性轉成了大寫,這就是規範化的寫法。不過對于我們的應用程式和網頁來說中劃線以及大小寫都是支援的。當然,大家最好還是按照标準的寫法來定義。
getKeywords() 用于從 @ 符号後擷取語言相關的資訊屬性,比如我們定義的這個 zh-cn ,然後定義了它的貨币為 CMY ,字元集為 UTF-8 ,直接通過 getKeywords() 就能擷取貨币和字元集屬性的數組。
比對判斷語言标記資訊
對于語言标記來說,我們可以判斷給定的兩個标記之間是否互相比對,比如:
echo (Locale::filterMatches('cmn-CN', 'zh-CN', false)) ? "Matches" : "Does not match", PHP_EOL;
echo (Locale::filterMatches('zh-CN-Latn', 'zh-CN', false)) ? "Matches" : "Does not match", PHP_EOL;
複制
當然,我們也可以使用另一個 lookup() 方法來确定給定的一系列語言标記哪個與指定的标記最接近。
$arr = [
'zh-hans',
'zh-hant',
'zh',
'zh-cn',
];
echo Locale::lookup($arr, 'zh-Hans-CN-Latn-pinyin', true, 'en_US'), PHP_EOL; // zh_hans
複制
生成一個标準規則的語言标記
既然能夠擷取各類語言标記的屬性資訊,那麼我們能不能生成一個标準的語言标記内容呢?
$arr = [
'language' => 'en',
'script' => 'Hans',
'region' => 'CN',
'variant2' => 'rozaj',
'variant1' => 'nedis',
'private1' => 'prv1',
'private2' => 'prv2',
];
echo Locale::composeLocale($arr), PHP_EOL; // en_Hans_CN_nedis_rozaj_x_prv1_prv2
複制
沒錯,composeLocale() 方法根據一個數組格式的内容,就可以生成一個完整标準的語言标記格式内容。當然,這個測試代碼是亂寫的,相當于是一個 en_CN 的标記,正常不會這麼寫的。
acceptFromHttp 從請求頭中讀取語言資訊
另外,Locale 類中還提供了一個從 header 頭中的 Accept Language 中擷取客戶浏覽器語言資訊的方法。
// Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
echo Locale::acceptFromHttp('en_US'), PHP_EOL; // en_US
echo Locale::acceptFromHttp('en_AU'), PHP_EOL; // en_AU
echo Locale::acceptFromHttp('zh_CN'), PHP_EOL; // zh
echo Locale::acceptFromHttp('zh_TW'), PHP_EOL; // zh
複制
不過從測試的結果來說,其實它隻需要一個字元串參數就可以了,是以我們在指令行也可以測試它。需要注意的是,對于中文來說,它不能傳回區域資訊,隻能傳回 language 資訊。
總結
這個 Locale 類相關的内容其實在筆者日常的開發中基本沒怎麼接觸過,但相信不少做跨境項目的同學會多少對它們會有一些了解。隻能說業務接觸不到,那就隻能先簡單地學習一下看看了,同樣地,以後大家遇到相關的業務需求時,别忘了它們的存在哦!
測試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/5.PHP中針對區域語言标記資訊的操作.php
參考文檔:
https://www.php.net/manual/zh/class.locale.php
https://www.zhihu.com/question/20797118/answer/63480740