4.4 区域设置

如果程序需要提供国际化的支持,就要求程序对用户的区域设置信息是敏感的。也就是说,程序在输出相关信息给用户的时候,应该考虑当前用户所在的地理位置区域。比如当用户所在地区为中国大陆的时候,程序应该采用简体中文作为信息的显示语言,并在日期和时间、数字和货币等显示的格式上也符合中国大陆的用户的使用习惯。通常来说,操作系统会提供相关的功能来允许用户设置其所在的区域。Java虚拟机也会以底层操作系统的区域设置作为其默认的设置。Java中与区域设置相关的API都可以根据Java虚拟机默认的或是程序指定的区域设置来产生对应的输出。通过操作系统或其他方式识别出来的用户的区域设置信息不一定是准确的,程序一般都应该提供允许用户自由切换区域设置的功能。

Java中的区域设置是通过java.util.Locale类的对象来表示的。由于区域设置本身的复杂性,Locale类的对象中所包含的信息是比较多的。这些信息的目的在于准确地区分不同的区域,同时又以便于使用者理解的方式组织起来。在Java 7之前,Locale只包含了语言名称、国家或地区名称以及变体信息。从Java 7开始,Java中的区域设置支持了IETF BCP 47(Tags for Identifying Languages)[1]这一最佳实践,相关的API也做了修订和增强。

4.4.1 IETF BCP 47

用户的区域设置可以用一个标识符来表示。程序通过这个标识符来确定应该采用什么样的方式来把信息呈现给用户。一般来说,一个区域设置标识符至少应该包括语言标识符和国家或地区的标识符两部分,还可能包含一个变体信息。比如英文的语言标识符是“en”,而美国的标识符是“US”。所以对于生活在美国的英语使用者来说,他们的区域设置就同时包含“en”和“US”。这也是Java中的Locale类的对象最开始的时候包含这3种信息的原因。不同的操作系统平台实现可能采用不同的标识符格式,但是这些基本信息都是存在的,只是表示的方式不同。为了增强互操作性,IETF BCP 47定义了一个语言标签的格式规范,这个标签可以作为区域设置的标识符的格式。从Java 7开始,Java平台开始使用BCP 47的格式作为其区域设置标识符的基本格式,之前的格式也予以保留以保证与早期版本的兼容性。新的Java程序应该使用BCP 47的格式来表示其区域设置,Java也提供了相关的API可以很方便地创建出这种格式的Locale类的对象。

IETF BCP 47中定义的语言标签只是一个简单的字符串,可以附加在一段信息上,用来声明这段信息所使用的语言。这个字符串由几个部分组成,每个部分之间用“-”分隔。每个部分被称为一个子标签,其格式和含义是不相同的,可以很容易地进行解析。即便某个部分中包含的内容本身可能是无意义的,也可以正确地进行解析。比如包含国家或地区标识符的那部分内容可能并不对应于任何实际存在的国家或地区,但是仍然可以被正确地分析出来。这么设计的好处在于可以很好地应对以后的变化。

第一部分是语言的名称,如“zh”、“en”和“fr”等。这个部分可以是2到8个字母。最常使用的是2或3个字母的ISO 639规范定义的语言名称。在主要语言名称的后面可以加上扩展的子语言名称。这通常是因为某些语言存在一些使用广泛的子语言。如中文中的粤语就可以用“zh-yue”来表示。第二部分是语言的书写格式。这个部分是在ISO 15924中定义的4个字符长度的符号。第三部分是国家或地区的名称,这个部分可以是ISO 3166-1定义的2个字母的编号或是UN M.49定义的3个数字的编号。第四部分是变体信息,用来描述语言或其方言的变体。以字母开头的变体信息的长度至少是5,而以数字开头的变体信息的长度至少是4。第五部分是语言的扩展。这些扩展用来描述语言的一些附加信息。每个扩展由两个部分组成:第一部分是单个字母的键,第二部分则是2到8个字母或数字组成的值。最后一部分是私有标记。这个部分以字母“x”开始,后面跟着1到8个字母或数字。

从上面对语言标签的描述中可以看出,语言标签以及基于它的Locale类的对象更多的时候只是一个标识符,它本身并不包含具体的本地化的能力。支持本地化的方法应该接受一个Locale类的对象作为参数,根据这个Locale类的对象所表示的区域来正确地产生相应的输出。

在Java 7之前,只有两种创建Locale类的对象的方式,一种是使用它的构造方法,另外一种是使用Locale类中预先定义的常用区域设置。Java 7新增了两种与BCP 47相关的构造方式。一种是用静态方法forLanguageTag来把一个符合BCP 47的语言标签字符串转换成Locale类的对象。另外一种则是使用新的Locale.Builder类来设置语言标签的各个部分,并最终产生一个完整的Locale类的对象。代码清单4-8给出了一个Locale.Builder类的使用示例,注意其中方法级联的使用。

代码清单4-8 Locale.Builder类的使用示例


public void useLocaleBuilder(){

Locale locale=new Locale.Builder().setLanguage("zh").setRegion("CN").setExtension('m',"myext").build();

String tag=locale.toLanguageTag();//值为“zh-CN-m-myext”

}


[1]IETF BCP47规范的网址是:http://tools.ietf.org/html/bep47。