一、简介

国际化是指在程序运行时可以根据客户端请求中的国家(地区)、语言的信息而显示不同的界面。国际化的英文单词为Internationalization,简称I18N(I、N分别为第一个和最后一个字母,18为中间省略的字母数)。

1、国际化相关类

  • java.util.ResourceBundle

    加载某个国家、语言的资源包。

  • java.util.Locale

    表示一个特定的国家(地区)、语言环境。

  • java.text.MessageFormat

    格式化带占位符的字符串。

2、国际化原理

将需要做国际化的内容(标签、提示信息等)放在资源文件中,并提供不同国家、语言的资源文件。资源文件命名如下:

其中,languagecountry必须是Java支持的语言和国家(Java支持的语言和国家可以通过Locale.getAvailableLocales()查看)。

  • baseName_language_country.properties

  • baseName_language.properties

  • baseName.properties

二、使用国际化

1、定义资源文件

  • app_en_US.properties
hi=Hello
  • app_zh_CN.properties
hi=\u4F60\u597D

如果资源文件中包含了非西欧字符,则需要将这些字符转为对应的Unicode编码,Java提供了native2ascii的工具,此工具在Java安装目录的bin目录下(%JAVA-HOME%/bin/native2ascii.exe)。

在命令行下执行:native2ascii app_zh_CN.properties app.properties即可将hi=你好转换为hi=\u4F60\u597D

2、在程序中加载资源文件

public static void main(String[] args) {
	Locale locale = Locale.getDefault();
	String baseName = "app";
	String key = "hi";
	//按Locale加载指定的资源文件
	ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale);
	System.out.println(bundle.getString(key));
	
	locale = Locale.US;
	bundle = ResourceBundle.getBundle(baseName, locale);
	System.out.println(bundle.getString(key));
}
  • 程序输出
你好
Hello

3、处理包含占位符的字符串

可以使用MessageFormat来处理包含占位符的字符串,例如:你好,{0}!现在是{1}。;需要用到的方法为format方法,方法定义如下:

java.text.MessageFormat.format(String, Object...)
  • 样例
String pattern = "你好,{0}!现在是{1}。";
System.out.println(MessageFormat.format(pattern, "Tom", new Date()));
  • 程序输出
你好,Tom!现在是18-8-4 下午6:42。

4、使用类文件代替资源文件

作为资源文件的Java类必须满足:

  • 类名命名和属性文件命名的要求一致

  • 类必须继承java.util.ListResourceBundle,重写getContents()方法

import java.util.ListResourceBundle;

public class App_zh_CN extends ListResourceBundle{

	@Override
	protected Object[][] getContents() {
		Object[][] contents = new Object[][]{
			{"hi", "你好呀!"},
			{"welcome", "热烈欢迎!"}
		};
		return contents;
	}

}

在加载资源文件时需要注意大小写,我在测试时发现加载类名资源文件时区分大小写,加载属性资源文件时不区分大小写。

ResourceBundle bundle = ResourceBundle.getBundle("App", locale);
我在测试时xxx.propertiesXxx_zh_CN.java都需要放到src目录下。

5、ResourceBundle资源加载顺序

ResourceBundle会按以下顺序搜索资源文件,如果前面的文件不存在才会使用后面的。

  • baseName_zh_CN.class

  • baseName_zh_CN.properties

  • baseName_zh.class

  • baseName_zh.properties

  • baseName.class

  • baseName.properties`

三、数值与日期的格式化

可以使用java.text.NumberFormatjava.text.DateFormat将数值和日期转换成字符串,这两个类中都包含了formatparse方法。其中,format方法用于将数值、日期格式化成字符串,parse方法用于将字符串解析成数值和日期。

1、数值格式化

可以使用NumberFormatgetXxxInstance()方法来创建NumberFormat对象,创建时也可以指定Locale

  • format
double number = 66.5;
//货币
NumberFormat format = NumberFormat.getCurrencyInstance();
System.out.println(format.format(number));
format = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(format.format(number));

//整数
format = NumberFormat.getIntegerInstance();
System.out.println(format.format(number));

//百分数
format = NumberFormat.getPercentInstance();
System.out.println(format.format(number));

程序输出:

¥66.50
$66.50
66
6,650%
  • parse
try {
	NumberFormat format = NumberFormat.getInstance();
	System.out.println(format.parse("88.99"));
	//整数
	format = NumberFormat.getIntegerInstance();
	System.out.println(format.parse("99.01"));
	//货币
	format = NumberFormat.getCurrencyInstance(Locale.US);
	System.out.println(format.parse("$33.66"));
} catch (ParseException e) {
	e.printStackTrace();
}

程序输出:

88.99
99
33.66

2、日期格式化

NumberFormat类似,可以使用DateFormatgetXxxInstance()方法来创建DateFormat对象,创建时可以指定日期时间样式和Locale。日期时间样式为DateFormat的四个静态常量:FULLLONGMEDIUMSHORT,默认为MEDIUM

  • format
Date date = new Date();
//日期
DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
System.out.println(format.format(date));
format = DateFormat.getDateInstance(DateFormat.MEDIUM);
System.out.println(format.format(date));
format = DateFormat.getDateInstance(DateFormat.LONG);
System.out.println(format.format(date));
format = DateFormat.getDateInstance(DateFormat.FULL);
System.out.println(format.format(date));

//时间
format = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.US);
System.out.println(format.format(date));
format = DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.US);
System.out.println(format.format(date));
format = DateFormat.getTimeInstance(DateFormat.LONG, Locale.US);
System.out.println(format.format(date));
format = DateFormat.getTimeInstance(DateFormat.FULL, Locale.US);
System.out.println(format.format(date));

//日期时间
format = DateFormat.getDateTimeInstance();
System.out.println(format.format(date));
format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.US);
System.out.println(format.format(date));

程序输出

18-8-4
2018-8-4
2018年8月4日
2018年8月4日 星期六

8:30 PM
8:30:25 PM
8:30:25 PM CST
8:30:25 PM CST

2018-8-4 20:30:25
Aug 4, 2018 8:30:25 PM
  • parse
try {
	DateFormat format = DateFormat.getDateTimeInstance();
	Date date = format.parse("2018-08-08 08:08:08");
	System.out.println(DateFormat.getInstance().format(date));
} catch (ParseException e) {
	e.printStackTrace();
}

程序输出:

18-8-8 上午8:08
  • SimpleDateFormat

使用java.text.SimpleDateFormat类可以更方便地格式化(解析)日期。

Pattern Output
dd.MM.yy 30.06.09
yyyy.MM.dd G ‘at’ hh:mm:ss z 2009.06.30 AD at 08:29:36 PDT
EEE, MMM d, ‘‘yy Tue, Jun 30, ‘09
h:mm a 8:29 PM
H:mm 8:29
H:mm:ss:SSS 8:28:36:249
K:mm a,z 8:29 AM,PDT
yyyy.MMMMM.dd GGG hh:mm aaa 2009.June.30 AD 08:29 AM
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(format.format(date));
try {
	System.out.println(format.parse("2018-08-08"));
} catch (ParseException e) {
	e.printStackTrace();
}

程序输出:

2018-08-04
Wed Aug 08 00:00:00 CST 2018
参考资料: