国际化又称为本地化。
当你把手机的language由中文切换到英文时,你的微信也相应改用英语,这就是i18n国际化。一般来说,应用软件提供一套不同语言的资源文件,放到特定目录中,应用根据不同语言的操作系统决定使用哪一种语言。
一般由两个条件限定一个国际化类型:语言类型和国家/地区类型。比如:
中文:语言类型:zh,国家/地区类型:CN(中国大陆)/HK(中国香港)/TW(中国台湾)。
英语:语言类型:en,国家类型:EN。
----------------------------------------------------------------------------------------------------------------
java.util.Locale是一个本地化类,是创建国际化应用的基础。
创建本地化对象有多种方式:Locale locale1=new Locale("zh","CN");//俩参,语言类型、国家类型
Locale locale2=new Locale("zh");//默认本地语言类型
Locale locale3=Locale.CHINA;//常量
Locale locale4=Locale.getDefault();//默认的本地化对象。
-------------------------------------------------------------------------------------------------------
光有本地化类还不行,需要有个利用本地化对象来操作输出信息的类:
java.text包中提供了几个这样的工具类:DateFormat、MessageFormat、NumberFormat。
----------------------------------------------------------------------------------------------------
NumberFormat举例:给一个123456.78,把它输出为¥123456.78,即把数字转换为货币格式。
1 Locale locale = new Locale("zh","CN"); 2 NumberFormat nf=NumberFormat.getCurrencyInstance(locale); 3 System.out.println("一头羊售价:"+nf.format(d));
public static void main(String args[]){ printCurrency(888.88); }
打印:一头羊售价:¥888.88
-------------------------------------------------------------------------------------------------------
DateFormat举例:给一个当前时间Date()对象,把它转换成英文格式。
public static void printUSDate(Date date){ Locale locale=new Locale("en","US"); DateFormat df=DateFormat.getDateInstance(DateFormat.MEDIUM, locale); System.out.println(df.format(date)); } public static void main(String args[]){ printUSDate(new Date()); }
打印:Jan 10, 2016。
上面的DateFormat.MEDIUM是啥?java源码注释:
/** * Constant for long style pattern. */ public static final int LONG = 1; /** * Constant for medium style pattern. */ public static final int MEDIUM = 2; /** * Constant for short style pattern. */ public static final int SHORT = 3; /** * Constant for default style pattern. Its value is MEDIUM. */ public static final int DEFAULT = MEDIUM;
把参数DateFormat.MEDIUM改成DateFormat.LONG,打印:January 10, 2016。
-------------------------------------------------------------------------------------------------------
MessageFormat:增加占位符功能。
什么是占位符功能?比如:我定义一个字符串:昨天{0}在{1}睡觉呢。传参{"小明","家"},那么打印:昨天小明在家睡觉呢。传参:{"大鹏","学校"},那么打印:昨天大鹏在学校睡觉呢。
举例1:银行给John说:John您好,你于XXX在招商银行存入XX元。不同时间,银行又对David说:David您好,你于XXX在招商银行存入XX元。信息相同,使用MessageFormat。参数信息可以动态改变。
public static void printBankNotice(Object[] params){ String pattern1="{0},你好,你于{1}在招商银行存入{2}元。"; String message1=MessageFormat.format(pattern1, params); System.out.println(message1); } public static void main(String args[]){ printBankNotice(new Object[]{"John",new GregorianCalendar().getTime(),1.0E3}); }
打印:John,你好,你于16-1-10 上午2:24在招商银行存入1,000元。
占位符功能还能对参数格式作适当的转换,参数顺序也可以灵活调整。
public static void printBankNotice2(Object[] params){ String pattern2="At{1,time,short} on{1,date,long},{0} paid {2,number,currency}."; MessageFormat mf=new MessageFormat(pattern2,Locale.US); System.out.println(mf.format(params)); } public static void main(String args[]){ printBankNotice2(new Object[]{"John",new GregorianCalendar().getTime(),1.0E3}); }
打印:At2:32 AM onJanuary 10, 2016,John paid $1,000.00.
---------------------------------------------------------------------------------------------------
应用程序中需要国际化,则使用java.util.ResourceBundle,
举例:定义一个英文的属性文件和一个中文的属性文件,里面放一些问候语,根据程序的需要选择不同语言的问候语。
步骤:
1.在程序的特定位置定义两个properties文件,一个是中文的,一个是英文的,名称格式为:
<资源名>_<语言代码>_<国家/地区编码>.properties
resource_en_US.properties内容:
greeting.common=How are you! greeting.morning = Good morning! greeting.afternoon =Good Afternoon\!
resource_zh_CN.properties内容:
greeting.common=\u60A8\u597D\uFF01 greeting.morning=\u65E9\u4E0A\u597D\uFF01 greeting.afternoon=\u4E0B\u5348\u597D\uFF01
(资源文件只能包含ASCII字符,所以你这样写了,程序运行时需要把这样的字符转换成Unicode的表示形式。但是这样编写我们不熟悉,也不现实,所以,MyEclipse提供了属性编辑器,可以方便我们写中文):
切换到Properties窗口:
在这里编写就好。
接下来使用ResourceBundle。
public static void resourceBoundle(){ ResourceBundle rb1 = ResourceBundle.getBundle("com/baobaotao/i18n/resource",Locale.US); ResourceBundle rb2 = ResourceBundle.getBundle("com/baobaotao/i18n/resource",Locale.CANADA); System.out.println("us:"+rb1.getString("greeting.common")); System.out.println("cn:"+rb2.getString("greeting.common")); }
上文讲到了占位符功能,在这里,你也可以把properties文件的属性值写成占位符形式,然后用ResourceBundle结合MessageFormat实现国际化字符串的动态改变。
---------------------------------------------------------------------------------------------------------
Spring的国际化
spring定义了MessageSource接口来实现国际化,它引入了java.util.Locale,并用getMessage方法加载国际化信息。也就是说,spring国际化的原理还是引用了上面讲的java的那一套,不过把它引入到了spring容器中。
类图结构:
根据继承关系我们看到,ResourceBundleMessageSource、ReloadableResourceBundleMessageSource、ApplicationContext都具有MessageSource功能。
-----------------------------------------------------------------------------------------------------------------------------------------------
ResourceBundleMessageSource是spring一般的国际化方法类。使用也很简单,
在XML中注册该类,容器启动时就会实例化该类:
<bean id="myResource1" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> </bean>
list里面可以放多个properties文件,这里fmt_resource是一个通用名,包含了该名下所有的properties文件,
在代码中,启动spring容器,加载MessageSource,定义格式化串,调用getMessage就可以了:
private static void rsrBdlMessageResource(){ String[] configs = {"com/baobaotao/i18n/beans.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(configs); //步骤1:获取MessageSource实例化对象 MessageSource ms = (MessageSource)ctx.getBean("myResource1"); //步骤2:定义格式化串 Object[] params = {"John", new GregorianCalendar().getTime()}; //步骤3:调用getMessage方法啊 String str1 = ms.getMessage("greeting.common",params,Locale.US); String str2 = ms.getMessage("greeting.morning",params,Locale.CHINA); String str3 = ms.getMessage("greeting.afternoon",params,Locale.CHINA); System.out.println(str1); System.out.println(str2); System.out.println(str3); }
-------------------------------------------------------------------------------------------------
ReloadableResourceBundleMessageSource:
跟ResourceBundleMessageSource相比,它多了一个定时刷新功能,即,系统在不重启的情况下,修改properties文件,使用ReloadableResourceBundleMessageSource重新加载(定时)。
在XML中注册bean的时候加一个定时属性就可以了:
<bean id="myResource2" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> <property name="cacheSeconds" value="2"/> </bean>
---------------------------------------------------------------------------------------------------------
ApplicationContext的国际化功能:
ApplicationContext属于容器级,它赋予了国际化信息功能,是因为国际化信息常常作为容器的公共基础设施对所有组件开放。
使用容器级国际化很简单,针对ResourceBundleMessageSource作一点点修改:
配置文件上的修改:
<bean id="mySource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>com/baobaotao/i18n/fmt_resource</value> </list> </property> </bean>
代码修改:
去掉getBean步骤,直接用ctx.getMessage获取字符串。
------------------------------------------------------------------------------------------------------
总结:
- 国际化信息又称为本地化信息,由语言类型(如zh)和国家/地区类型来限定(如CN)。
- java.util.Locale是创建国际化的基础类。
- NumberFormat(对数字转换成特定格式)、DateFormat(对日期输出为特定格式)、MessageFormat(使用占位符)等是操作国际化的工具类。
- 使用ResourceBundle类处理针对国际化的properties文件(命名规则有限定,如resource_en_US.properties)。
- spring管理国际化定义了MessageSource接口。
- ResourceBundleMessageSource实现了MessageSource接口。
- ReloadableResourceBundleMessageSource实现了MessageSource接口,多了定时更新国际化信息的功能。
- ApplicationContext实现了MessageSource接口,把国际化信息上升到了容器级。
玉不琢,不成器;人不学,不知道。——《礼记·学记》