国际化操作是在开发中较为常见的一种要求,实际上国际化的操作就是指一个程序可以同时适应多门语言,即如果现在程序的使用者是中国人,则会显示中文,如果是英文人,则会显示英语,也就是通过国际化操作让一个程序适应各个国家的语言要求。
但是实现国际化程序只靠 Local类时不够的,还需要属性文件和 ResourceBundle 类的支持,所谓的属性文件是指后缀为 “.properties” 的文件,文件中的内容保存结构为“key=value”形式。
因为国际化的程序只是显示的语言不同,那么就可以根据不同的国家定义不同的属性文件,属性文件中保存真正要使用的文字信息,要访问这些属性文件,可以使用 ResourceBundle 类来完成。
一、国际化程序的实现思路
例如,现在有一个程序要求可以同时适应法语、英语、中文的显示,那么此时就必须使用国际化:
从图中可以得知,需要根据各个不同的国家配置不同的资源文件(资源文件有时也称为属性文件,后缀为.properties
)所有的资源文件以“key->value”的形式出现,在程序执行中只是根据 key 找到 value 并将 value 的内容进行显示,也就是说,只要 key 不变,value 的内容可以任意更换。
如果要实现 Java 程序的国际化操作必须通过以下三个类完成:
java.util.Local:用于表示一个国家语言类
java.util.ResourceBundle:用于访问资源文件
java.util.MessageFormat:格式化资源文件的占位字符串
这 3 个类的具体操作是通过 Local 类所指定的区域码,然后 ResourceBundle 根据 Local 类所指定的区域码找到相应的资源文件,如果资源文件中存在动态文本,则使用 MessageFormat 进行格式化。
资源文件有时也称为属性文件,可以直接使用 Java 类集中提供的 Properties 类进行操作
二、Local 类
Local 类时实现国际化的一个重要类
实际上对于各个国家都有对应的 ISO 编码,例如,中国的编码为 zh-CN、英语-美国的编码为 en-US。
三、ResourceBundle 类
这个类的主要作用是读取属性文件,读取属性文件时可以直接指定属性文件的名称(指定名称时不需要文件的后缀),也可以根据 Local 所指定的区域码来选取指定的资源文件。
如果现在要使用 ResourceBundle 对象,则肯定直接通过 ResourceBundle 类中的静态方法 getBundle() 取得:
import java.util.ResourceBundle;
public class Test{
public static void main(String[] args) {
ResourceBundle rb = ResourceBundle.getBundle("Message");//找到资源文件
System.out.println("内容:" + rb.getString("info"));//从资源文件中取得内容
}
}
- 4
- 5
- 6
- 7
- 8
可以看出程序通过资源文件中的 key 取得了对应的 value。
四、Java 国际化程序实现
完成一个简单的国际化操作,可以根据 Local 所选择的国家不同,输出不同国家的“你好”
中文:你好!
英语:Hello!
法语:Bonjour
首先根据不同的国家代码建立不同的属性文件,建立的属性文件与生产的*.class
保存在同一个文件夹中。因为现在程序中使用的有三种语言,所以要定义 3 种属性文件,在属性文件定义时必须按照“名称_国家代码”的形式命名,即所有相关的属性文件的名称全部一样,只有国家代码不一样
(1)中文的属性文件:Message_zh_CN.properties
info = \u4f60\u597d\uff01
(2)英语的属性文件:Message_en_US.properties
info = Hello!
(3)法语的属性文件:Message_fr_FR.properties
info = Bonjour!
- 4
- 5
- 6
属性文件中不能直接写入中文,不然会出现乱码,因此需要将相应的中文变为 Unicode 编码才可以,要成功地将一个中文编码变为 Unicode 编码,可以直接在运行处执行 native2ascii.exe
命令,输入相应的中文之后会自动将其进行编码
import java.util.Locale;
import java.util.ResourceBundle;
public class Test{
public static void main(String[] args) {
Locale zhLoc = new Locale("zh","CN");//表示中国地区
Locale enLoc = new Locale("en","US");//表示美国地区
Locale frLoc = new Locale("fr","FR");//表示法国地区
//找到中文的属性文件
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc);
//找到英文的属性文件
ResourceBundle enrb = ResourceBundle.getBundle("Message",enLoc);
//找到法语的属性文件
ResourceBundle frrb = ResourceBundle.getBundle("Message",frLoc);
System.out.println("中文:" + zhrb.getString("info"));//从资源文件中取得内容
System.out.println("英语:" + enrb.getString("info"));//从资源文件中取得内容
System.out.println("法语:" + frrb.getString("info"));//从资源文件中取得内容
}
}
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
可以看出根据 Local 所指定的国家不同,读取的资源文件也不同,这样就实现了国际化程序
五、处理动态文本
如果输出的消息中包含了一些动态文本,则必须使用占位符清楚地表示出动态文本的位置,占位符使用“{编号}”的格式出现。使用占位符后,程序可以直接通过 MessageFormat 对信息进行格式化,为占位符动态设置文本的内容。
MessageFormat 是 Format 类的子类,Format 类主要实现格式化操作,除了 MessageFormat 子类外,Format 还有 NumberFormat、DateFormat 两个子类
在进行国际化操作时,不光只有文字需要处理,实际上数字的显示,日期的显示都要符合各个区域的要求
此时如果要输出“你好,XXX!”,其中XXX 的内容是由程序动态设置的,所以,此时修改之前的 3 个属性文件,让其动态地接收程序的 2 个文本。
(1)中文的属性文件:Message_zh_CN.properties
info = \u4f60\u597d\uff0c{0}\uff01 //意思是中文的“你好,{0}!”
(2)英语的属性文件:Message_en_US.properties
info = Hello,{0}!
- 4
此时两个属性文件都加入了{0},表示一个占位符,如果要更多的占位符,则直接在后面继续加上“{1}”,“{2}”即可。
然后继续使用之前的 Local 类和 ResourceBundle 类读取资源文件的内容,但是读取之后的文件因为要处理占位符的内容,所以要使用 MessageFormat 类进行处理:
public static String format(String pattern,Object...arguments)
- 1
语句中第一个参数表示要匹配的字符串,第二个参数“Object…arguments”表示输入参数可以任意多个,没有个数的限制
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public class Test{
public static void main(String[] args) {
Locale zhLoc = new Locale("zh","CN");//表示中国地区
Locale enLoc = new Locale("en","US");//表示美国地区
//找到中文的属性文件
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc);
//找到英文的属性文件
ResourceBundle enrb = ResourceBundle.getBundle("Message",enLoc);
//依次读取各个属性的内容,通过键值名称为"info"
String str1 = zhrb.getString("info");
String str2 = enrb.getString("info");
System.out.println("中文:" + MessageFormat.format(str1,"中文"));
System.out.println("英文:" + MessageFormat.format(str2,"English"));
}
}
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
程序代码通过 MessageFormat.format() 方法设置动态文本的内容,如果有更多的占位符可以按照:
六、使用类代替资源文件
可以使用属性文件保存所有的资源信息,在 Java 中也可以使用类来保存所有的资源信息,但是并不多见
同理,如果使用类保存信息,也必须按照 key-value 的形式出现,而且类的命名必须与属性文件一致,而且此类必须继承 ListResourceBundle 类,继承之后要覆写此类中的 getContent() 方法:
建立类文件Message_zh_CN.java
import java.util.ListResourceBundle;
public class Message_zh_CN extends ListResourceBundle{
private final Object data [][] = {
{"info","你好,{0}"}
};
public Object [][] getContents(){//覆写方法
return data;
}
}
- 4
- 5
- 6
- 7
- 8
- 9
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public class Test{
public static void main(String[] args) {
Locale zhLoc = new Locale("zh","CN");//表示中国地区
//找到中文的属性文件
ResourceBundle zhrb = ResourceBundle.getBundle("Message",zhLoc);
//依次读取各个属性的内容,通过键值名称为"info"
String str = zhrb.getString("info");
System.out.println("中文:" + MessageFormat.format(str,"中文"));
}
}
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这里使用类代替了资源文件,但是资源类中的属性一定是一个二维数组
注意: