萬盛學電腦網

 萬盛學電腦網 >> 腳本專題 >> javascript >> JavaScript面對國際化編程時的一些建議

JavaScript面對國際化編程時的一些建議

   這篇文章主要介紹了JavaScript面對國際化編程時的一些建議,包括時區與語言編碼等一些值得注意的問題,需要的朋友可以參考下

  什麼是國際化?

  國際化(Internationalization的縮寫是i18n——i,中間18個字符,n)是將軟件處理的能讓來自各種地方使用各種語言的用戶更簡單使用的一個過程。假定某個用戶來自某個地方說某種語言,他可能不經意間就得到一些錯誤提示。尤其是你甚至都沒有做這種假設。

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 function formatDate(d) { // Everyone uses month/date/year...right? var month = d.getMonth() + 1; var date = d.getDate(); var year = d.getFullYear(); return month + "/" + date + "/" + year; }   function formatMoney(amount) { // All money is dollars with two fractional digits...right? return "$" + amount.toFixed(2); }   function sortNames(names) { function sortAlphabetically(a, b) { var left = a.toLowerCase(), right = b.toLowerCase(); if (left > right) return 1; if (left === right) return 0; return -1; }   // Names always sort alphabetically...right? names.sort(sortAlphabetically); }

  JavaScript過去的i18n支持太糟糕

  傳統JS的i18n程序使用toLocaleString()方法進行格式化。結果字符串包含實現自身提供的所有細節:沒有辦法自己選擇(你確實需要那種date格式的weekday嗎?year是無關緊要的嗎?)。即使包含對應的細節,格式也可能是錯的,比如本期望是百分比但得到的是數字。而且你還不能選擇一個區域設置(locale)。

  對於排序,JS提供了基本沒用的基於區域設置(locale-sensitive)的文本比較函數。localeCompare()確實存在,但是其接口根本不適合sort。而且還不允許選擇區域設置,或者排序方式。

  這些限制太糟了(當我認識到時,我非常吃驚!),因為需要i18n支持(通常是金融站點用於顯示貨幣)的嚴謹web應用會把數據打包,發給服務器,服務器進行操作,然後發回客戶端。數據往返服務器僅僅為了處理貨幣的數量。Yeesh。

  新的JS國際化API

  新的ECMAScript國際化API大大提升了JS的i18n能力。 它提供了大家所能想到的格式化date、數字,文本排序的方式。區域設置是可選的,如果請求的區域設置不支持可以回退。格式化請求可以指定具體要包含的組件。支持自定義的百分比、有效數字、貨幣格式。開放了大量排序選項用於文本排序。如果你關心性能,首要的操作是選擇一個區域設置,然後處理選項參數,現在這個操作只會處理一次,而不是之前每次區域設置相關的操作執行時都會被執行一遍。

  這不是說,這個API是萬能藥,而僅僅是"盡最大努力"。精確的輸出幾乎總是故意不指定的。一份實現可以僅支持 oj 區域設置(合法的),也可以忽略(幾乎全部)提供的格式化選項。大多數實現都包含高質量的多區域支持,但並不保證有(尤其是資源限定的系統,如手機)。

  在底層,Firefox的實現依賴於Unicode 的國際化組件庫(ICU) ,這個庫又依賴 Unicode Common 區域數據倉庫(CLDR)的區域數據集。我們的實現是自托管的:ICU之上的大部分實現用JS寫的。在這個過程中,我們遇到了一些問題(我們從未如此大規模的自托管過),但基本上都不大。

  Intl 接口(不是數字1,是字母l)

  i18n 存在於 Intl 對象之上。Intl 包含3個構造函數:Intl.Collator, Intl.DateTimeFormat, 和Intl.NumberFormat。每個構造函數創建一個對象,這個對象提供相關操作、高效地為這些操作緩存區域設置和選項。按以下方式創建對象:

  ?

1 2 var ctor = "Collator"; // 或其他 var instance = new Intl[ctor](locales, options);

  locales 是個字符串,指定單個語言標簽,或者包含多個語言標簽的類數組對象。語言標簽如下面的字符串:en(普通英語),de-AT(奧地利德語),zh-Hant-TW(台灣使用的繁體中文)。語言標簽可以包含一個“Unicode擴展”,形式為-u-key1-value1-key2-value2..., 其中每個key是“擴展key”。不同的構造函數對此進行具體解釋。

  opions 是個對象,其屬性(如果不存在,就賦值為undefined)決定格式化器(formatter)和整理器(collator)的行為。精確的解釋由構造函數決定。

  給定區域信息和選項,實現會嘗試生成近似理想行為的最接近行為。Firefox 支持用於整理(collation)的400+區域,用於date/time和數字格式化的600+區域,所以很可能(但不保證)你想要的區域是被支持的。

  Intl 通常不保證某些特定行為。如果請求的區域不被支持,Intl 允諾“盡最大努力”的行為。即使區域是被支持的,行為也不是嚴格指定的。永遠不要假設特定的選項集適用於某個特定格式。(圍繞請求的組件)總體格式的用語可能因浏覽器甚至浏覽器的版本而不同。單個組件的格式是未指定的:weekday的短格式可以為“S”, “Sa”, 或“Sat”。Intl API並不用於公開精確的特定行為。

  選項

  date/time格式化的主要選項屬性如下:

  weekday, era

  "narrow", "short", or "long". (era通常指歷法系統中長於一年的分段,如現行日皇統治, 或者其他紀年法)

  month

  "2-digit", "numeric", "narrow", "short", or "long"

  year

  day

  hour, minute, second

  "2-digit" or "numeric"

  timeZoneName

  "short" or "long"

  timeZone

  區分大小寫的"UTC"通過對應的toUTC進行格式化。有些值如"CEST"和"America/New_York"不是必須被支持的,它們確實在當前Firefox下沒有效果。

  這些值並不映射到特定格式:記住Intl API幾乎不指定精確的行為。Intl的目的,舉例來說是"narrow", "short", 和"long"生成對應大小的“S”/“Sa”, “Sat”, 和“Saturday”(輸出可能不太准確,因為Saturday和Sunday都可以生成“S”)。 "2-digit"和"numeric"映射到2位數字的字符串或者全長度的數字字符串,如“70”和“1970”。

  最終使用的選項大部分是請求的選項。但是,如果你不指定請求的 weekday/year/month/day/hour/minute/second,那麼 year/month/day 將會被加入到你提供的選項。

  除此之外,還有些特殊的選項:

  hour12

  指定hour采用12小時還是24小時格式。默認通常是依賴於區域設置的(某些細節,如午夜是0點,還是12點,以及是否存在前導0,都是依賴於區域設置的)。

  還有另外2種特殊屬性,localeMatcher (可選"lookup"或"best fit") 和formatMatcher (可選"basic"或"best fit"),兩者默認值都是"best fit"。這些會影響正確的區域設置和格式的選取。它們的用例可能比較難懂,就不贅述了。

  區域設置相關選項

  DateTimeFormat也允許通過自定義歷法和數字系統來格式化。具體細節存在於區域設置,所以它們可以在語言標簽的Unicode擴展中找到。

  例如,泰國的泰語中語言標簽為th-TH。回一下Unicode擴展的格式-u-key1-value1-key2-value2.... 歷法系統的key是ca, 數字系統的key時nu。泰語數字系統值為thai,中文歷法系統值為chinese。因此用大體這樣的方式來格式化date,我們把包含這些key/value對的Unicode追加到語言標簽上去:th-TH-u-ca-chinese-nu-thai。

  關於更多歷法和數字系統的信息,查看DateTimeFormat的完整文檔。

  舉例

  創建DateTimeFormat對象後,下一步是通過方便的format()函數來格式化date。更方便的是,這個函數是有界函數(bound function):你不必在DateTimeFormat上直接調用。之後給它傳遞一個時間戳或者Date對象。

  總結一下,下文是如何為特定用途創建Dat

copyright © 萬盛學電腦網 all rights reserved