JS不完全国际化&本地化手册 之 理论篇

 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已。趁着这个机会好好学习整理一下,为后面的技术选型做准备。
 本篇将阐述国际化和本地化的概念,以及其中一个很重要的概念——Language tag(也叫Language code 或 Culture)。

何为国际化?

 国际化我认为就是应用支持多语言和文化习俗(数字、货币、日期和字符比较算法等),而本地化则是应用能识别用户所属文化习俗自动适配至相应的语言文化版本。
 过去常常以为国际化就是字符串的替换——如"你好!"替换为"What's up, man!",其实具体是分为以下5方面:

字符串替换
 如"你好!"替换为"What's up, man!".

数字表示方式
 如1200.01,英语表示方式为1,200.01,而法语则为1 200,01,德语则为1.200,01.

货币表示方式
 如人民币¥1,200.01,美元表示方式为$1,200.01,而英语的欧元则为1,200.01,德语的欧元则为1.200,01 .
注意: 这里没有还没算上汇率呢.

日期表示方式
 如2016年9月15日,英语表示方式为9/15/2016, 而法语为15/9/2016, 德语为15.9.2016.

字符比较算法
 如ä和z比较时,英语、德语中均是ä排在z前面,而在瑞典语中则是z排在ä前面.

本地化的关键 —— Language Tag

 既然要自动适配至用户所属的语言文化版本,那么总得有个根据才能识别吧?我想大家应该对zh-CN和en等不陌生吧,而它们正是我们所需的根据了!在我们使用已有i18n库实现国际化/本地化时,必定会写下以下文档

{ "en": { "name": "Enter Name" }, "zh-CN": { "name": "输入姓名" } }

 但除了en和zh-CN还有其他键吗?它们的组成规则又是如何的呢?下面我们来稍微深入的了解这些Language Tag吧!

语法规则

注意以下采用ABNF语言描述(ABNF的语法请参考语法规范:BNF与ABNF)

Language-Tag = langtag / privateuse / grandfathered langtag = language ["-" script] ["-" region] *("-" variant) *("-" extension) ["-" privateuse]

可以看到Language-Tag分为langtag,privateuse 和 grandfatherd三个子类,下面我们先了解一般情况用不上的两个吧!
privateuse
 标签的意思不由subtag registry定义,而是由使用的团队间私自定义、维护和使用。
 格式:

privateuse = "x" 1*("-" (1*8alphanum))

示例:x-zh-CN是privateuse,其意思不一定与languagezh-CN一致。
注意: 只作为小集团内部用可以,决不能大范围适用。

grandfathered
 用于向后兼容。由于RFC 4646前的标签无法完全匹配当前registry的标签语法和意思,因此通过grandfathered来提供向后兼容的特性。
 语法:

grandfathered = irregular / regualr irregular = "en-GB-oed" ; irregular tags do not match / "i-ami" ; the 'langtag' production and / "i-bnn" ; would not otherwise be / "i-default" ; considered 'well-formed' / "i-enochian" ; These tags are all valid, / "i-hak" ; but most are deprecated / "i-klingon" ; in favor of more modern / "i-lux" ; subtags or subtag / "i-mingo" / "i-navajo" / "i-pwn" / "i-tao" / "i-tay" / "i-tsu" / "sgn-BE-FR" / "sgn-BE-NL" / "sgn-CH-DE" regular = "art-lojban" ; these tags match the 'langtag' / "cel-gaulish" ; production, but their subtags / "no-bok" ; are not extended language / "no-nyn" ; or variant subtags: their meaning / "zh-guoyu" ; is defined by their registration / "zh-hakka" ; and all of these are deprecated / "zh-min" ; in favor of a more modern / "zh-min-nan" ; subtag or sequence of subtags / "zh-xiang"

注意: 几乎所有grandfarthered标签均可被当前registry的标签及其组合作替代(像i-tao可以被tao代替),因此如无意外请使用现行的标签吧。

下面就到了我们的重头戏langtag了,首先我们看看langtag下的第一个subtag——language.

Primary language subtag

 像en这种就是Primary language subtag,用于标识资源所对应的语言。
 语法:

language = 2*3ALPAH ["-" extlang] / 4ALPHA / 5*8ALPHA extlang = 3ALPHA *2("-" 3ALPHA)

看到language有三种形式,其中让我比较好奇的是第一种2*3ALPHA ["-" extlang]。这种形式中前面的2*3ALPHA称为macrolanguage,用于标明资源对应一种语言的汇总,而具体的某一种语言/方言则通过extlang指定。而包含extlang部分的language也被称为encompassed language.
如zh-cmn和zh-yue就是encompassed language,其中zh是macrolanguage,而cmn和yue则是extlang。
 这里有个很有趣的事情是,我们认为普通话和广东话等都是汉语的方言,但西方却认为普通话、广东话根本就不属于一种语言,因此像zh-cmn和zh-yue在规范中被设置为redundant,建议直接使用cmn和yue等。不过由于历史原因,我们还是使用zh-CN代表cmn-CN。
 另外现在可以作为macrolanguage的就只有7个标签(ar,kok,ms,sw,uz,zh和sgn)
 另外几个和cmn类似的subtags如下

cmn 普通话(官话、国语) wuu 吴语(江浙话、上海话) czh 徽语(徽州话、严州话、吴语-徽严片) hak 客家语 yue 粤语(广东话) nan 闽南语(福建话、台语) cpx 莆仙话(莆田话、兴化语) cdo 闽东语 mnp 闽北语 zco 闽中语 gan 赣语(江西话) hsn 湘语(湖南话) cjy 晋语(山西话、陕北话)

注意: 一般采用全小写

Script subtag

 用于指定字迹或文字系统资源所属的语言和方言等。
 语法:

script = 4ALPHA

注意: 一般采用首字母大写,后续字母全小写

Region subtag

 指定与国家、地域对应的语言/方言文化。
 语法:

region = 2ALPHA / 3DIGIT

注意: 一般采用全大写

Variant subtag

 指定其他subtag又无法提供的额外信息
 语法:

variant = 5*8alphanum / (DIGIT 3alphanum)

示例:de-CH-1996其中1996是variant subtag,整体意思是在Switzerland使用的自1996改良过的德语。

Extension subtag

 提供一种机制让我们去扩展langtag
 语法:

extension = singleton 1*("-" (2*8alphanum)) singleton = DIGIT / %x41-57 / %x59-5A / %x61-77 / %x79-7A

现在仅支持u作为sigleton的值。
示例:de-DE-u-co-phonebk表示采用电话本核对的方式对内容进行排序等操作。

更多关于language-tag的信息请参考BCP 47

如何选择Language Tag

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzjzys.html