国际化的程序实现及其原理
国际化的程序实现原理
所谓的国际化的程序指的是可以根据不同的国家实现不同的语言描述,但是程序处理的核心业务是相同的
--如果想要进行国际化的程序开发需要解决如下问题:
a.如何可以定义保存文字的文件信息
b.如何额可以根据不同的区域语言的编码读取指定的资源信息
一.Locale类
--通过分析发现,如果想要实现国际化,那么首先需要解决的就是不同国家用户的区域和语言编码的问题,而在java.util包中提供有一个专门描述区域和语言编码的类
--而后主要可以使用Locale中的两个构造方法进行实例化
Locale(String language)
从语言代码构建语言环境。
Locale(String language, String country)
从语言和国家构建语言环境。
Locale(String language, String country, String variant)
从语言,国家和变体构建语言环境。
--国际化对照表参考:每个国家对应的语言Locale和国家代码对照表--此时需要的是国家和语言的代码,而中文的代码为:zh_CN 美国英语的代码:en_US
--范例:实例化Local对象
1 public class MyLocale {
2 public static void main(String[] args) {
3 Locale locale = new Locale("zh","cn"); //表示中文环境
4 System.out.println(locale);
5 }
6 }
--运行结果
zh_CN
--如果说想要自动获得当前的运行环境,那么就可以利用Local类本身默认的方式进行实例化:
static Locale getDefault()
获取Java虚拟机的此实例的默认语言环境的当前值。
1 public class MyLocale {
2 public static void main(String[] args) {
3 Locale locale = new Locale("en","us"); //表示英文环境
4 System.out.println(locale);
5 System.out.println(Locale.getDefault());
6 }
7 }
--运行结果
en_US
zh_CN
Process finished with exit code 0
--在实际的开发过程之中,很多人可能并不关心国家和语言的编码,所以为了简化开发,Locale类也将世界上比较著名的语言的代码参数设置为了常量:
static Locale CANADA
对国家有用的常数。
static Locale CANADA_FRENCH
对国家有用的常数。
static Locale CHINA
对国家有用的常数。
static Locale CHINESE
有用的语言常数
static Locale ENGLISH
有用的语言常数
static Locale FRANCE
对国家有用的常数。
static Locale FRENCH
有用的语言常数
static Locale GERMAN
有用的语言常数
static Locale GERMANY
对国家有用的常数。
static Locale ITALIAN
有用的语言常数
static Locale ITALY
对国家有用的常数。
static Locale JAPAN
对国家有用的常数。
static Locale JAPANESE
有用的语言常数
static Locale KOREA
对国家有用的常数。
static Locale KOREAN
有用的语言常数
static Locale PRC
对国家有用的常数。
static char PRIVATE_USE_EXTENSION
私人使用扩展('x')的关键。
static Locale ROOT
根区域的常用常数。
static Locale SIMPLIFIED_CHINESE
有用的语言常数
static Locale TAIWAN
对国家有用的常数。
static Locale TRADITIONAL_CHINESE
有用的语言常数
static Locale UK
对国家有用的常数。
static char UNICODE_LOCALE_EXTENSION
Unicode区域扩展('u')的关键。
static Locale US
对国家有用的常数。
--运行结果
1 public class MyLocale {
2 public static void main(String[] args) {
3 Locale locale = new Locale("en","us"); //表示英文环境
4 System.out.println(locale);
5 System.out.println(Locale.getDefault());
6 System.out.println(Locale.CHINA + " " + Locale.US);
7 }
8 }
en_US
zh_CN
zh_CN en_US
Process finished with exit code 0
二.读取资源文件 ResourceBundle
--当我们准备好资源文件,那么随后就需要进行资源文件耳朵读取操作,可以使用java.util.ResourceBundle类来完成,此类的定于如下
public abstract class ResourceBundle
extends Object
可以发现ResourceBundle类是一个抽象类,如果说现在想要进行此类对象的实例化,可以直接利用该类中提供的静态方法来完成
static ResourceBundle getBundle(String baseName)
使用指定的基本名称,默认语言环境和调用者的类加载器获取资源包。
static ResourceBundle getBundle(String baseName, Locale locale)
使用指定的基本名称和区域设置以及调用者的类加载器获取资源包。
static ResourceBundle getBundle(String baseName, Locale locale, ClassLoader loader)
使用指定的基本名称,区域设置和类加载器获取资源包。
static ResourceBundle getBundle(String baseName, Locale targetLocale, ClassLoader loader, ResourceBundle.Control control)
使用指定的基本名称,目标语言环境,类加载器和控件返回资源包。
static ResourceBundle getBundle(String baseName, Locale targetLocale, ResourceBundle.Control control)
使用指定的基本名称,目标语言环境和控件以及调用者的类加载器返回资源包。
static ResourceBundle getBundle(String baseName, ResourceBundle.Control control)
使用指定的基本名称,默认语言环境和指定的控件返回资源包。
--baseName是资源文件的名称,但是没有后缀
--范例:使用ResourceBundle类读取内容,如果资源没有放在包里面,则直接编写资源名称即可
--在这里,需要注意一下资源文件的编写事项,如梭我们直接在资源文件中书写中文字符,那么在使用ResourceBundle类的静态方法获取到资源文件时,得到的结果将会是乱码
1 class MyResourceBundle{
2 public static void main(String[] args) {
3 ResourceBundle message = ResourceBundle.getBundle("message");
4 System.out.println(message.getString("welcome"));
5 }
6 }
--运行结果
"»¶ÓÀ´µ½XXXϵͳ"
Process finished with exit code 0
--为了避免这种现象的发生,我们需要将中文字符转化为Unicode码.可以通过JDK安装路径下bin文件中的该工具实现
--将该转义结果复制到我们的资源文件中
--再次执行程序得到结果
1 class MyResourceBundle{
2 public static void main(String[] args) {
3 ResourceBundle message = ResourceBundle.getBundle("message");
4 System.out.println(message.getString("welcome"));
5 }
6 }
--运行结果
欢迎来到XXX系统
Process finished with exit code 0
--如果说没有读取到我们的资源文件,会出现如下异常
Exception in thread "main" java.util.MissingResourceException: Can't find bundle for base name messagse, locale zh_CN
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1573)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1396)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:782)
at 常用类库.国际化编程.MyResourceBundle.main(MyLocale.java:20)
Process finished with exit code 1
--在进行资源读取的时候,获取的资源文件的key值必须存在,否则会发生如下异常
Exception in thread "main" java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key welcomes
at java.util.ResourceBundle.getObject(ResourceBundle.java:450)
at java.util.ResourceBundle.getString(ResourceBundle.java:407)
at 常用类库.国际化编程.MyResourceBundle.main(MyLocale.java:21)
三.实现国际化程序
--在完成国际化程序实现的前期准备完成之后,就可以依靠资源文件,Locale类以及ResourceBundle类来完成国际化程序的处理操作
--范例:进行国际化的程序实现(核心关键:读取资源信息)
1.在CLASSPATH下建立国际化源文件:
--将之前所建立的无区域的资源文件也放入test包中,其中共有三个可供选择的资源文件
--通过程序进行指定区域的资源文件的加载
1 class LocaleTest {
2 public static void main(String[] args) {
3 ResourceBundle bundle = ResourceBundle.getBundle("test.Messages");
4 System.out.println(bundle.getString("welcome"));
5 }
6 }
--运行结果
欢迎来到XXX系统
Process finished with exit code 0
--我们发现在使用ResourceBundle进行资源文件读取时并没有指定一个明确的Locale对象,但是发现中文的资源文件起作用了,因为这个方法里面默认加载的就是当前本地的资源文件
1 @CallerSensitive
2 public static final ResourceBundle getBundle(String baseName)
3 {
4 return getBundleImpl(baseName, Locale.getDefault(),
5 getLoader(Reflection.getCallerClass()),
6 getDefaultControl(baseName));
7 }
--可以发现在方法内部调用了Locale.getDefault()方法获取当前的区域编码,如果现在有需要也可以修改当前的Locale环境,则可以使用ResourceBundle类中的如下方法
1 class LocaleUSTest{
2 public static void main(String[] args) {
3 ResourceBundle bundle = ResourceBundle.getBundle("test.Messages",Locale.US);
4 System.out.println(bundle.getString("welcome"));
5 }
6 }
--运行结果
welcome to this system
Process finished with exit code 0
--如果现在有指定区域的资源文件存在的时候,那么没有设置区域的资源文件的信息将不会被读取,例如读取不存在资源文件的区域代码时,则将会读取我们本地的资源文件
1 class LocaleUSTest{
2 public static void main(String[] args) {
3 ResourceBundle bundle = ResourceBundle.getBundle("test.Messages",Locale.UK);
4 System.out.println(bundle.getString("welcome"));
5 }
6 }
--运行结果
欢迎来到XXX系统
Process finished with exit code 0
--当然如果本地的区域资源文件也不存在时,那么读取的就是没有区域的资源文件,即读取的先后顺序为:
读取指指定区域的资源文件 > 默认的本地资源 > 没有区域设置的资源文件
四.消息格式化
--如果说现在某一个用户登录成功了,那么一般都会显示这样的信息,"XXX,欢迎您的光临",那么此时如果这些内容保存在了资源文件里面,则就需要通过占位符来进行描述,同时对于读取出来的数据也需要进行消息格式化,正如上文所说的欢迎来到XXX系统,那么这个XXX就是需要格式化的字符串内容,但是XXX这样的预留显得并不是特别方便,常规的可以使用{0}{1}这样的形式占位,对资源文件作出如下修改
--此时如果要进行文件的资源读取,那么占位符的信息也将一起读取出来,所以此时就需要利用MessageFormat类来完成,我们可以发现MessageFormat类是Format类的子类
1 Class MessageFormat
2 java.lang.Object
3 java.text.Format
4 java.text.MessageFormat
--范例,实现国际化:
1 class MyMessageFormatDemo{
2 public static void main(String[] args) {
3 ResourceBundle bundle = ResourceBundle.getBundle("test.Messages");
4 String welcome = bundle.getString("welcome");
5 String format = MessageFormat.format(welcome, "\n国际化模拟程序\n");
6 System.out.println(format);
7 }
8 }
--运行结果
1 欢迎来到
2 国际化模拟程序
3 系统
4
5 Process finished with exit code 0
--在实际的开发过程之中,见到资源文件中出现有{0},{1}这样的结构,说明该信息一定是占位符,需要惊进行信息的格式化