最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是以前的项目也玩过,陌生的是以前的实现仅仅停留在"有"的阶段而已。趁着这个机会好好学习整理一下,为后面的技术选型作准备。
本篇将于你们一块儿挽起袖子撸代码:)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