资源包包含特定于语言环境的对象。当程序需要一个特定于语言环境的资源时(如
String
),程序可以从适合当前用户语言环境的资源包中加载它。使用这种方式,可以编写很大程度上独立于用户语言环境的程序代码,它将资源包中大部分(即便不是全部)特定于语言环境的信息隔离开来。
这使编写的程序可以:
- 轻松地本地化或翻译成不同的语言
- 一次处理多个语言环境
- 以后可以轻松进行修改,以便支持更多的语言环境
资源包属于这样的系列,其成员共享一个公共的基本名称,但是名称中还有标识其语言环境的其他组件。例如,某个资源包系列的基本名称可能是 "MyResources"。该系列应该有一个默认资源包,其名称与其系列名相同( "MyResources"),如果不支持指定的语言环境,则应该将此资源包用作最后的手段。然后,此系列可根据需要提供特定于语言环境的成员,例如一个名为 "MyResources_de" 的德语资源包。
一个系列中的每个资源包都包含相同的项,但是这些项已经针对该资源包所代表的语言环境进行了翻译。例如,"MyResources" 和 "MyResources_de" 可能有用在取消操作按钮上的 String
。在 "MyResources" 中,String
可能包含 "Cancel",而 "MyResources_de" 中则可能包含 "Abbrechen"。
如果不同的国家/地区有不同的资源,则可以对它们进行限定:例如,"MyResources_de_CH" 包含瑞士 (CH) 中包含德语 (de) 的对象。如果只想修改限定中的某些资源,就可以这样做。
当程序需要特定于语言环境的对象时,它使用 getBundle
方法加载 ResourceBundle
类:
ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", currentLocale);
资源包包含键/值对。键唯一地标识了包中特定于语言环境的对象。下面是一个 ListResourceBundle
示例,它包含两个键/值对:
public class MyResources extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
// LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
{"OkKey", "OK"},
{"CancelKey", "Cancel"},
// END OF MATERIAL TO LOCALIZE
};
}
}
键始终为
String
类型。在此示例中,两个键是 "OkKey" 和 "CancelKey"。在上面的示例中,值也是
String
类型,即 "OK" 和 "Cancel",但并非必须如此。值可以是任意对象类型。
可以使用适当的获取方法从资源包中获取某个对象。因为 "OkKey" 和 "CancelKey" 都是字符串,所以应该使用 getString
获取它们:
button1 = new Button(myResources.getString("OkKey"));
button2 = new Button(myResources.getString("CancelKey"));
所有获取方法都需要将键作为参数并返回对象(如果找到的话)。如果未找到对象,则获取方法将抛出
MissingResourceException
。
除了 getString
之外,ResourceBundle
还提供了获取字符串数组的方法 getStringArray
,以及用于其他任意对象类型的 getObject
方法。使用getObject
时,必须将结果强制转换为适当的类型。例如:
int[] myIntegers = (int[]) myResources.getObject("intList");
Java 平台提供了两个 ResourceBundle
的子类,即 ListResourceBundle
和 PropertyResourceBundle
,这为创建资源提供了一种相当简单的方式。正如在前面示例中所看到的,ListResourceBundle
以键/值对的列表方式管理其资源。PropertyResourceBundle
则使用一个属性文件来管理其资源。
如果 ListResourceBundle
或 PropertyResourceBundle
无法满足需求,那么可以编写自己的 ResourceBundle
子类。子类必须重写两个方法:handleGetObject
和 getKeys()
。
ResourceBundle.Control
ResourceBundle.Control
类提供通过带
ResourceBundle.Control
实例的
getBundle
工厂方法执行包加载进程所需的信息。为了启用非标准资源包格式、更改搜索策略或定义缓存参数,可以实现自己的子类。有关细节请参考类和
getBundle
工厂方法的描述。
缓存管理
getBundle
工厂方法创建的资源包实例是默认缓存的,如果资源包实例已经缓存,那么这些工厂方法将多次返回相同的资源包实例。
getBundle
客户端可以清除缓存、使用生存时间值管理已缓存资源包实例的生命周期,或者指定不缓存资源包实例。有关细节请参考
getBundle
工厂方法、
clearCache
、
ResourceBundle.Control.getTimeToLive
和
ResourceBundle.Control.needsReload
的描述。
示例
下面是一个极其简单的
ResourceBundle
子类示例
MyResources
,它管理两个资源(对于大量的资源,应该使用
Map
)。注意,如果某个“父级”
ResourceBundle
处理具有相同值的相同键(如下面的 okKey),则无需提供值。
// default (English language, United States)
public class MyResources extends ResourceBundle {
public Object handleGetObject(String key) {
if (key.equals("okKey")) return "Ok";
if (key.equals("cancelKey")) return "Cancel";
return null;
}
public Enumeration<String> getKeys() {
return Collections.enumeration(keySet());
}
// Overrides handleKeySet() so that the getKeys() implementation
// can rely on the keySet() value.
protected Set<String> handleKeySet() {
return new HashSet<String>(Arrays.asList("okKey", "cancelKey"));
}
}
// German language
public class MyResources_de extends MyResources {
public Object handleGetObject(String key) {
// don't need okKey, since parent level handles it.
if (key.equals("cancelKey")) return "Abbrechen";
return null;
}
protected Set<String> handleKeySet() {
return new HashSet<String>(Arrays.asList("cancelKey"));
}
}
不必限制只使用
ResourceBundle
的单个系列。例如,可以有异常消息
ExceptionResources
的包集(
ExceptionResources_fr
、
ExceptionResources_de
等)和窗口小部件
WidgetResource
的包集(
WidgetResources_fr
、
WidgetResources_de
等);可以按自己喜欢的方式分解资源。
Constructors |
public |
ResourceBundle()
单独的构造方法。(由子类的构造方法调用,通常是隐式的。)
|
Methods |
final public static void |
clearCache()
从已经使用调用者的类加载器加载的缓存中移除所有资源包。
|
final public static void |
clearCache(ClassLoader loader)
从已经使用给定类加载器加载的缓存中移除所有资源包。
|
public boolean |
containsKey(String key)
确定给定 key 是否包含在此 ResourceBundle 及其父包中。
key |
资源 key |
return |
如果给定 key 包含在此 ResourceBundle 或其父包中,则返回 true ;否则返回 false 。 |
Throws |
NullPointerException:
如果 key 为 null |
since |
1.6 |
|
abstract protected Object |
handleGetObject(String key)
从此资源包中获取给定键的对象。如果此资源包未包含给定键的对象,则返回 null。
|
protected Set |
handleKeySet()
返回只 包含在此 ResourceBundle 中的键的 Set 。
默认实现返回 getKeys 方法返回的键的 Set ,那些 handleGetObject 方法返回 null 的键除外。创建 Set 后,该值就被保存在此ResourceBundle 中,以避免在下次调用中产生相同的 Set 。可在子类实现中重写此方法,以便更快地进行处理。
return |
只包含于此 ResourceBundle 中的键的 Set |
since |
1.6 |
|
public Set |
keySet()
返回此 ResourceBundle 及其父包中包含的所有键的 Set 。
return |
此 Set 及其父包中包含的所有键的 Set 。 |
since |
1.6 |
|
Properties |
final public staticResourceBundle |
getBundle(String baseName)
使用指定的基本名称、默认的语言环境和调用者的类加载器获取资源包。调用此方法等同于调用
getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader()) ,
不同之处在于要使用 ResourceBundle 的安全特权来运行 getClassLoader() 。有关搜索和实例化策略的信息,请参阅 getBundle 。
|
final public staticResourceBundle |
getBundle(String baseName, ResourceBundle.Control control)
使用指定基本名称、默认语言环境和指定控件返回一个资源包。调用此方法等同于调用
getBundle(baseName, Locale.getDefault(),
this.getClass().getClassLoader(), control),
不同之处在于要使用 ResourceBundle 的安全特权来运行 getClassLoader() 。有关带 ResourceBundle.Control 的资源包加载进程的完整描述,请参阅 getBundle 。
|
final public staticResourceBundle |
getBundle(String baseName, Locale locale)
使用指定的基本名称、语言环境和调用者的类加载器获取资源包。调用此方法等同于调用
getBundle(baseName, locale, this.getClass().getClassLoader()) ,
不同之处在于要使用 ResourceBundle 的安全特权来运行 getClassLoader() 。有关搜索和实例化策略的信息,请参阅 getBundle 。
|
final public staticResourceBundle |
getBundle(String baseName, Locale targetLocale, ResourceBundle.Control control)
使用指定基本名称、目标语言环境和控件、调用者的类加载器返回一个资源包。调用此方法等同于调用
getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
control),
不同之处在于要使用 ResourceBundle 的安全特权来运行 getClassLoader() 。有关带 ResourceBundle.Control 的资源包加载进程的完整描述,请参阅 getBundle 。
baseName |
资源包的基本名称,一个完全限定类名 |
targetLocale |
资源包所需的语言环境 |
control |
为资源包加载进程提供信息的控件 |
return |
用于给定基本名称和 locales 中某个 Locale 的资源包 |
Throws |
NullPointerException:
如果 baseName 、locales 或 control 为 null |
Throws |
MissingResourceException:
如果在任何 locales 中都无法找到用于指定基本名称的资源包。 |
Throws |
IllegalArgumentException:
如果给定 control 没有正确执行(例如,control.getCandidateLocales 返回 null。)注意,control 的验证是根据需要执行的。 |
since |
1.6 |
|
public static ResourceBundle |
getBundle(String baseName, Locale locale, ClassLoader loader)
使用指定的基本名称、语言环境和类加载器获取资源包。
从概念上讲,getBundle 使用下列策略来搜索并实例化资源包:
getBundle 使用基本名称、指定的语言环境和默认语言环境(从 Locale.getDefault 获得)来生成候选包名称 序列。如果指定语言环境的语言、国家/地区和变量都是空字符串,则基本名称就是唯一的候选包名称。否则,从指定语言环境(language1、country1 和 variant1)和默认语言环境(language2、country2 和 variant2)的属性值生成下列序列:
- baseName + "_" + language1 + "_" + country1 + "_" + variant1
- baseName + "_" + language1 + "_" + country1
- baseName + "_" + language1
- baseName + "_" + language2 + "_" + country2 + "_" + variant2
- baseName + "_" + language2 + "_" + country2
- baseName + "_" + language2
- baseName
省略最后部分为空字符串的候选包名称。例如,如果 country1 是一个空字符串,则省略第二个候选包名称。
然后 getBundle 在候选包名称上进行迭代,找到第一个可实例化 为实际资源包的候选包名称。对于每个候选包名称,它都试图创建资源包:
- 首先,它试图使用候选包名称加载一个类。如果可以找到这样的类并使用指定的类加载器加载,而且此类的分配与 ResourceBundle 兼容,可通过 ResourceBundle 访问,并可以被实例化,那么
getBundle 将创建此类的一个新实例,并使用它作为结果资源包。
- 否则,
getBundle 尝试搜索属性资源文件。它从候选包名称生成一个路径名,用 "/" 替换所有的 "." 字符,并添加字符串 ".properties"。然后尝试用 ClassLoader.getResource 找到一个具有此名称的“资源”(注意,getResource 获得的“资源”与资源包中的内容没有任何关系,它只是一个数据的容器,如文件)。如果它找到一个“资源”,则会尝试用其内容创建一个新的PropertyResourceBundle 。如果成功,那么此实例就成为结果资源包。
如果未找到结果资源包,则抛出 MissingResourceException 。
找到了结果资源包后,它的父链 将被实例化。getBundle 在可以获得的候选包名称中进行迭代,获得名称的方法是从结果资源包的包名称中连续移除变量、国家/地区和语言(每次都用前缀 "_")。如上所述,省略最后部分为空字符串的候选包名称。对于每个候选包名称,都尝试实例化一个资源包,如上所述。只要能够成功,就用新的资源包调用先前已实例化资源包的 setParent 方法,除非先前已实例化的资源包已经有非 null 的父包。
getBundle 可以缓存已实例化的资源包,并且可以多次返回相同的资源包实例。
baseName 参数应该是一个完全限定类名。但是,为了与早期的版本兼容,Sun 的 Java SE Runtime Environment 并不对此进行检查,所以可通过指定路径名(使用 "/")而不是完全限定类名(使用 ".")来访问 PropertyResourceBundle 。
示例: 提供了下面的类和属性文件:
MyResources.class
MyResources.properties
MyResources_fr.properties
MyResources_fr_CH.class
MyResources_fr_CH.properties
MyResources_en.properties
MyResources_es_ES.class
所有文件的内容都是有效的(也就是说 ".class" 文件是 ResourceBundle 的公共非抽象子类,".properties" 文件的语法正确)。默认的语言环境是 Locale("en", "GB") 。
使用给出的语言环境参数值调用 getBundle 将实例化取自以下源的资源包:
- Locale("fr", "CH"):结果 MyResources_fr_CH.class、父 MyResources_fr.properties、父 MyResources.class
- Locale("fr", "FR"):结果 MyResources_fr.properties、父 MyResources.class
- Locale("de", "DE"):结果 MyResources_en.properties、父 MyResources.class
- Locale("en", "US"):结果 MyResources_en.properties、父 MyResources.class
- Locale("es", "ES"):结果 MyResources_es_ES.class、父 MyResources.class
不使用 MyResources_fr_CH.properties 文件,因为它被 MyResources_fr_CH.class 隐藏了。类似地,MyResources.properties 也被 MyResources.class 隐藏了。
|
public static ResourceBundle |
getBundle(String baseName, Locale targetLocale, ClassLoader loader, ResourceBundle.Control control)
使用指定基本名称、目标语言环境、类加载器和控件返回资源包。与 不带 control 参数的 getBundle 工厂方法不同,给定control 指定查找和实例化资源包的方式。从概念上说,具有给定 control 的包加载进程是按以下步骤执行的。
- 此工厂方法在缓存中为指定
baseName 、targetLocale 和 loader 查找资源包。如果在缓存中找到所请求的资源包实例,并且该实例及其所有父实例的生存时间都已经到期,则向调用者返回该实例。否则,此工厂方法继续进行以下加载进程。
- 调用
control.getFormats 方法获取生成包名称或资源名称的资源包格式。字符串 "java.class" 和 "java.properties" 分别指定基于类和基于属性的资源包。其他以 "java." 开头的字符串被保留,供以后扩展使用,不必将它们用于应用程序定义的格式。其他字符串指定应用程序定义的格式。
- 可以调用带有目标语言环境的
control.getCandidateLocales 方法获取用于已搜索到的资源包的候选 Locale 列表。
- 可以调用
control.newBundle 方法实例化针对基本包名称、候选语言环境和某种格式的 ResourceBundle 。(参考下方关于缓存查找的注释。)此步骤在所有候选语言环境和格式上进行迭代,直到 newBundle 方法返回一个 ResourceBundle 实例,或者该迭代已经用完了所有的组合。例如,如果候选语言环境是 Locale("de", "DE") 、Locale("de") 和 Locale("") ,而格式是"java.class" 和 "java.properties" ,那么以下是用来调用 control.newBundle 的语言环境和格式组合的序列。
语言环境 |
格式 |
Locale("de", "DE") |
java.class |
Locale("de", "DE") |
java.properties |
Locale("de") |
java.class |
Locale("de") |
java.properties |
Locale("") |
java.class |
Locale("") |
java.properties |
- 如果前面的步骤未找到资源包,则前进到步骤 6。如果已经找到用作基本包的包(
Locale("") 的包),以及只包含Locale("") 的候选语言环境列表,则向调用者返回该包。如果已经找到作为基本包的包,但候选语言环境列表包含 Locale("") 之外的语言环境,则暂时搁置该包并前进到步骤 6。如果找到一个不是基本包的包,则前进到步骤 7。
- 可调用
control.getFallbackLocale 方法获取一个回退语言环境(当前目标语言环境的替代),以尝试进一步寻找资源包。如果该方法返回一个非 null 语言环境,那么该语言环境将变成下一个目标语言环境,并且加载进程将从步骤 3 开始。否则,如果找到一个基本包并在前面的步骤 5 中暂时被搁置,那么现在要将该语言环境返回给调用者。否则抛出 MissingResourceException。
- 此时,我们已经找到一个不是基本包的包。如果此包在其实例化期间设置其父链,则将此包返回给调用者。否则,根据从中找到此包的候选语言环境列表,将此包的父链实例化。最后将该包返回给调用者。
在进行上述资源包加载进程期间,此工厂方法将在调用 control.newBundle 方法之前查找缓存。如果在该缓存中找到的资源包的生存时间已到期,则该工厂方法将调用 control.needsReload 方法确定是否需要重载资源包。如果需要重载,则该工厂方法将调用 control.newBundle 重载资源包。如果 control.newBundle 返回 null ,则该工厂方法将在缓存中放一个伪资源包,以此作为不存在资源包的标记,从而避免后续请求所带来的查找开销。这类伪资源包同样受到 control 所指定的到期时间控制。
所有已加载的资源包都是在默认情况下被缓存的。有关细节请参阅 control.getTimeToLive 。
以下是带有默认 ResourceBundle.Control 实现的包加载进程的示例。
条件:
- 基本包的名称:
foo.bar.Messages
- 所请求的
Locale :Locale#ITALY
- 默认
Locale :Locale#FRENCH
- 可用的资源包:
foo/bar/Messages_fr.properties 和 foo/bar/Messages.properties
首先,getBundle 试图按以下顺序加载资源包。
- 类
foo.bar.Messages_it_IT
- 文件
foo/bar/Messages_it_IT.properties
- 类
foo.bar.Messages_it
- 文件
foo/bar/Messages_it.properties
- 类
foo.bar.Messages
- 文件
foo/bar/Messages.properties
此时,getBundle 找到一个 foo/bar/Messages.properties ,该包被搁置,因为它不是一个基本包。getBundle 调用返回 Locale.FRENCH 的 control.getFallbackLocale("foo.bar.Messages", Locale.ITALY) 。接着,getBundle 试图按以下顺序加载一个包。
- 类
foo.bar.Messages_fr
- 文件
foo/bar/Messages_fr.properties
- 类
foo.bar.Messages
- 文件
foo/bar/Messages.properties
getBundle 查找 foo/bar/Messages_fr.properties 并创建一个 ResourceBundle 实例。然后,getBundle 根据候选语言环境列表设置其父链。在该列表中只有 foo/bar/Messages.properties ,并且 getBundle 创建一个 ResourceBundle 实例,该实例成为用于foo/bar/Messages_fr.properties 的实例的父实例。
baseName |
资源包的基本名称,一个完全限定类名 |
targetLocale |
资源包所需的语言环境 |
loader |
加载资源包的类加载器 |
control |
为资源包加载进程提供信息的控件 |
return |
具有给定基本名称和语言环境的资源包 |
Throws |
NullPointerException:
如果 baseName 、targetLocale 、loader 或 control 为 null |
Throws |
MissingResourceException:
如果没有找到用于指定基本名称的资源包 |
Throws |
IllegalArgumentException:
如果给定 control 没有正确执行(例如,control.getCandidateLocales 返回 null。)注意,control 的验证是根据需要执行的。 |
since |
1.6 |
|
abstract public Enumeration |
getKeys()
返回键的枚举。
return |
包含在此 ResourceBundle 及其父包中的键的 Enumeration 。 |
|
public Locale |
getLocale()
返回此资源包的语言环境。调用 getBundle() 后可使用此方法来确定返回的资源包是真正对应于所请求的语言环境,还是只是一个回退。
|
final public Object |
getObject(String key)
从此资源包或它的某个父包中获取给定键的对象。此方法首先尝试使用 handleGetObject 从此资源包中获取对象。如果不成功,并且父资源包不为 null,则调用父包的 getObject 方法。如果仍不成功,则抛出 MissingResourceException。
|
protected void |
setParent(ResourceBundle parent)
设置此包的父包。当此包不包含特定的资源时,通过 getObject 来搜索父包。
|
final public String |
getString(String key)
从此资源包或它的某个父包中获取给定键的字符串。调用此方法等同于调用
(String) getObject (key) 。
|
final public String[] |
getStringArray(String key)
从此资源包或它的某个父包中获取给定键的字符串数组。调用此方法等同于调用
(String[]) getObject (key) 。
|