RSS

Java信息绑定

28 Apr

程序中的文字信息可以写在属性文件中,不一定要写在程序代码中,这样日后修改只要修改文本文件就可以了,而不需要重新编译程序。

使用ResourceBundle使用java.util.ResourceBundle来做信息绑定,首先准备一个.properties文件,例如message.properties,内容如下: onlyfun.caterpillar.welcome = Hello onlyfun.caterpillar.name     = World .properties文件放在classpath路径下(可以在windows环境变量里面设置),当然也可以放到工程文件里,这个可以看这个截图。

01 package onlyfun.caterpillar;
02 import java.util.ResourceBundle;
03 public class ResourceBundleDemo {
04
05 public ResourceBundleDemo() {
06     ResourceBundle resource = ResourceBundle.getBundle(“message”);
07     System.out.println(resource.getString(“onlyfun.caterpillar.welcome”));
08     System.out.println(resource.getString(“onlyfun.caterpillar.name”));
09 }
10
11 }

格式化信息可以使用java.text.MessageFormat来辅助信息的格式化,MessageFormat可以接受一个字符串模式来指定。对于文字信息中可能变动的部分,可以使用Argument Index先占住文字的位置,参数索引是{0}~{9}的非负整数,之后使用MessageFormat实例的format()方法时,可以提供真正的参数来填充索引处的信息。 message2.properties:

onlyfun.caterpillar.greeting = Hello! {0}! This is your first {1}!

01 package onlyfun.caterpillar;
02 import java.util.ResourceBundle;
03 import java.text.MessageFormat;
04
05 public class MessageFormatDemo {
06 public MessageFormatDemo(String arg0, String arg1){
07 try{
08     ResourceBundle resource = ResourceBundle.getBundle(“message2”);
09     String message = resource.getString(“onlyfun.caterpillar.greeting”);
10     Object [] params = new Object[] {arg0, arg1};
11     MessageFormat formatter = new MessageFormat(message);
12     System.out.println(formatter.format(params));
13 } catch(ArrayIndexOutOfBoundsException e){
14     System.out.println(
没有指定参数);
15 }
16 }
17 }

国际化信息国际化的英文是Internationalization,简称I18N。为了在应用程序中表示一个区域,Java提供有java.util.Locale类,一个Locale实例包括了语系信息和区域信息。例如en表示英文语系的国家,这个字母组合在ISO 639中定义的,而区域信息则是想US表示美国,这个字母组合则是在ISO 3166中定义的。

可以这么新增一个Locale的实例,用以表示中文语系zh、中国cn:
Locale locale = new Locale(“zh”, “CN”);
如何将Locale用于信息绑定呢?当使用ResourceBundle.getBundle()方法时,默认就会自动取得计算机上的语系与区域信息
资源包中的每个成员共享一个被称作基名(base name)的名称,然后在此基础上根据一定的命名规范进行扩展。下面就列出了一些成员的名称:
LabelResources
LabelResources_de
LabelResources_de_CH
LabelResources_de_CH_UNIX

可见这些子类依据这样的命名规范:baseName_language_country_variant,其中language等几个变量就是你在构造Locale类时所使用的。而资源包正是通过这个符合命名规范的名称来和locale进行关联的,比如LabelResource_de_CH就对应于由德语(de)和瑞士(CH)组成的locale对象。
当你的应用程序需要查找特定locale对象关联的资源包时,它可以调用ResourceBundlegetBundle方法,并将locale对象作为参数传入。
Locale currentLocale = new Locale(“de”, “CH”, “UNIX”);
ResourceBundle myResources = ResourceBundle.getBundle(“LabelResources”, currentLocale);
如果该locale对象匹配的资源包子类找不到,getBundle将试着查找最匹配的一个子类。具体的查找策略是这样的:getBundle使用基名,locale对象和缺省的locale来生成一个候选资源包名称序列。如果特定locale对象的语言代码、国家代码和可选变量都是空值,则基名是唯一的候选资源包名称。否则的话,具体locale对象(language1country1variant1)和缺省localelanguage2country2variant2)将产生如下的序列:

