程序根据不同地区的用户,呈现不同的语言,日期、货币等称为本地化。在不修改应用程序的情况下,根据不同用户直接采用不同语言、日期格式等,这样的设计称为国际化。
一、Java支持的国家和语言
import java.util.Locale;
public class Test
{
public static void main(String[] args)
{
Locale[] localeList = Locale.getAvailableLocales();
for(int i = 0; i < localeList.length; ++i)
{
String str = localeList[i].getDisplayCountry() + "=" + localeList[i].getCountry();
//中国=CN
//美国=US
//...
}
for(int i = 0; i < localeList.length; ++i)
{
String str = localeList[i].getDisplayLanguage() + "=" + localeList[i].getLanguage();
//中文=zh
//英文=en
//...
}
}
}
二、程序国际化
如果想要根据系统的语言环境来自动获得对应的文本,比如对于英文显示"hello",对于中文显示"你好",我们可以建立两个资源文件,资源文件中内容是key-value对,value值是对应语言的内容,比如中文资源文件的内容为 hi=你好,英文资源文件的内容为 hi=hello。资源文件的名称格式应该是"baseName_language_country.properties",其中baseName部分可以为用户指定,但两个文件的baseName必须相同,language为语言代码,country为国家代码,比如中文资源文件名为"trans_zh_CN.properties",英文资源文件名为"trans_en_US.properties"。对于中文资源文件,从JDK9开始,使用的字符编码应该是UTF8。资源文件应该放置CLASSPATH的路径下。如果找不到对应的资源文件或者文件中的键值对的话会抛出异常。下面程序会在中文系统下显示"你好",在英文环境下显示"hello":
import java.util.Locale;
import java.util.ResourceBundle;
public class Test
{
public static void main(String[] args)
{
Locale myLocale = Locale.getDefault(Locale.Category.FORMAT); //获得系统默认的国家/语言环境
ResourceBundle bundle = ResourceBundle.getBundle("trans", myLocale);//根据国家/语言环境自动加载对应的资源文件
String str = bundle.getString("hi"); //获得hi键对应的值
System.out.println(str);
}
}
资源文件中还可以包含动态内容,如下所示的两个资源文件中包含两个占位符,可以使用MessageFormat类来替换字符串中占位符的内容:
trans_en_US.properties:hi=hello, {0}, Today is {1}.
trans_zh_CN.properties:hi=你好, {0}, 今天是{1}.
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Date;
public class Test
{
public static void main(String[] args)
{
Locale myLocale = Locale.getDefault(Locale.Category.FORMAT); //获得系统默认的国家/语言环境
ResourceBundle bundle = ResourceBundle.getBundle("trans", myLocale);//根据国家/语言环境自动加载对应的资源文件
String str = MessageFormat.format(bundle.getString("hi"), "leon", new Date()); //获得hi键对应的值
System.out.println(str);
}
}
还可以使用类文件来代替资源文件,该类必须从ListResourceBundle派生,类名格式为baseName_language_country,而且要实现方法getContents():
import java.util.ListResourceBundle;
public class trans_zh_CN extends ListResourceBundle
{
@Override
public Object[][] getContents()
{
return myData;
}
private final Object myData[][] = {{"hi", "你好, {0}, 今天是{1}"}};
}
也可以通过ResourceBundle来实现不修改程序代码来改变程序中的文本,将可能会改变的文本放置messages.properties文件中,通过ResourceBundle.getBundle("messages")来获得ResourceBundle对象,通过该对象的getString()来获取指定的文本,当需要修改文本的时候只修改.properties文件即可。
三、使用NumberFormat、DecimalFormat格式化数值
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws Exception
{
String s = NumberFormat.getInstance().format(123456789); //"123,456,789"
s = NumberFormat.getInstance().format(new BigDecimal("1234567.12345")); // "1,234,567.123"
s = NumberFormat.getInstance().format(123456789.12345678); //"123,456,789.123"
s = NumberFormat.getCurrencyInstance().format(123456789); //"¥123,456,789.00"
Locale loc = Locale.US;
s = NumberFormat.getCurrencyInstance(loc).format(123456789); //"$123,456,789.00"
s = NumberFormat.getPercentInstance().format(12.3); //"1,230%"
Number n = NumberFormat.getInstance().parse("123,456,789"); //123456789
//自定义格式,通过NumberFormat的子类DecimalFormat,NumberFormat的getInstance()方法基本都是返回的DecimalFormat对象,除了某些特定国家区域设定下
NumberFormat formatter = new DecimalFormat("#,####.###"); //每四位一个逗号,小数最多三位
s = formatter.format(123456789.123456); //"1,2345,6789.123"
formatter = new DecimalFormat("#,####.000"); //每四位一个逗号,小数固定三个位数,不足补0
s = formatter.format(123456789.12); //"1,2345,6789.120"
}
}
四、使用DateTimeFormatter格式化日期
import java.time.*;
import java.time.format.*;
import java.util.Locale;
public class Test
{
public static void main(String[] args)
{
//本地(中国)区域
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("Gyyyy QQQQ MMMM E");
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("Gyy QQQ MMM E");
LocalDateTime date = LocalDateTime.now();
String str = formatter1.format(date); // "公元2020 第四季度 十月 周六"
str = formatter2.format(date); // "公元20 4季度 10月 周六"
//美国区域
DateTimeFormatter dfmt1 = formatter1.withLocale(Locale.US);
str = dfmt1.format(date); // "AD2020 4th quarter October Sat"
DateTimeFormatter dfmt2 = formatter2.withLocale(Locale.US);
str = dfmt2.format(date); // "AD20 Q4 Oct Sat"
}
}