| CONTENTS | PREV | NEXT | INDEX | Designing Enterprise Applications with the J2EETM Platform, Second Edition |
J2SE internationalization APIs include utility classes and interfaces for externalizing application resources, formatting messages, formatting currency and decimals, representing dates and times, and collating. The next few sections explain how to use J2SE internationalization APIs in J2EE applications.
J2SE applications store locale-specific resources such as GUI item labels, menu items, and help text in classes called resource bundles. Resource bundles support internationalization by separating localized data from the code that uses it. Each resource bundle class contains localized resources for a particular locale. A resource bundle is a map of key/value pairs, where the keys are names that are shared across locales, and the values are resources localized to the resource bundle's locale. Application code references locale-specific resources by key rather than storing them directly.
Figure 10.1 Resource Bundles Map Key Strings to Localized Resources
For example, Figure 10.1 shows four separate resource bundles for English, French, German, and Japanese, which map the key YesLabel to localized strings for "Yes," "Oui," "Ja," and "Hai," respectively. Application source code would look up the localized string by name (YesLabel) from the resource bundle corresponding to the desired locale. The resource bundle class names are formed from the base name of the bundle for the default locale (MyBundle in this example), plus an optional underscore and locale, using the naming convention described in Section 10.1.1.1 on page 313.
Subclasses of abstract class java.util.ListResourceBundle keep named resources in an internal list, while subclasses of java.util.PropertyResourceBundle store them in external, textual property files. Application clients or rich clients can load resource bundle classes dynamically corresponding to the client's locale.
J2EE applications can also use resource bundles. Code Example 10.1 shows a very simple resource bundle for two messages in English.
public class WebMessages extends java.util.ListResourceBundle{
public Object [][] getContents(){
return contents;
}
static final Object[][] contents = {
//Messages
{"com.sun.blueprints.messages.welcome",
"Welcome to the Java(TM) Pet Store"},
{"com.sun.messages.come_back_soon",
"Come Back Soon"}
}
}
| Code Example 10.1 An English Resource Bundle |
Class WebMessages associates the localized English string Welcome to Java(TM) Pet Store with the name com.sun.blueprints.messages.welcome and associates the string Come Back Soon with the name com.sun.messages.come_back_soon. Application code retrieves localized strings by name from an instance of this class.
Adding support for new languages is as simple as creating another subclass of ListResourceBundle. Code Example 10.2 shows the source code for a resource bundle that provides localized Japanese text for one of the messages in Code Example 10.1.
public class WebMessages_ja extends java.util.ListResourceBundle{
public Object [][] getContents(){
return contents;
}
static final Object[][] contents = {
//Messages
{"com.sun.blueprints.messages.welcome",
"\uE382\u88E3\u8186\uE381\u9383\u819D"}
// (Unicode for Japanese phrase)
}
}
| Code Example 10.2 A Japanese Resource Bundle |
Class WebMessages_ja defines a Japanese localized string for one of the keys used by class WebMessages. Note that the resource bundle's class file name ends with _ja, indicating that it is Japanese. Static method ResourceBundle.getResource determines the class name of the resource bundle to load for a locale by appending a suffix to the name of the bundle. The suffix follows the standard locale naming convention described in Section 10.1.1.1 on page 313.
Note that a locale-specific resource bundle class need not specify localized messages for all keys. Class ResourceBundle always uses the most specific localized string it can find, falling back to the class name with no suffix if a string cannot be found. Because Code Example 10.2 does not define a localized string for key com.sunw.messages.come_back_soon, a request for the string associated with that key will return Come Back Soon, the string defined in the default bundle defined in Code Example 10.3.
Code Example 10.3 shows code, possibly from a servlet or JSP page, that retrieves a resource bundle for a locale, and uses it to print a localized string.
// Get Japanese resource bundle
ResourceBundle messages = ResourceBundle.getResource("WebMessages",
Locale.JAPAN);
// Get localized string
String greeting =
messages.getString("com.sun.blueprints.messages.welcome");
// Output welcome message
out.println(greeting);
| Code Example 10.3 Getting Messages from a Resource Bundle |
Remember that an application should deliver content corresponding to the locale of the client, not the locale of the component container. As previously mentioned, UTF-8 encoding is recommended because it can display multiple languages on a single Web page and has wide browser support.
When a locale is not specified, resource bundles default to the container's default locale. The container's default locale should be set to a value appropriate for the majority of an application's users.
Of course, localized content cannot be limited to static strings retrieved from resource bundles. The J2SE standard class java.text.MessageFormat provides a generic way to create concatenated message strings. A MessageFormat object contains a pattern string with embedded format specifiers. Method MessageFormat.format formats an array of objects using the format specifiers embedded in the pattern and returns the result as a StringBuffer.
String pattern = "Order number {0}, line item {1}: this item is out
of stock.";
MessageFormat mf = new MessageFormat(pattern);
Object[] objs = new Object[] {
new Integer(orderNumber),
new Integer(lineNumber)
};
StringBuffer result = new StringBuffer();
String message = mf.format(objs, result, new FieldPosition());
//... use formatted message...
Code Example 10.4 Using MessageFormat to Format a Message
|
Code Example 10.4 illustrates how to use MessageFormat to format a message. The MessageFormat holds the pattern and uses it to format the result string, substituting formatted objects (Integer objects in this case) in place of format specifiers {0} and {1}. Code Example 10.4 is internationalized because it retrieves a format pattern from a resource bundle for the desired locale.
MessageFormat is recommended for formatting system-level messages such as error or logging strings. While MessageFormat is powerful, it is too programmatic for creating most internationalized dynamic Web content; instead, consider using JSP pages for that purpose. MessageFormat can be used very effectively to internationalize JSP custom tags.
Virtually all enterprise applications store, compare, and perform arithmetic on date values. Both calendars and textual representations of date and time values vary by locale. Calendars vary among regions, cultures, and organizations. For example, many cultures use lunar calendars, and some companies have their own corporate calendar. Even two locales that use the same calendar may represent times and dates differently.
The standard class java.util.Date represents date values. Its subclass, java.sql.Date, represents date values returned from JDBC data sources.
The standard J2SE platform abstract class java.util.Calendar represents abstract operations on date and time values, including assignment, comparison, and week day. Concrete subclasses of Calendar (java.util.GregorianCalendar, for example) implement abstract calendar operations in terms of a specific calendar system.
For textual representation of dates and times, the J2SE platform offers the standard abstract class java.text.DateFormat (and related classes). DateFormat provides a locale-sensitive API for parsing, formatting, and normalizing dates. Concrete subclass java.text.SimpleDateFormat implements date and time value formatting for all supported locales.
J2EE applications should represent date and time values using class java.util.Date, interpret them using class Calendar, and parse and format them using class DateFormat. See The Java Tutorial for examples of how to use these classes together.
Collation is the process of ordering text using language- or script-specific rules, rather than using binary comparison, and is therefore locale-specific. A character set may have multiple collating sequences, some of which may have to do with properties of the script. For example, alphabets (like Roman) with a concept of upper- and lowercase can have multiple collating sequences that treat letter case differently. Lists of numbers may be ordered numerically or lexically. International character sets may have diacritics, non-phonetic lexical symbols, ligatures, equivalent characters (Greek
and
, for example), and other features that affect collation.
The J2SE standard abstract class java.text.Collator and related classes provide locale-aware collation. Collator is recommended for ordering lists of items in internationalized J2EE applications. For example, a component that produces ordered lists of catalog entries could use Collator to place the entries in an order appropriate to the client's locale.
Dependence on database collation services is discouraged. Collating in database queries or stored procedures requires complex bean-managed persistence code. Most databases only support one sort order at a time. Database collation services have other limitations and, in any case, are nonportable.
Collator is recommended because its behavior is independent of the source of the data being ordered. In an enterprise application, the same locale-aware collation code could be used for data retrieved from enterprise beans using container- managed persistance (CMP), data received from a Web client or Web service, data retrieved using JDBC, or data accessed by a Connector. Collator gives the developer more control over the results of the collation. It is also portable, and its data source independence ensures that collation is consistent throughout the application.