baseName + “_” + language1 + “_” + country1 + “_” + variant1
baseName + “_” + language1 + “_” + country1
baseName + “_” + language1
baseName + “_” + language2 + “_” + country2 + “_” + variant2
baseName + “_” + language2 + “_” + country2
baseName + “_” + language2 baseName
然后,getBundle方法按照产生的序列依次查找匹配的资源包子类并对结果子类初始化。首先,它将寻找类名匹配候选资源包名称的类,如果找到将创建该类的一个实例,我们称之为结果资源包。否则,getBundle方法将寻找对应的资源文件,它通过候选资源包名称来获得资源文件的完整路径(将其中的“.”替换为“/”,并加上“.properties”后缀),如果找到匹配文件,getBundle方法将利用该资源文件来创建一个PropertyResourceBundle实例,也就是最终的结果资源包。与此同时,getBundle方法会将这些资源包实例缓存起来供以后使用。
如果没有找到结果资源包,该方法将抛出MissingResourceException异常。所以为了防止异常的抛出,一般来说都需要至少实现一个基名资源包子类。
注意:基名参数必须是一个完整的类名称(比如LabelResourcesresource.LabelResources等),就相当于你引用一个类时需要指定完整的类路径。但是,为了和以前的版本保持兼容,在使用PropertyResourceBundles时也允许使用“/”来代替“.”表示路径。
比如你有以下这些资源类和资源文件:MyResources.class MyResources_fr_CH.properties MyResources_fr_CH.class MyResources_fr.properties MyResources_en.properties MyResources_es_ES.class。你利用以下的locale设置来调用getBundle方法,你将会得到不同的结果资源包(假设缺省localeLocale(“en”, “UK”)),请参下面

locale设置结果资源包

Locale(“fr”, “CH”)         MyResources_fr_CH.class
Locale(“fr”, “FR”)         MyResources_fr.properties
Locale(“de”, “DE”)        MyResources_en.properties
Locale(“en”, “US”)        MyResources_en.properties
Locale(“es”, “ES”)        MyResources_es_ES.class

创建了具体的资源包子类实例以后,就需要获得具体的信息。信息在资源包中是以键值对的方式存储的,:LabelResources.properties
# This is LabelResources.properties file
greetings =
您好!
farewell =
再见。
inquiry =
您好吗?
其中等号左边的字符串表示主键,它们是唯一的。为了获得主键对应的值,你可以调用ResourceBundle类的getString方法,并将主键作为参数。此外,文件中以“#”号开头的行表示注释行
如果想要提供中文信息,由于信息资源文件必须是ISO-8859-1编码,所以对于非西方语系的处理,必须先将之转换为Java Unicode Escape格式。例如可以先在message3_zh_cn.txt编写:
onlyfun.caterpillar.welcome =
哈罗
onlyfun.caterpillar.name =
世界
然后用JDK的工具程序native2ascii来转换。例如
native2ascii -encoding gb2312 message3_zh_cn.txt message3_zh_cn.properties
转换后的message3_zh_cn.properties文件内容如下:
onlyfun.caterpillar.welcome = \ufffd\ufffd\ufffd
onlyfun.caterpillar.name = \u6d93\ufffd\ufffd

将这个文件放于Classpath可以存取到的路径,也可以提供默认的信息文件message.properties:
onlyfun.caterpillar.welcome = Hello
onlyfun.caterpillar.name = World

01 package onlyfun.caterpillar;
02 import java.util.Locale;
03 import java.util.ResourceBundle;
04 public class I18NDemo {
05 public I18NDemo(){
06 //
根据系统语言(zh-cn)message3_zh_cn.properties,找不到才会找message3

07 //Locale locale = new Locale(“zh”, “cn”);
08 ResourceBundle source = ResourceBundle.getBundle(“message3″);
09 System.out.println(source.getString(“onlyfun.caterpillar.welcome”) + “!”);
10 System.out.println(source.getString(“onlyfun.caterpillar.name”) + “!”);
11 }
12 
}

如果去掉注释部分,那么应该这样写ResourceBundle.getBundle(“message3”,locale)。这样就可以根据Locale里的设定语言来显示,而不是根据系统默认的语言和区域来显示。

Advertisements
 
Leave a comment

Posted by on 04/28/2008 in JAVA

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: