前言

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

 本篇将阐述国际化和本地化的概念,以及其中一个很重要的概念——Language tag(也叫Language code 或 Culture)。

何为国际化?

 国际化我认为就是应用支持多语言和文化习俗(数字、货币、日期和字符比较算法等),而本地化则是应用能识别用户所属文化习俗自动适配至相应的语言文化版本。

 过去常常以为国际化就是字符串的替换——如"你好!"替换为"What's up, man!",其实具体是分为以下5方面:

  1. 字符串替换

     如"你好!"替换为"What's up, man!".
  2. 数字表示方式

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

     如人民币¥1,200.01,美元表示方式为$1,200.01,而英语的欧元则为€1,200.01,德语的欧元则为1.200,01 €.

    注意: 这里没有还没算上汇率呢.
  4. 日期表示方式

     如2016年9月15日,英语表示方式为9/15/2016, 而法语为15/9/2016, 德语为15.9.2016.
  5. 字符比较算法

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

本地化的关键 —— Language Tag

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

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

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

语法规则

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

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

可以看到Language-Tag分为langtagprivateusegrandfatherd三个子类,下面我们先了解一般情况用不上的两个吧!

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-cmnzh-yue就是encompassed language,其中zh是macrolanguage,而cmnyue则是extlang。

 这里有个很有趣的事情是,我们认为普通话和广东话等都是汉语的方言,但西方却认为普通话、广东话根本就不属于一种语言,因此像zh-cmnzh-yue在规范中被设置为redundant,建议直接使用cmnyue等。不过由于历史原因,我们还是使用zh-CN代表cmn-CN

 另外现在可以作为macrolanguage的就只有7个标签(ar,kok,ms,sw,uz,zhsgn)

 另外几个和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

 硬着头皮啃下这么多规范的内容,但我还不知道如何组合合适的language-tag呢:(其实选择和组合的原则就只有一条

在足以区别当前上下文中其他language-tag的前提下,保持language-tag足够地短小精干

示例1:下文普通话、粤语并存

<p lang="cmn">
小陈说:"老大爷,东方广场怎么走啊?"
老大爷回答道:"<span lang="yue">你讲咩也啊?我听唔明喔。</span>"
</p>

示例2:下文含大陆人讲英语、香港人讲普通话和美国人说英语

<p lang="cmn">
小陈说:"<span lang="en-CN">Hi, where are you come from?</span>"
李先生说:"<span lang="cmn-HK">你的英文跟我的普通话一样普通啊,哈哈!</span>"
Simon说:"<span lang="en">Hey, what's up!</span>"
</p>

 那现在引出另一个问题,那就是我们怎么知道各个subtag具体定义了哪些值呢?

具体都定义在IANA Language Subtag Registry中了。

假如觉得查找起来还是不方便,那么就使用Language Subtag Lookup tool吧!

另外若不清楚各国各地区所使用的语言或方言时,可通过Ethnologue查看,直接点击地图上的区域即可获取相应的subtag信息。

总结

 现在我们已经对国际化和本地化有了更全面的理解,也对Language tag有了更深入的认识,现在是不是迫不及待想挽起袖子撸代码呢?敬请期待下篇《JS魔法堂:不完全国际化&本地化手册 之 实战篇》

 尊重原创,转载请注明来自: http://www.cnblogs.com/fsjohnhuang/p/5908028.html _肥仔John

感谢

网页头部的声明应该是用 lang="zh" 还是 lang="zh-cn"?

Language Subtag Registry

BCP 47

Language on the Web

Choosing a Language Tag

Language tags in HTML and XML

JS魔法堂:不完全国际化&本地化手册 之 理論篇的更多相关文章

  1. JS魔法堂:不完全国际化&本地化手册 之 实战篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  2. JS魔法堂:不完全国际化&本地化手册 之 拓展篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  3. JS魔法堂:判断节点位置关系

    一.前言 在polyfill querySelectorAll 和写弹出窗时都需要判断两个节点间的位置关系,通过jQuery我们可以轻松搞定,但原生JS呢?下面我将整理各种判断方法,以供日后查阅. 二 ...

  4. JS魔法堂:LINK元素深入详解

    一.前言 我们一般使用方式为 <link type="text/css" rel="stylesheet" href="text.css&quo ...

  5. JS魔法堂:IMG元素加载行为详解

    一.前言 在<JS魔法堂:jsDeferred源码剖析>中我们了解到img元素加载失败可以作为函数异步执行的优化方案,本文打算对img元素的加载行为进行更深入的探讨. 二.资源加载的相关属 ...

  6. JS魔法堂:jsDeferred源码剖析

    一.前言 最近在研究Promises/A+规范及实现,而Promise/A+规范的制定则很大程度地参考了由日本geek cho45发起的jsDeferred项目(<JavaScript框架设计& ...

  7. JS魔法堂:属性、特性,傻傻分不清楚

    一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...

  8. JS魔法堂:那些困扰你的DOM集合类型

    一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = documen ...

  9. JS魔法堂:doctype我们应该了解的基础知识

    一.前言 什么是doctype?其实我们一直使用,却很少停下来看清楚它到底是什么,对网页有什么作用.本篇将和大家一起探讨那个默默无闻的doctype吧! 二.什么是doctype doctype或DT ...

随机推荐

  1. CoreCLR源码探索(一) Object是什么

    .Net程序员们每天都在和Object在打交道 如果你问一个.Net程序员什么是Object,他可能会信誓旦旦的告诉你"Object还不简单吗,就是所有类型的基类" 这个答案是对的 ...

  2. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  3. 数学思想:为何我们把 x²读作x平方

    要弄清楚这个问题,我们得先认识一个人.古希腊大数学家 欧多克索斯,其在整个古代仅次于阿基米德,是一位天文学家.医生.几何学家.立法家和地理学家. 为何我们把 x²读作x平方呢? 古希腊时代,越来越多的 ...

  4. Java中的多态

    1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal {public abstract void Say();} 子类: public class ...

  5. AngularJs之九(ending......)

    今天继续angularJs,但也是最后一篇关于它的了,基础部分差不多也就这些,后续有机会再写它的提升部分. 今天要写的也是一个基础的选择列表: 一:使用ng-options,数组进行循环. <d ...

  6. SQL Server-聚焦在视图和UDF中使用SCHEMABINDING(二十六)

    前言 上一节我们讨论了视图中的一些限制以及建议等,这节我们讲讲关于在UDF和视图中使用SCHEMABINDING的问题,简短的内容,深入的理解,Always to review the basics. ...

  7. asp.net mvc 验证码

    效果图 验证码类 namespace QJW.VerifyCode { //用法: //public FileContentResult CreateValidate() //{ // Validat ...

  8. 通过sails和阿里大于实现短信验证

    通过sails与阿里大于来实现注册短信验证码的发送,逻辑图如下 1.用户在客户端发送手机号给服务器,服务器接收到手机号,生成对应时间戳,随机四位数验证码 2.服务器将电话号码和验证码告诉阿里大于服务器 ...

  9. Postman - 功能强大的 API 接口请求调试和管理工具

    Postman 是一款功能强大的的 Chrome 应用,可以便捷的调试接口.前端开发人员在开发或者调试 Web 程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的 Fi ...

  10. Dynamics CRM 2015-Data Encryption激活报错

    在CRM的日常开发中,Data Encryption经常是不得不开启的一个功能.但是有时,我们可能遇到一种情况,Organization导入之后,查看Data Encryption是已激活的状态,但是 ...