All Packages Class Hierarchy This Package Previous Next Index
java.lang.Object | +----java.util.ResourceBundle
Using ResourceBundles, you can have multiple resources for different languages, so that a single applet or application can handle multiple languages or locales.
You can also add resources later, without modifying your source code.
Accessing ResourceBundles
Instead of using hard-coded strings, you write your code to load them out of a ResourceBundle.
Original Source Code
button1 = new Button("Ok");
button2 = new Button("Cancel");
Modified Code
ResourceBundle myResources =
ResourceBundle.getResourceBundle("MyResources", myLocale, myClassLoader);
...
button1 = new Button(myResources.getString("OkKey"));
button2 = new Button(myResources.getString("CancelKey"));
Typically, you will be using the default locale; in that case you can omit the myLocale parameter. Remember that the keys are case-sensitive!
Arbitrary objects can be accessed from a ResourceBundle; there are also a number of convenience routines to avoid doing explicit casting. If you don't have an object that matches one of those convenience routines, you will have to cast it yourself. For example,
int[] myIntegers = (int[]) myResources.getObject("intList");
To access ResourceBundles, you supply a baseclass name. The resource lookup searches for classes with various suffixes on the basis of the desired locale (1), and the default locale (2), in the following order from lower-level (more specific) to higher-level (less specific):
baseclass + "_" + language1 + "_" + country1 + "_" + variant1
baseclass + "_" + language1 + "_" + country1
baseclass + "_" + language1
baseclass + "_" + language2 + "_" + country2 + "_" + variant2
baseclass + "_" + language2 + "_" + country2
baseclass + "_" + language2
baseclass
The result of the lookup is a class, but that class may be backed by a property file on disk.
NOTE the baseclass must be fully qualified, e.g. "myPackage.MyResources", not just "MyResources". It must also be accessable by your code; it cannot be a class that is private to the package where ResourceBundle.getResourceBundle is called.
Note: ResourceBundles are used internally in accessing NumberFormats, Collations, etc. The lookup strategy is the same.
Note: If a lookup fails, you will get an MissingResourceException.
The call to ResourceBundle.getResourceBundle requires a ClassLoader as an argument. The ClassLoader passed must be suitable for loading the desired ResourceBundle class. Typically this is the same ClassLoader that was used to load the class making the call to getResourceBundle. If your ResourceBundles exist as files on your CLASSPATH, then null may be passed in for the ClassLoader argument.
Building ResourceBundles You can build multiple resources for different locales by supplying different classes, named according to the lookup strategy. For example, AppResourceBundle_FR can be used for French resources. If there are different resources for different countries, you can make specializations: AppResourceBundle_FR_BE for Belgium. If you want to only modify some of the resources in the specialization, you can do so.
NOTE You should always supply a baseclass with no suffixes. This will be the class of "last resort", if a locale is requested that does not exist. For example, below we have a class MyResources as this last resort. It happens to contain US strings, so we don't have to have an explicit MyResource_EN or MyResource_EN_US.
There are two convenience subclasses of ResourceBundle that are provided, which provide a fairly simple way to produce resources.
If you want to write your own ResourceBundle, you can.
The only method that you must override is handleGetObject. The following
is a very simple example, if you didn't have many objects (for a larger
number you would probably use a Hashtable). Notice that
you must return null if the key is not found. Notice also that you don't
need to supply a value if a "higher-level" ResourceBundle handles the same
key with the same value (look at UK below).
Example:
class MyResources extends ResourceBundle {
public Object handleGetObject(String key) {
if (key.equals("okKey")) return "Ok";
if (key.equals("cancelKey")) return "Cancel";
return null;
}
}
class MyResources_DE extends ResourceBundle {
public Object handleGetObject(String key) {
if (key.equals("okKey")) return "Gut";
if (key.equals("cancelKey")) return "Vernichten";
return null;
}
}
class MyResources_UK extends ResourceBundle {
public Object handleGetObject(String key) {
// don't need okKey, since higher level handles it.
if (key.equals("cancelKey")) return "Dispose";
return null;
}
}
You do not have to restrict yourself to using a single set of
ResourceBundles.
For example, you could have a set of bundles for Exception messages,
ExceptionResources (ExceptionResources_FR, ExceptionResources_DE,...),
and one for widgets,
WidgetResource (WidgetResources_FR, WidgetResources_DE,...); breaking up
the resources however you like.
public ResourceBundle()
public final Menu getMenu(String key) throws MissingResourceException
public final MenuBar getMenuBar(String key) throws MissingResourceException
public final String getString(String key) throws MissingResourceException
public final String[] getStringArray(String key) throws MissingResourceException
public final Object getObject(String key) throws MissingResourceException
public final static ResourceBundle getResourceBundle(String baseName,
ClassLoader loader) throws MissingResourceException
public static ResourceBundle getResourceBundle(String baseName,
Locale locale,
ClassLoader loader) throws MissingResourceException
protected abstract Object handleGetObject(String key) throws MissingResourceException
All Packages Class Hierarchy This Package Previous Next Index