最近加入到新項目組負責前端技術預研和選型,其中涉及到一個熟悉又陌生的需求——國際化&本地化。熟悉的是以前的項目也玩過,陌生的是以前的實現僅僅停留在"有"的階段而已。趁着這個機會好好學習整理一下,爲後面的技術選型作準備。
本篇將於你們一塊兒挽起袖子擼代碼:)javascript
在實現本地化處理前,咱們起碼先要獲取Language tag吧?那麼獲取方式分爲兩類
1.直接獲取瀏覽器的Language tag信息
通常來講瀏覽器語言的版本標示着用戶所屬或所期待接收哪一種語言文化風俗的內容,因而經過如下函數獲取瀏覽器的語言信息便可獲取language-taghtml
function getLang(){ return navigator.language || navigator.browserLanguage }
2.用戶選擇Language tag信息
你們在瀏覽蘋果官網時也會發現如下界面,讓咱們自行選擇language-tag。
注意蘋果官網採用的是Server-driven Negotiation的機制提供本地化功能,和本篇主打前端實現有所區別。前端
最適當的設置和獲取language-tag的方式固然就是上述兩種方式相結合啦!首先自動獲取瀏覽器的Language tag信息,並提供入口讓用戶自行選擇Language tag信息。java
有了本地化識別的根據(language tag)後,咱們就能夠開始實現本地化處理了,但從頭開始處理還累了,幸虧H5爲咱們提供新的API來減輕咱們的工做量。它們分別是處理排序的Intl.Collator
,處理日期格式化的Intl.DateTimeFormat
和處理數字/貨幣等格式化的Intl.NumberFormat
。git
用於字符排序.github
new Intl.Collator([locales[, options]]) @param Array|String [locales] - language-tag字符串或數組 @param Array [options] - 配置項
options的屬性及屬性值(如無特別說明則values第一個值爲默認值)算法
@prop String localeMatcher @desc 指定用於locale匹配的算法 @values 'best fit' | 'lookup' @prop String usage @desc 指定用途 @values 'sort' | 'search' @prop String sensitivity @desc 指定對比時是否忽略大小寫、讀音符號 @values 'base' - 大小寫不敏感,讀音符號不敏感 'accent' - 除採用base規則外,讀音符號敏感 'case' - 除採用base規則外,大小寫敏感 'variant' - base,accent和case的並集 @prop Boolean ignorePunctuation @desc 指定是否忽略標點符號 @values false | true @prop Boolean numeric @desc 指定是否將兩個數字字符轉換爲數字類型再做比較 @values false | true @prop String caseFirst @desc 指定是否以大寫或小寫做優先排序 @values 'false' | 'upper' | 'lower'
實例方法json
Intl.Collator.prototype.compare(a, b):Number @desc 比較字符串a和字符串b,若a排在b前面則返回-1,等於則返回0,排在後面則返回1. Intl.Collator.prototype.resolveOptions():Object @desc 返回根據構造函數中options入參生成的最終採用的options
用於日期格式化輸出.api
new Intl.DateTimeFormat([locales[, options]]) @param Array|String [locales] - language-tag字符串或數組 @param Array [options] - 配置項
options的屬性及屬性值(如無特別說明則values第一個值爲默認值)數組
@prop String localeMatcher @desc 指定用於locale匹配的算法 @values 'best fit' | 'lookup' @prop String timeZone @desc 指定被格式化的時間所在的時區 @values [IANA time zone database](https://www.iana.org/time-zones) such as "Asia/Shanghai", "Asia/Kolkata", "America /New_York", "UTC" @prop String timeZoneName @desc 指定格式化後所顯示的時區樣式 @values 'short' | 'long' @prop Boolean hour12 @desc 指定採用12小時制仍是24小時制 @values false | true @default-value 由locales入參決定 @prop String year @desc 指定年份的樣式 @values 'numeric' | '2-digit' | 'narrow' | 'short' | 'long' @prop String month @desc 指定月份的樣式 @values 'numeric' | '2-digit' | 'narrow' | 'short' | 'long' @prop String day @desc 指定日期的樣式 @values 'numeric' | '2-digit' @prop String hour @desc 指定小時的樣式 @values undefined | 'numeric' | '2-digit' @prop String minute @desc 指定分鐘的樣式 @values undefined | 'numeric' | '2-digit' @prop String second @desc 指定秒的樣式 @values undefined | 'numeric' | '2-digit' @prop String weekday @desc 指定周的樣式 @values 'narrow' | 'short' | 'long'
實例方法
Intl.Collator.prototype.format(a):String @desc 格式化日期 Intl.DateTimeFormat.prototype.resolveOptions():Object @desc 返回根據構造函數中options入參生成的最終採用的options
用於數字、貨幣格式化輸出.
new Intl.NumberFormat([locales[, options]]) @param Array|String [locales] - language-tag字符串或數組 @param Array [options] - 配置項
options的屬性及屬性值(如無特別說明則values第一個值爲默認值)
@prop String localeMatcher @desc 指定用於locale匹配的算法 @values 'best fit' | 'lookup' @prop String style @desc 指定格式化的風格 @values 'decimal' | 'currency' | 'percent' @remark 當style設置爲currency後,屬性currency必須設置 @prop String currency @desc 指訂貨幣的格式化信息 @values 如"USD"表示美圓, "EUR"表示歐元, "CNY"表示RMB.[Current currency & funds code first](http://www.currency-iso.org/en/home/tables/table-a1.html) @prop String currencyDisplay @desc 指訂貨幣符號的樣式 @values 'symbol' | 'code' | 'name' @prop Boolean useGrouping @desc 指定是否採用如千位分隔符對數字進行分組 @values false | true @prop Number minimumIntegerDigits @desc 指定整數最小位數 @values 1-21 @prop Number maximumFractionDigits @desc 指定小數部分最大位數 @values 0-20 @prop Number minimumFractionDigits @desc 指定小數部分最小位數 @values 0-20 @prop Number maximumSignificantDigits @desc 指定有效位最大位數 @values 1-21 @prop Number minimumSignificantDigits @desc 指定有效爲最小位數 @values 1-21
注意:minimumIntegerDigits
,maximumFractionDigits
和minimumFractionDigits
爲一組,而maximumSignificantDigits
和minimumSignificantDigits
爲另外一組,當設置maximumSignificantDigits
後,minimumIntegerDigits
這組的設置爲所有失效。
上述Intl接口並非全部瀏覽器均支持,幸虧有大牛已爲了咱們準備好polyfill了,但因爲Intl.Collator因此來的規則和實現的代碼量較龐大,所以polyfill中僅僅實現了Intl.DateTimeFormat和Intl.NumberFormat接口而已,不過對於通常項目而言應該足矣。Intl polyfill
另外,還對String
,Number
和Date
的原型做擴展,以便咱們使用Intl
的三劍客!
String.prototype.localeCompare(compareString[, locales[, options]]) Number.prototype.toLocaleString([locales[, options]]) Date.prototype.toLocaleString([locales[, options]]) Date.prototype.toLocaleDateString([locales[, options]]) Date.prototype.toLocaleTimeString(([locales[, options]])
說了這麼多那咱們怎麼讓項目實現國際化/本地化呢?那固然要找個可靠的第三方庫啦——Format.js,它不只提供字符串替換還提供日期、數字和貨幣格式化輸出的功能,並且各大前端框架都已將其做二次封裝,使用駕輕就熟呢!
要注意的是它依賴Intl.NumberFormat和Intl.DateTimeFormat,所以當瀏覽器部支持時須要polyfill一下。
var areIntlLocalesSupported = require('intl-locales-supported'); var localesMyAppSupports = [ /* list locales here */ ]; if (global.Intl) { // Determine if the built-in `Intl` has the locale data we need. if (!areIntlLocalesSupported(localesMyAppSupports)) { // `Intl` exists, but it doesn't have the data we need, so load the // polyfill and replace the constructors with need with the polyfill's. var IntlPolyfill = require('intl'); Intl.NumberFormat = IntlPolyfill.NumberFormat; Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat; } } else { // No `Intl`, so use and load the polyfill. global.Intl = require('intl'); }
intl-locales-supported
顧名思義就是檢查原生Intl
是否支持特定的Language tag(如cmn-Hans),若不支持則使用Polyfill版本。
原生JavaScript使用示例:
<div id="msg"></div> <script> const msgs = {en: {GREETING: 'Hello {name}'} ,fr: {GREETING: 'Bonjour {name}'}} const locale = getLang() const msg = (msgs[locale] || msgs.en).GREETING const txt = new IntlMessageFormat(msg, locale) document.getElementById('msg').textContent = txt.format({name: 'fsjohnhuang'}) </script>
Polymer組件使用示例:
<link rel="import" href="./bower_components/app-localize-behavior/app-localize-behavior.html"> <dom-module id="x-demo"> <template> <div>{{localize('name')}}</div> </template> <script> Polymer({ is: 'x-demo', properties: {name: {type: String, value: 'fsjohnhuang'}}, behaviors: [Polymer.AppLocalizeBehavior], attached: function(){ this.loadResources(this.resolveUrl('./locales.json')) } }) </script> </dom-module>
locales.json
{"en": {"GREETING": "Hello {name}"} ,"fr": {"GREETING": "Bonjour {name}"}}
更多的玩法請參考官網吧!
項目中咱們更多地是採用如Formatjs等上層i18n庫,而不是更底層的Intl
API,但若想更好地實現國際化和本地化,我想了解Intl
及其背後的規則是十分有必要的。
另外細心的你會發現上文提到另外一個概念——Server-driven Negotiation,到底它和國際化/本地化有什麼關係呢?那麼請期待下篇——《JS魔法堂:不徹底國際化&本地化手冊 之 拓展篇》
尊重原創,轉載請註明來自: http://www.cnblogs.com/fsjohnhuang/p/5911482.html ^_^肥仔John