Internationalization Formatting

   

In most cases, the work that must be done to provide support for internationalization of a Java application is in the formatting of output data for a specific locale. Numbers , dates, and other text can all require formatting before they are displayed. Java provides a set of easy to use classes for formatting data based on standard locale formatting rules. The support for internationalization formatting is provided through the Format class and its specialized set of format classes.

Format Class

The java.text.Format class is an abstract base class that provides support for formatting dates, times, numbers, and other locale sensitive objects into strings and also for parsing strings back into the corresponding objects. The three main subclasses are

  • DateFormat ” Format and parse date and times in a locale-sensitive way.

  • NumberFormat ” Format and parse numerical data in a locale-sensitive way.

  • MessageFormat ” Format and parse string messages in a language-independent way.

Date and Time Formatting

Date and Time are stored internally in a locale-independent manner. To produce a locale-sensitive date or time, the date and/or time must be formatted specifically for a particular locale where it is being used. The same internally stored date would be displayed differently for two distinct locales. The following two lines show an example of the same date for two different locales:

 November 3, 1997 (English) 3 novembre 1997 (French) 

The DateFormat class is actually an abstract class. It has several static methods for getting locale-sensitive formats for date and times. A concrete subclass of DateFormat is SimpleDateFormat and is probably used more than any other class for formatting date and times. It has functionality to format a Date object to a string and also to parse a string into a Date object. The SimpleDateFormat provides a set of patterns that will be used when formatting or parsing a Date or date String object. A summary of that set of patterns is provided here:

Symbol Meaning Presentation Example
G era designator (Text) AD
y year (Number) 1996
M month in year (Text & Number) July & 07
d day in month (Number) 10
h hour in am/pm (1~12) (Number) 12
H hour in day (0~23) (Number)
m minute in hour (Number) 30
s second in minute (Number) 55
S millisecond (Number) 978
E day in week (Text) Tuesday
D day in year (Number) 189
F day of week in month (Number) 2 (2 nd Wed in July)
w week in year (Number) 27
W week in month (Number) 2
a am/pm marker (Text) PM
k hour in day (1~24) (Number) 24
K hour in am/pm (0~11) (Number)
z time zone (Text) Pacific Standard Time
' escape for text (Delimiter)  
'' single quote (Literal) `''
  single quote (Literal) '

A pattern is constructed using these symbols and then the pattern is applied when formatting a Date object or parsing a date String. Here are some examples of using these patterns to format date and time strings:

Format Pattern Result
"yyyy.MM.dd G 'at'hh:mm:ss z" 1996.07.10 AD at 15:08:56 PDT
"EEE, MMM d, ''yy" Wed, July 10, '96
"h:mm a" 12:08 PM
"hh 'o''clock'a, zzzz" 12 o'clock PM, Pacific Daylight Time
"K:mm a, z" 0:00 PM, PST
"yyyyy.MMMMM.dd GGG hh:mm aaa" 1996.July.10 AD 12:08 PM

Listing 24.1 shows an example of how to use a custom format. Here it is used to format a Timestamp object into a certain format. This format pattern is hard-coded here, but it easily be put into a ResourceBundle to make it easier to change.

Listing 24.1 Using a Custom Format Pattern
 import java.sql.Timestamp; import java.text.DateFormat; import java.text.SimpleDateFormat; public class CustomDateFormat {   // Default Constructor   public CustomDateFormat()   {     super();   }   public void printTimestamp( Timestamp ts, String formatPattern )   {     SimpleDateFormat dateFormat = new SimpleDateFormat( formatPattern );     dateFormat.applyPattern( formatPattern );     String timeStampStr = dateFormat.format( ts );     System.out.println( timeStampStr );   }   public static void main(String[] args)   {     CustomDateFormat example = new CustomDateFormat();     // Create a custom format pattern string     String pattern = "EEE, MMM d, ''yy";     // Create a Timestamp object     Timestamp ts = Timestamp.valueOf( "2000-09-10 15:30:20.000" );     example.printTimestamp( ts, pattern );   } } 

Although you can use these patterns to generate a SimpleDateFormat instance, you are encouraged to create a date-time formatter with getTimeInstance, getDateInstance, or getDateTimeInstance methods in the DateFormat class. Each of these class methods can return a date/time formatter initialized with a default format pattern. You can thenuse the format method as before to format a Date to the proper Locale string.

Listing 24.2 Using the Default Date Format
 import java.sql.Timestamp; import java.text.DateFormat; import java.text.SimpleDateFormat; public class DefaultDateFormat {   // Default Constructor   public DefaultDateFormat()   {     super();   }   public void printTimestamp( Timestamp ts )   {     DateFormat dateFormat = DateFormat.getDateTimeInstance();     String timeStampStr = dateFormat.format( ts );     System.out.println( timeStampStr );   }   public static void main(String[] args)   {     DefaultDateFormat example = new DefaultDateFormat();     // Create a Timestamp object     Timestamp ts = Timestamp.valueOf( "2000-09-10 15:30:20.000" );     example.printTimestamp( ts );   } } 

Number Formatting

The java.text.NumberFormat class and the concrete subclass DecimalNumberFormat give the Java programmer the ability to parse and format numerical data in a language-specific manner. As stated before, the data is stored internally in a locale-neutral format and then can be formatted depending on the current locale.

With the DecimalNumberFormat class, differences in the way decimal point data is displayed in various Locales can easily be handled with little. For example, the code in Listing 24.3 prints out a decimal number in all the available Locales. If you wanted to print out the information just for the default Locale, you could get an instance of a DecimalFormat object by using the static getInstance method on the NumberFormat class.

Listing 24.3 Using the DecimalFormat Class
 import java.util.Locale; import java.text.NumberFormat; public class DecimalFormatExample {   public DecimalFormatExample()   {   }   public void formatDecimalNumber( Locale aLocale, double aDecimalNumber )   {     NumberFormat format = NumberFormat.getInstance( aLocale );     System.out.println( aLocale.getDisplayName() + " " + format.format ( aDecimalNumber ) graphics/ccc.gif );   }   public static void main(String[] args)   {     DecimalFormatExample example = new DecimalFormatExample();     // Create a decimal number      double aDecimalNumber = -7143.65;     // Get the installed Locales     Locale[] availableLocales = NumberFormat.getAvailableLocales();     int size = availableLocales.length;     for( int i = 0; i < size; i++ )     {       Locale aLocale = availableLocales[i];       // Skip language-only locales       if( aLocale.getCountry().length() != 0 )         example.formatDecimalNumber( aLocale, aDecimalNumber );     }   } } 

Message Formatting

The java.text.MessageFormat class provides a way to concatenate messages in a language-neutral manner. Although it can be used for non-internationalized applications just as well, its use can save time in internationalized application that need to dynamically concatenate messages at runtime. For example, say that you need to print out a message to the user of how many files are contained on a particular drive and we want to be able to print the same message in both English and German.

Ideally, the display strings would come from a ResourceBundle and we would just load the correct ResourceBundle depending on the Locale. The example in Listing 24.4 shows how you might go about doing this task. In this example however, we don't utilize a ResourceBundle, but rather have the format strings in the main method. This is to keep the example simple. The only difference between this example and one using a ResourceBundle is with a ResouceBundle, you just need to read in the correct pattern from the Bundle and pass it to the formatMessage method in the example class. Here is Listing 24.4.

Listing 24.4 An Example using the MessageFormat Class
 import java.text.MessageFormat; public class MessageFormatExample {   // Default Constructor   public MessageFormatExample()   {     super();   }   public void formatMessage( String pattern, Object[] tokens )   {     MessageFormat msgFormatter = new MessageFormat( pattern );     System.out.println( msgFormatter.format( pattern, tokens ) );   }   public static void main(String[] args)   {     MessageFormatExample example = new MessageFormatExample();     // Create a English pattern for the MessageFormat object to use     String englishPattern = "The disk { 0}  contains { 1}  files.";     // Create a French Pattern for the MessageFormat Object to use     String frenchPattern = "Il y a { 0}  fichiers sur le disque { 1} .";     // Create the token array and initialize it     Object[] tokens = { "C", "3"} ;     // Format the English version     example.formatMessage( englishPattern, tokens );     // Format the French version     example.formatMessage( frenchPattern, tokens );   } } 

Here is the output for Listing 24.4.

 C:\jdk1.3se_book\classes>java MessageFormatExample The disk C contains 3 files. Il y a C fichiers sur le disque 3. C:\jdk1.3se_book\classes> 

The top message that is printed out from Listing 24.4 is obviously for an English locale, whereas the bottom one is for a French locale. Notice that in both cases, the number of files is 3 and the drive letter is C.

Again, the pattern format should probably be stored in a resource bundle and the data can be inserted into the message dynamically. The MessageFormat class uses a pattern to figure out where to insert the data into the message. Look at one of the patterns from the previous Listing. Here's the English Locale pattern from the Listing in 24.4:

 "The disk { 0}  contains { 1}  files." 

Remember that this message should come from a ResourceBundle and represents the English locale. The French equivalent pattern looks like this:

 "Il y a { 0}  fichiers sur le disque { 1} ." 

Notice that the data that's being inserted into each message is the same. Only the message itself is different. When you call the format method on the MessageFormat class, you can pass an object array. The number and 1 that you see in these patterns are indexes into the object[] that was passed in.

Remember in the beginning of this section, you read that the MessageFormat could be used for situations other than internationalization. There are no locale-specific methods or functionality in the MessageFormat class. You just need to set up the locale-specific strings in ResourceBundles and then use them accordingly .

The MessageFormat class can also be used in other areas of Java application design. Suppose you need to send email messages to different users wherein only a certain portion of the email was specific to a user. You could set up a MessageFormat pattern for this and then just substitute the dynamic information for each user into the appropriate template. The MessageFormat class is really flexible and makes this type of application programming easy to do.

   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net