JS不完全国际化&本地化手册 之 理论篇
最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已。趁着这个机会好好学习整理一下,为后面的技术选型做准备。
本篇将阐述国际化和本地化的概念,以及其中一个很重要的概念——Languagetag(也叫Languagecode或Culture)。
国际化我认为就是应用支持多语言和文化习俗(数字、货币、日期和字符比较算法等),而本地化则是应用能识别用户所属文化习俗自动适配至相应的语言文化版本。
过去常常以为国际化就是字符串的替换——如"你好!"替换为"What'sup,man!",其实具体是分为以下5方面:
- 字符串替换
如"你好!"替换为"What'sup,man!". - 数字表示方式
如1200.01,英语表示方式为1,200.01,而法语则为1200,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排在ä前面.本地化的关键——LanguageTag 既然要自动适配至用户所属的语言文化版本,那么总得有个根据才能识别吧?我想大家应该对zh-CN和en等不陌生吧,而它们正是我们所需的根据了!在我们使用已有i18n库实现国际化/本地化时,必定会写下以下文档
{ "en":{"name":"EnterName"}, "zh-CN":{"name":"输入姓名"} }
但除了en和zh-CN还有其他键吗?它们的组成规则又是如何的呢?下面我们来稍微深入的了解这些LanguageTag吧!
注意以下采用ABNF语言描述(ABNF的语法请参考语法规范:BNF与ABNF)
Language-Tag=langtag /privateuse /grandfathered langtag=language ["-"script] ["-"region] *("-"variant) *("-"extension) ["-"privateuse]
可以看到Language-Tag分为langtag,privateuse和grandfatherd三个子类,下面我们先了解一般情况用不上的两个吧!
privateuse
标签的意思不由subtagregistry定义,而是由使用的团队间私自定义、维护和使用。
格式:
privateuse="x"1*("-"(1*8alphanum))
示例:x-zh-CN是privateuse,其意思不一定与languagezh-CN一致。
注意:只作为小集团内部用可以,决不能大范围适用。
grandfathered
用于向后兼容。由于RFC4646前的标签无法完全匹配当前registry的标签语法和意思,因此通过grandfathered来提供向后兼容的特性。
语法:
grandfathered=irregular /regualr irregular="en-GB-oed";irregulartagsdonotmatch /"i-ami";the'langtag'productionand /"i-bnn";wouldnototherwisebe /"i-default";considered'well-formed' /"i-enochian";Thesetagsareallvalid, /"i-hak";butmostaredeprecated /"i-klingon";infavorofmoremodern /"i-lux";subtagsorsubtag /"i-mingo" /"i-navajo" /"i-pwn" /"i-tao" /"i-tay" /"i-tsu" /"sgn-BE-FR" /"sgn-BE-NL" /"sgn-CH-DE" regular="art-lojban";thesetagsmatchthe'langtag' /"cel-gaulish";production,buttheirsubtags /"no-bok";arenotextendedlanguage /"no-nyn";orvariantsubtags:theirmeaning /"zh-guoyu";isdefinedbytheirregistration /"zh-hakka";andallofthesearedeprecated /"zh-min";infavorofamoremodern /"zh-min-nan";subtagorsequenceofsubtags /"zh-xiang"
注意:几乎所有grandfarthered标签均可被当前registry的标签及其组合作替代(像i-tao可以被tao代替),因此如无意外请使用现行的标签吧。
下面就到了我们的重头戏langtag了,首先我们看看langtag下的第一个subtag——language.
像en这种就是Primarylanguagesubtag,用于标识资源所对应的语言。
语法:
language=2*3ALPAH ["-"extlang] /4ALPHA /5*8ALPHA extlang=3ALPHA *2("-"3ALPHA)
看到language有三种形式,其中让我比较好奇的是第一种2*3ALPHA["-"extlang]。这种形式中前面的2*3ALPHA称为macrolanguage,用于标明资源对应一种语言的汇总,而具体的某一种语言/方言则通过extlang指定。而包含extlang部分的language也被称为encompassedlanguage.
如zh-cmn和zh-yue就是encompassedlanguage,其中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=4ALPHA
注意:一般采用首字母大写,后续字母全小写
指定与国家、地域对应的语言/方言文化。
语法:
region=2ALPHA /3DIGIT
注意:一般采用全大写
指定其他subtag又无法提供的额外信息
语法:
variant=5*8alphanum /(DIGIT3alphanum)
示例:de-CH-1996其中1996是variantsubtag,整体意思是在Switzerland使用的自1996改良过的德语。
提供一种机制让我们去扩展langtag
语法:
extension=singleton1*("-"(2*8alphanum)) singleton=DIGIT /%x41-57 /%x59-5A /%x61-77 /%x79-7A
现在仅支持u作为sigleton的值。
示例:de-DE-u-co-phonebk表示采用电话本核对的方式对内容进行排序等操作。
更多关于language-tag的信息请参考BCP47
硬着头皮啃下这么多规范的内容,但我还不知道如何组合合适的language-tag呢:(其实选择和组合的原则就只有一条
在足以区别当前上下文中其他language-tag的前提下,保持language-tag足够地短小精干
示例1:下文普通话、粤语并存
<plang="cmn"> 小陈说:"老大爷,东方广场怎么走啊?" 老大爷回答道:"<spanlang="yue">你讲咩也啊?我听唔明喔。</span>" </p>
示例2:下文含大陆人讲英语、香港人讲普通话和美国人说英语
<plang="cmn"> 小陈说:"<spanlang="en-CN">Hi,whereareyoucomefrom?</span>" 李先生说:"<spanlang="cmn-HK">你的英文跟我的普通话一样普通啊,哈哈!</span>" Simon说:"<spanlang="en">Hey,what'sup!</span>" </p>
那现在引出另一个问题,那就是我们怎么知道各个subtag具体定义了哪些值呢?
具体都定义在IANALanguageSubtagRegistry中了。
假如觉得查找起来还是不方便,那么就使用LanguageSubtagLookuptool吧!
另外若不清楚各国各地区所使用的语言或方言时,可通过Ethnologue查看,直接点击地图上的区域即可获取相应的subtag信息。
现在我们已经对国际化和本地化有了更全面的理解,也对Languagetag有了更深入的认识,现在是不是迫不及待想挽起袖子撸代码呢?敬请期待下篇《JS魔法堂:不完全国际化&本地化手册之实战篇》
网页头部的声明应该是用lang="zh"还是lang="zh-cn"?
LanguageSubtagRegistry
BCP47
LanguageontheWeb
ChoosingaLanguageTag
LanguagetagsinHTMLandXML