• Step By Step(Java 国际化篇)


        Java编程语言是第一个设计成为全面支持国际化的语言。从一开始,它就具备了进行有效的国际化所必须的一个重要特征:使用Unicode来处理所有字符串。支持Unicode使得在Java编程语言中,编写程序来操作多种语言的字符串变得异常方便。多数程序员认为进行国际哈需要做的事情就是支持Unicode并在用户接口中对消息进行翻译。然而在实际的开发中,国际化一个程序所需要做的绝不仅仅是提供Unicode支持,它还包括日期、时间、货币和数字等格式上的差异。
        1.    Locales:
        需要依赖国际化的两个主要格式化类为NumberFormat和DateFormat,它们在通过工厂方法获取其实现子类时,都会依赖参数Locale来决定最终被实例化的子类,见如下代码:

    1     public static void main(String[] args) {
    2 Locale loc = new Locale("de","DE");
    3 NumberFormat currFmt = NumberFormat.getCurrencyInstance(loc);
    4 double amt = 123456.78;
    5 String result = currFmt.format(amt);
    6 System.out.println("The result = " + result);
    7 }
    8 /* 输出结果如下:
    9 The result = 123.456,78 ? */

        从结果可以看出原有的货币格式被转换为德语的格式了。以上例子是从数字格式化为字符串,同样还可以通过字符串转换为数字,但是这要依赖parse方法,见如下代码:

    1     public static void main(String[] args) throws ParseException {
    2 Locale loc = new Locale("de","DE");
    3 NumberFormat fmt = NumberFormat.getNumberInstance(loc);
    4 String amt = "123.456,78";
    5 double result = fmt.parse(amt).doubleValue();
    6 System.out.println("The result = " + result);
    7 }
    8 /* 输出结果如下:
    9 The result = 123456.78 */

        在上面的代码中都是通过直接给出ISO定义的语言和地区代码缩写的方式来构造Locale对象的,事实上Java中提供了一组预定义的Locale静态对象来表示不同的语言和地区的Locale实例,如:
        Locale.CANADA
        Locale.CANADA_FRENCH
        Locale.CHINA
        Locale.FRANCE
        Locale.GERMANY
        Locale.ITALY
        Locale.JAPAN
        Locale.KOREA
        ...
        以下的仅设定了语言而没有设定位置:
        Locale.CHINESE
        Locale.ENGLISH
        Locale.FRENCH
        Locale.GERMAN
        Locale.ITALIAN
        ...
        以下再给出几个关于Locale的示例代码:

     1     //设置缺省国际化Locale,注意:该操作只是修改当前应用程序的
    2 //本地化,而不是修改当前操作系统的。
    3 public static void main(String[] args) {
    4 Locale.setDefault(Locale.FRANCE);
    5 DateFormat df = DateFormat.getInstance();
    6 NumberFormat nf = NumberFormat.getInstance();
    7 System.out.println(df.format(new Date()));
    8 System.out.println(nf.format(123.4567));
    9 }
    10 /* 输出结果如下:
    11 26/08/11 23:28
    12 123,457 */
    13
    14 //获取当前机器支持语言的列表
    15 public static void main(String[] args) {
    16 Locale[] locales = Locale.getAvailableLocales();
    17 for (Locale loc : locales)
    18 System.out.println(loc.getDisplayName());
    19 }

        2.    数字格式:

     1     //将数组中的数字转换为指定的美国本地化显示格式
    2 public static void main(String[] args) {
    3 int data[] = { 100, 1000, 10000, 1000000 };
    4 NumberFormat nf = NumberFormat.getInstance(Locale.US);
    5 for (int i = 0; i < data.length; ++i) {
    6 System.out.println(data[i] + "\t" + nf.format(data[i]));
    7 }
    8 }
    9 //格式化BigDecimal
    10 public static void main(String[] args) {
    11 StringBuffer buffer = new StringBuffer();
    12 Locale it = Locale.ITALY;
    13 Locale.setDefault(it);
    14 BigDecimal rate = new BigDecimal(".03250000");
    15 BigDecimal months = new BigDecimal("12");
    16 BigDecimal monthlyRate = rate.divide(months, BigDecimal.ROUND_HALF_DOWN);
    17 NumberFormat pf = new DecimalFormat("#,##0.00000%");
    18 buffer.append("Annual rate : " + pf.format(rate.doubleValue()) + "\n");
    19 buffer.append("Monthly rate: " + pf.format(monthlyRate.doubleValue()) + "\n");
    20 BigDecimal balance = new BigDecimal("10000.0000");
    21 NumberFormat nf = NumberFormat.getCurrencyInstance();
    22 for (int i = 0; i < 12; i++) {
    23 BigDecimal interest = balance.multiply(monthlyRate);
    24 balance = balance.add(interest);
    25 buffer.append("Balance : " + nf.format(balance.doubleValue()) + "\n");
    26 }
    27 System.out.println(buffer.toString());
    28 }
    29 //格式化数字格式中主要的3中表示方式:数字、货币和百分比
    30 public class MyTest {
    31 static public void displayNumber(Locale currentLocale) {
    32 Integer quantity = new Integer(123456);
    33 Double amount = new Double(345987.246);
    34 NumberFormat numberFormatter;
    35 String quantityOut;
    36 String amountOut;
    37 numberFormatter = NumberFormat.getNumberInstance(currentLocale);
    38 quantityOut = numberFormatter.format(quantity);
    39 amountOut = numberFormatter.format(amount);
    40 System.out.println(quantityOut + " " + currentLocale.toString());
    41 System.out.println(amountOut + " " + currentLocale.toString());
    42 }
    43
    44 static public void displayCurrency(Locale currentLocale) {
    45 Double currency = new Double(9876543.21);
    46 NumberFormat currencyFormatter;
    47 String currencyOut;
    48 currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
    49 currencyOut = currencyFormatter.format(currency);
    50 System.out.println(currencyOut + " " + currentLocale.toString());
    51 }
    52
    53 static public void displayPercent(Locale currentLocale) {
    54 Double percent = new Double(0.75);
    55 NumberFormat percentFormatter;
    56 String percentOut;
    57 percentFormatter = NumberFormat.getPercentInstance(currentLocale);
    58 percentOut = percentFormatter.format(percent);
    59 System.out.println(percentOut + " " + currentLocale.toString());
    60 }
    61
    62 public static void main(String[] args) {
    63 Locale[] locales = { new Locale("fr", "FR"),
    64 new Locale("de", "DE"),
    65 new Locale("en", "US") };
    66 for (int i = 0; i < locales.length; i++) {
    67 System.out.println();
    68 displayNumber(locales[i]);
    69 displayCurrency(locales[i]);
    70 displayPercent(locales[i]);
    71 }
    72 }
    73 }

        3.    日历格式:

     1     //从不同的locale获取每周中的哪一天为周的第一天,并显示
    2 //不同locale针对星期的显示名称。
    3 public static void main(String[] args) {
    4 Locale usersLocale = Locale.getDefault();
    5
    6 DateFormatSymbols dfs = new DateFormatSymbols(usersLocale);
    7 String weekdays[] = dfs.getWeekdays();
    8 Calendar cal = Calendar.getInstance(usersLocale);
    9 //获取不同地区定义的哪一天是每周的第一天
    10 int firstDayOfWeek = cal.getFirstDayOfWeek();
    11 int dayOfWeek;
    12 //根据不同的每周第一天,遍历并显示不同地区针对星期的名称。
    13 for (dayOfWeek = firstDayOfWeek; dayOfWeek < weekdays.length; dayOfWeek++)
    14 System.out.println(weekdays[dayOfWeek]);
    15
    16 for (dayOfWeek = 0; dayOfWeek < firstDayOfWeek; dayOfWeek++)
    17 System.out.println(weekdays[dayOfWeek]);
    18 }
    19 //比较日本时区时间和本地时区时间
    20 public static void main(String[] args) {
    21 Calendar local = Calendar.getInstance();
    22 Calendar japanCal = new GregorianCalendar(TimeZone.getTimeZone("Japan"));
    23 japanCal.setTimeInMillis(local.getTimeInMillis());
    24 int jpHour = japanCal.get(Calendar.HOUR); // 3
    25 int jpMinutes = japanCal.get(Calendar.MINUTE); // 0
    26 int jpSeconds = japanCal.get(Calendar.SECOND); // 0
    27 System.out.println("Japan's time is Hour = " + jpHour + "\tMinutes = "
    28 + jpMinutes + "\tSeconds = " + jpSeconds);
    29 int localHour = local.get(Calendar.HOUR); // 3
    30 int localMinutes = local.get(Calendar.MINUTE); // 0
    31 int localSeconds = local.get(Calendar.SECOND); // 0
    32 System.out.println("Local's time is Hour = " + localHour + "\tMinutes = "
    33 + localMinutes + "\tSeconds = " + localSeconds);
    34 }

        4.    日期格式:

     1     //定义指定的日期格式化格式,再根据locale的不同,打印出不同的日期名称。
    2 public static void main(String[] args) {
    3 Locale locale = Locale.ENGLISH;
    4 //SimpleDateFormat对象的构造函数中,如果没有显示的传入locale对象,
    5 //该对象在解析和格式化的过程中将使用缺省的本地化对象。
    6 DateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy", locale);
    7 DateFormat formatter2 = new SimpleDateFormat("HH:mm:ss zzzz", locale);
    8 System.out.println("Result = " + formatter.format(new Date()));
    9 System.out.println("Result2 = " + formatter2.format(new Date()));
    10 //定义指定格式的日期格式化对象,在结合Locale对象去格式化当前时间。
    11 Date date = new Date();
    12 String s = DateFormat.getTimeInstance(DateFormat.SHORT, locale).format(date);
    13 System.out.println(s);
    14
    15 //使用缺省的本地化locale格式化日期和数字,这里DateFormat和NumberFormat工厂方法
    16 //将会根据不同的locale来实例化不同的DateFormat和NumberFormat的实现类,然而这些
    17 //逻辑对使用者是完全透明的。
    18 DateFormat df = DateFormat.getInstance();
    19 NumberFormat nf = NumberFormat.getInstance();
    20 System.out.println(df.format(new Date()));
    21 System.out.println(nf.format(123.4567));
    22 }
    23 //根据不同的时间Pattern、日期Pattern、日期时间Pattern,连同不同的Locale参数来
    24 //构造出DateFormat的实现子类,在格式化指定的日期对象。
    25 public class MyTest {
    26 static public void displayDate(Locale currentLocale) {
    27 DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT,
    28 currentLocale);
    29 Date today = new Date();
    30 String dateOut = dateFormatter.format(today);
    31 System.out.println(dateOut + " " + currentLocale.toString());
    32 }
    33
    34 static public void showBothStyles(Locale currentLocale) {
    35 int[] styles = { DateFormat.DEFAULT, DateFormat.SHORT,
    36 DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL };
    37 System.out.println("Locale: " + currentLocale.toString());
    38 Date today = new Date();
    39 for (int k = 0; k < styles.length; k++) {
    40 DateFormat formatter = DateFormat.getDateTimeInstance(styles[k], styles[k],
    41 currentLocale);
    42 String result = formatter.format(today);
    43 System.out.println(result);
    44 }
    45 }
    46
    47 static public void showDateStyles(Locale currentLocale) {
    48 Date today = new Date();
    49 int[] styles = { DateFormat.DEFAULT, DateFormat.SHORT,
    50 DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL };
    51 System.out.println("Locale: " + currentLocale.toString());
    52 for (int k = 0; k < styles.length; k++) {
    53 DateFormat formatter = DateFormat.getDateInstance(styles[k], currentLocale);
    54 String result = formatter.format(today);
    55 System.out.println(result);
    56 }
    57 }
    58
    59 static public void showTimeStyles(Locale currentLocale) {
    60 Date today = new Date();
    61 int[] styles = { DateFormat.DEFAULT, DateFormat.SHORT,
    62 DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL };
    63 System.out.println("Locale: " + currentLocale.toString());
    64 for (int k = 0; k < styles.length; k++) {
    65 DateFormat formatter = DateFormat.getTimeInstance(styles[k], currentLocale);
    66 String result = formatter.format(today);
    67 System.out.println(result);
    68 }
    69 }
    70
    71 static public void main(String[] args) {
    72 Locale[] locales = { Locale.CHINA,new Locale("en", "US") };
    73 for (int i = 0; i < locales.length; i++)
    74 displayDate(locales[i]);
    75 showDateStyles(new Locale("en", "US"));
    76 showDateStyles(Locale.CHINA);
    77 showTimeStyles(new Locale("en", "US"));
    78 showTimeStyles(Locale.CHINA);
    79 showBothStyles(new Locale("en", "US"));
    80 showBothStyles(Locale.CHINA);
    81 }
    82 }

        5.    字符排序:
        大多数程序员都知道如何使用String类中的compareTo方法对字符串进行比较。但是由于大小写字符的ASCII值之间的差异,既小写字符总是大于大写字符,因此很多时候排序的结果并非程序员所真正希望得到的。然而有些时候,排序的问题不仅仅被大小写的问题所困扰,使用不同的本地化(Locale)对象,得到的排序规则往往也是不同的,比如在有些语言中存在重音符,其值更是大于小写字符,基于这样的排序结果也就失去的排序的真正意义。在Java中提供了Collator对象(Comparator的实现类),因此在当需要对字符串进行排序时,可以使用该类的工厂方法针对不同的Locale生成一个Collator的子类,之后在传给如Collections.sort这样的排序方法来完成实际的排序,如下例:

     1     static public void main(String[] args) {
    2 List<String> fruits = new ArrayList<String>();
    3 fruits.add("A");
    4 fruits.add("é");
    5 fruits.add("C");
    6 fruits.add("D");
    7 fruits.add("A");
    8 Collator collator = Collator.getInstance(Locale.US);
    9 Collections.sort(fruits, collator);
    10 for (int i = 0; i < fruits.size(); i++) {
    11 String fruit = fruits.get(i);
    12 System.out.println("Fruit = " + fruit);
    13 }
    14 }
    15 /* 结果如下:
    16 Fruit = A
    17 Fruit = A
    18 Fruit = C
    19 Fruit = D
    20 Fruit = é
    21 */

        在Collator中提供了不同的排序强度,字符间的差别主要区分为PRIMARY、SECONDARY和TERTIARY三种,PRIMARY差别将主要关注字符间的主要差异,如A和Z之间就是主要的差异,而é和"É"(法语)之间的差别为SECONDARY,最后"A"和"a"之间的差异为TERTIARY。由此看出,排序强度越高,其区分字符间的差异性就越差,见下例:

     1     static public void main(String[] args) {
    2 String s1 = "é";
    3 String s2 = "É";
    4
    5 Collator frCollator = Collator.getInstance(Locale.FRANCE);
    6 System.out.println("The current strength is PRIMARY.");
    7 frCollator.setStrength(Collator.PRIMARY);
    8 if (frCollator.compare(s1, s2) == 0)
    9 System.out.println("s1 = s2");
    10 System.out.println("The current strength is SECONDARY.");
    11 frCollator.setStrength(Collator.SECONDARY);
    12 if (frCollator.compare(s1, s2) == 0)
    13 System.out.println("s1 = s2");
    14 System.out.println("The current strength is TERTIARY.");
    15 frCollator.setStrength(Collator.TERTIARY);
    16 if (frCollator.compare(s1, s2) == 0)
    17 System.out.println("s1 = s2");
    18 }
    19 /* 输出结果如下:
    20 The current strength is PRIMARY.
    21 s1 = s2
    22 The current strength is SECONDARY.
    23 s1 = s2
    24 The current strength is TERTIARY.
    25 */

        从输出结果中可以看出,当排序强度将为TERTIARY时,这两个字符将被视为不同的字符了。
        6.    消息格式化:

     1     //这里演示了MessageFormat的最基本用法:
    2 // {0,time}: 0表示第0个占位符,time表示该占位符的格式为时间,如不指定style,按缺省格式显示。
    3 // {1,number}: 1表示第1个占位符,number表示该占位符为数字。
    4 static public void main(String[] args) {
    5 String pattern = "The time is {0,time} and your lucky number is {1,number}.";
    6 MessageFormat format = new MessageFormat(pattern);
    7 Object objects[] = {new Date(),new Integer((int)(Math.random() * 1000))};
    8 String formattedOutput = format.format(objects);
    9 System.out.println(formattedOutput);
    10
    11 pattern = "The datetime is {0} and your lucky number is {1}.";
    12 format = new MessageFormat(pattern);
    13 //指定Locale
    14 format.setLocale(Locale.US);
    15 formattedOutput = format.format(objects);
    16 System.out.println(formattedOutput);
    17 format.setLocale(Locale.CHINA);
    18 formattedOutput = format.format(objects);
    19 System.out.println(formattedOutput);
    20 }
    21 /* 输出结果如下:
    22 The time is 10:47:47 and your lucky number is 97.
    23 The datetime is 8/28/11 10:47 AM and your lucky number is 97.
    24 The datetime is 11-8-28 上午10:47 and your lucky number is 97.
    25 */

        Java针对Message中占位符的type,不仅提供了常规的number、time和date,还提供了choice格式,见如下例句:
        String pattern = "On {2,date,long},{0} destroyed {1} houses and caused {3,number,currency} of damage";
        注意占位符{1},尽管没有明确标注,仍然可以推测出它是number类型的。这里存在的主要问题是{1}后面的houses是复数格式,因此如果参数设置为1,则不符合英文的语法1 houses。再有就是如果参数设置为0,则更加奇怪"0 houses"。根据英文的语法规则,我们期待的格式是如果数量>=2,显示n houses,如果等于1,显示1 house,如果<=0,显示no house。如何完成这个功能呢?这里我们可以利用Java中给占位符提供的另外一种type: choice。其语法规则如下:
        一个选择格式是由一个序列对组成,每一个对包括一个下限和一个格式字符串,下限和格式字符串由一个#符号分隔,对与对之间由符号|分隔。如:
        {1,choice,0#no house|1#one house|2#{1} houses}
         如果不使用选择格式,又希望实现刚刚说到的逻辑,就需要手工进行数量的判断,再根据数量的不同定义不同的pattern,如果使用选择格式,代码将会更加清晰明确,如:
        String pattern = "On {2,date,long},{0} destroyed {1,choice,0#no house|1#one house|2#{1} houses} houses and caused {3,number,currency} of damage";
         7.    字符集:
         在进行byte和char之间的转换时,不同编码方式的字符集提供了不同的编码(encode)和解码(decode)规则,见如下代码:

     1     public class MyTest {
    2 public static void print(ByteBuffer bb) {
    3 while (bb.hasRemaining())
    4 System.out.print(bb.get() + " ");
    5 System.out.println();
    6 bb.rewind();
    7 }
    8
    9 public static void main(String[] args) {
    10 ByteBuffer bb = ByteBuffer.wrap(new byte[] { 0, 0, 0, 0, 0, 0, 0,
    11 (byte) 'a' });
    12 System.out.println("Initial Byte Buffer");
    13 print(bb);
    14 //提供了几种常用的字符集
    15 Charset[] csets = { Charset.forName("UTF-16LE"),
    16 Charset.forName("UTF-16BE"), Charset.forName("UTF-8"),
    17 Charset.forName("US-ASCII"), Charset.forName("ISO-8859-1") };
    18 for (int i = 0; i < csets.length; i++) {
    19 System.out.println(csets[i].name() + ":");
    20 //编码显示
    21 print(csets[i].encode(bb.asCharBuffer()));
    22 //解码用于下一次迭代
    23 csets[i].decode(bb);
    24 bb.rewind();
    25 }
    26 }
    27 }
    28 //根据指定的字符集,将数据在CharBuffer和ByteBuffer之间做转换(编码和解码)
    29 public static void main(String[] args) throws CharacterCodingException {
    30 //由于有中文的存在,因此这里需要是用UTF-8的字符集,如果使用其他
    31 //的西方字符集会导致encode抛出异常。
    32 Charset charset = Charset.forName("UTF-8");
    33 // An engine that can transform a sequence of bytes in a specific
    34 // charset into a sequence of sixteen-bit Unicode characters.
    35 // from byte to unicode
    36 CharsetDecoder decoder = charset.newDecoder();
    37 // An engine that can transform a sequence of sixteen-bit Unicode
    38 // characters into a sequence of bytes in a specific charset.
    39 // from unicode to byte
    40 CharsetEncoder encoder = charset.newEncoder();
    41 ByteBuffer bbuf = ByteBuffer.allocate(1024);
    42 CharBuffer cbuf = CharBuffer.allocate(1024);
    43 String tmp = "HelloWorld123你好";
    44 cbuf.put(tmp);
    45 cbuf.flip();
    46 //或者直接给CharBuffer赋值,如:
    47 //cbuf = CharBuffer.wrap("HelloWorld123你好");
    48 //该语句相当于上面3条语句的功能。
    49
    50 //注:在encode内部已经调用了bbuf.flip(),如果外部重复调用,会导致后面的
    51 //decode返回空值。
    52 bbuf = encoder.encode(cbuf);
    53 byte[] buf = bbuf.array();
    54 String s = new String(buf,charset);
    55 System.out.println("ByteBuffer = " + s);
    56 //注:在decode内部已经调用了cbuf.flip(),如果外部重复调用,会导致后面
    57 //打印空值。
    58 cbuf = decoder.decode(bbuf);
    59 System.out.println("CharBuffer = " + cbuf.toString());
    60 }

        8.    资源包:
        经常会遇到这样的情形,我们应用程序中的大量字符串信息需要被翻译成各种不同的语言,如英文、德文等。我们常用的方式是自定义包含各种不同语言信息的文件,并通过文件名来标识其所属的语种。我们的应用程序在根据当前不同的locale来选择不同的语言资源文件。在Windows的MFC中,是通过一种被称为字符表的资源来存储这些信息的。在Java中,JDK同样提供了其自身的支持--资源包。
        和我们想象的一样,JDK也是通过将不同语言的字符串信息存放在不同的资源文件中,同时也定义了语言资源文件的文件命名规则:包名_语言_国家,如MyProgramStrings_de_DE。如果locale = new Locale("de","DE");该资源文件将会被加载。既然Java已经为我们提供了这样的方法,我们还是应该充分的利用这一规则。事实上,和我们预想的非常相似,该资源文件也是以键值对的方式存储资源信息的,如下面的德文和英文资源文件:
        File: MessageBundle_en_US.properties
        planet = Mars
        template = At {2,time,short} on {2,date,long}, we detected {1,number,integer} spaceships on the planet {0}.
       
        File: MessageBundle_de_DE.properties
        planet = Mars
        template = Um {2,time,short} am {2,date,long} haben wir {1,number,integer} Raumschiffe auf dem Planeten Mars entdeckt.
        将以上两个文件copy到工程的bin目录下,再执行下面的示例代码:

     1     public class MyTest {
    2 static void displayMessage(Locale currentLocale) {
    3 System.out.println("currentLocale = " + currentLocale.toString());
    4 //getBundle的第一个参数是资源文件的前缀,后缀则根据Locale来定义。
    5 ResourceBundle messages = ResourceBundle.getBundle("MessageBundle",currentLocale);
    6 Object[] messageArguments = { messages.getString("planet"),
    7 new Integer(7), new Date() };
    8 MessageFormat formatter = new MessageFormat("");
    9 formatter.setLocale(currentLocale);
    10 formatter.applyPattern(messages.getString("template"));
    11 String output = formatter.format(messageArguments);
    12 System.out.println(output);
    13 }
    14
    15 public static void main(String[] args) {
    16 displayMessage(new Locale("en", "US"));
    17 displayMessage(new Locale("de", "DE"));
    18 }
    19 }
    20 /* 输出结果如下:
    21 currentLocale = en_US
    22 At 9:27 PM on August 29, 2011, we detected 7 spaceships on the planet Mars.
    23 currentLocale = de_DE
    24 Um 21:27 am 29. August 2011 haben wir 7 Raumschiffe auf dem Planeten Mars entdeckt.
    25 */

         以下示例结合了ChoiceFormat和ResourceBundle,资源文件内容如下:
        File: ChoiceBundle_en_US.properties
        noFiles = are no files
        oneFile = is one file
        multipleFiles = are {2} files
        pattern = There {0} on {1}.
       
        File: ChoiceBundle_fr_FR.properties
        noFiles = n' y a pas des fichiers
        oneFile = y a un fichier
        multipleFiles = y a {2} fichiers
        pattern = Il {0} sur {1}.
        见代码如下:

     1     public class MyTest {
    2 static void displayMessages(Locale currentLocale) {
    3 System.out.println("currentLocale = " + currentLocale.toString());
    4 //1. 根据Locale的不同,获取不同的资源文件
    5 ResourceBundle bundle = ResourceBundle.getBundle("ChoiceBundle",currentLocale);
    6 MessageFormat messageForm = new MessageFormat("");
    7 //2. 给MessageFormat对象设定locale,便于资源文件的定位。
    8 messageForm.setLocale(currentLocale);
    9 //3. 设定ChoiceFormat下限部分
    10 double[] fileLimits = { 0, 1, 2 };
    11 //4. 从资源文件中读取指定的key/value,之后再初始化ChoiceFormat的选择部分。
    12 String[] fileStrings = { bundle.getString("noFiles"),
    13 bundle.getString("oneFile"), bundle.getString("multipleFiles") };
    14 ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);
    15 //5. 根据资源文件中“pattern”键值对来定义MessageFormat的pattern部分。
    16 String pattern = bundle.getString("pattern");
    17 //6. 定义MessageFormat.pattern的格式信息。
    18 Format[] formats = { choiceForm, null, NumberFormat.getInstance() };
    19 messageForm.applyPattern(pattern);
    20 messageForm.setFormats(formats);
    21 //7. 定义和formats对应的格式参数。
    22 Object[] messageArguments = { null, "XDisk", null };
    23 for (int numFiles = 0; numFiles < 4; numFiles++) {
    24 //8. 重新设定格式参数中第0个和第2个参数的值,该值为被ChoiceFormat利用,
    25 //并根据该参数值的不同选择不同的Choice字符串来替换。
    26 messageArguments[0] = new Integer(numFiles);
    27 messageArguments[2] = new Integer(numFiles);
    28 //9. 开始格式化了。
    29 String result = messageForm.format(messageArguments);
    30 System.out.println(result);
    31 }
    32 }
    33
    34 public static void main(String[] args) {
    35 displayMessages(new Locale("en", "US"));
    36 displayMessages(new Locale("fr", "FR"));
    37 }
    38 }
    39 /* 输出结果如下:
    40 currentLocale = en_US
    41 There are no files on XDisk.
    42 There is one file on XDisk.
    43 There are 2 files on XDisk.
    44 There are 3 files on XDisk.
    45 currentLocale = fr_FR
    46 Il n' y a pas des fichiers sur XDisk.
    47 Il y a un fichier sur XDisk.
    48 Il y a 2 fichiers sur XDisk.
    49 Il y a 3 fichiers sur XDisk.
    50 */

        Java不仅提供了资源包文件的方式来包含不同语言的资源信息,还提供了资源包类的方式,其命名规则和资源包的规则一致,只是扩展名由".properties"替换为".java",其内容也从键值对的配置文件改为java的代码文件。资源包中定义的类必须是扩展自ResourceBundle类,使用方式和资源包配置文件的方式完全一致。见下面的示例代码:

     1     //File: SimpleResourceBundle.java
    2 public class SimpleResourceBundle extends ResourceBundle {
    3 @Override
    4 protected Object handleGetObject(String key) {
    5 if (key.equals("AMMessage"))
    6 return "早上好";
    7 if (key.equals("PMMessage"))
    8 return "晚上好";
    9 return null;
    10 }
    11 @Override
    12 public Enumeration getKeys() {
    13 StringTokenizer keyTokenizer = new StringTokenizer(keys);
    14 return keyTokenizer;
    15 }
    16 private String keys = "AMMessage PMMessage";
    17 }
    18 //File: SimpleResourceBundle_en_US.java
    19 public class SimpleResourceBundle_en_US extends ResourceBundle {
    20 @Override
    21 protected Object handleGetObject(String key) {
    22 if (key.equals("AMMessage"))
    23 return "Good morning";
    24 if (key.equals("PMMessage"))
    25 return "Good evening";
    26 return null;
    27 }
    28 @Override
    29 public Enumeration getKeys() {
    30 StringTokenizer keyTokenizer = new StringTokenizer(keys);
    31 return keyTokenizer;
    32 }
    33 private String keys = "AMMessage PMMessage";
    34 }
    35
    36 //调用类代码如下:
    37 public static void main(String[] args) {
    38 try {
    39 //由于使用缺省的locale,因此在定义资源包类的文件时,可以不包含locale相关的后缀。
    40 ResourceBundle rb = ResourceBundle.getBundle("SimpleResourceBundle");
    41 System.out.println(rb.getString("AMMessage"));
    42 System.out.println(rb.getString("PMMessage"));
    43 //由于给ResourceBundle的工厂方法传入了Locale参数,因此会获取US的资源包绑定类。
    44 ResourceBundle rb_US = ResourceBundle.getBundle("SimpleResourceBundle",Locale.US);
    45 System.out.println(rb_US.getString("AMMessage"));
    46 System.out.println(rb_US.getString("PMMessage"));
    47 } catch (MissingResourceException mre) {
    48 mre.printStackTrace();
    49 }
    50 }
    51 /* 输出结果如下:
    52 早上好
    53 晚上好
    54 Good morning
    55 Good evening
    56 */

        在Java中还提供了另外一种更为方便的资源包绑定类的实现方式,既直接扩展ListResourceBundle类,ListResourceBundle让你把所有资源都放到一个对象数组并提供查询功能,见如下代码:

     1     //File: SimpleResourceBundle_de_DE.java
    2 public class SimpleResourceBundle_de_DE extends ListResourceBundle {
    3 public Object[][] getContents() {
    4 return contents;
    5 }
    6
    7 private static final Object[][] contents = {
    8 {"backgroundColor",Color.black},
    9 {"defaultPaperSize",new double[]{210,297}}
    10 };
    11 }
    12 //File: SimpleResourceBundle_en_US.java
    13 public class SimpleResourceBundle_en_US extends ListResourceBundle {
    14 public Object[][] getContents() {
    15 return contents;
    16 }
    17
    18 private static final Object[][] contents = {
    19 {"backgroundColor",Color.blue},
    20 {"defaultPaperSize",new double[]{216,279}}
    21 };
    22 }
    23 //主程序文件
    24 public static void main(String[] args) {
    25 try {
    26 ResourceBundle rb = ResourceBundle.getBundle("SimpleResourceBundle",Locale.GERMANY);
    27 Color bg = (Color)rb.getObject("backgroundColor");
    28 double[] paperSize = (double[])rb.getObject("defaultPaperSize");
    29 System.out.println("Germany Color is " + bg);
    30 System.out.println("Germany paperSize is x = " + paperSize[0] + "\ty = " + paperSize[1]);
    31 ResourceBundle rb_US = ResourceBundle.getBundle("SimpleResourceBundle",Locale.US);
    32 bg = (Color)rb_US.getObject("backgroundColor");
    33 paperSize = (double[])rb_US.getObject("defaultPaperSize");
    34 System.out.println("US Color is " + bg);
    35 System.out.println("US paperSize is x = " + paperSize[0] + "\ty = " + paperSize[1]);
    36 } catch (MissingResourceException mre) {
    37 mre.printStackTrace();
    38 }
    39 }
    40 /* 输出结果如下:
    41 Germany Color is java.awt.Color[r=0,g=0,b=0]
    42 Germany paperSize is x = 210.0 y = 297.0
    43 US Color is java.awt.Color[r=0,g=0,b=255]
    44 US paperSize is x = 216.0 y = 279.0
    45 */
  • 相关阅读:
    出差常熟,郁闷中 沧海
    ABAP中程序之间传递参数的办法 沧海
    LSMW中出现No logical path specified. 沧海
    请认真对待生活 沧海
    escape sequence 沧海
    休假一周 沧海
    Print Program and Form Modify 沧海
    下周回南京 沧海
    LO020真麻烦 沧海
    函数讲解函数列表(ZT) 沧海
  • 原文地址:https://www.cnblogs.com/orangeform/p/2156516.html
Copyright © 2020-2023  润新知