Internationalize your software, Part 3

Learn how to develop software for the global marketplace

1 2 3 4 5 Page 3
Page 3 of 5

Java's NumberFormat umbrella class is used to instantiate numeric formatters. Since NumberFormat is an abstract class, you must call a static factory method to return a numeric formatter. NumberFormat contains a pair of static factory methods for each kind of numeric formatter; one of these methods works with the default locale, while the other method requires a Locale object argument.

The getNumberInstance () method returns a number formatter for the default locale, while the getNumberInstance (Locale) method returns a number formatter for a specified locale. The getCurrencyInstance () method returns a currency formatter for the default locale, and the getCurrencyInstance (Locale) method returns a currency formatter for a specified locale. And finally, the getPercentInstance () method returns a percent formatter for the default locale, while the getPercentInstance (Locale) method returns a percent formatter for a specified locale. As previously stated, the scientific formatter's factory methods are not publicly-accessible.

This table displays the results of running a Java application that instantiates number formatters for the U.S., France and Germany locales, and formats a floating-point number according to each locale's conventions. The source code to this application is located in example11.java.

Unformatted: 1234567.89

Formatted for en_US: 1,234,567.89 Formatted for fr_FR: 1�?234�?567,89 Formatted for de_DE: 1.234.567,89

If you were to observe the preceding results at a Microsoft Windows command prompt, you might be surprised to see a couple of strange-looking characters located in the formatted number for the fr_FR locale. Instead of seeing a space character between the 1 and 2 characters (as well as the 4 and 5 characters), you would see an accented lower-case "a" character. What's going on?

These strange-looking characters, located in the grouping (thousands) separator positions for French numbers, are represented by the Unicode value '\u00A0' and are known as non-breaking space character.

A non-breaking space character is a space character that cannot be used as the location for a line-break. Normally, when a sequence of characters exceeds the maximum length of a line, software must find a place within this line where the line can be broken (all characters following the break are moved to the next line). It would not be appropriate to break a word between its letters. Nor would it be appropriate to break a number between its digits.

The logical choice is to break a line between words and numbers -- in the area occupied by space characters. Unfortunately, there's a problem with this approach, and it manifests itself with French numbers. The appropriate symbol used as a group separator to identify the "thousands" positions within French numbers is a space character. It would be insulting to a French user if software broke a line at one of these separators; part of the number would appear on one line while the other part appears on the next line. The Unicode standardization committee came up with a novel solution to this problem: the non-breaking space character. This character appears as a space character, but it's not treated as one by software.

So how do we use number formatters? Take a look at the following code fragment.

double value = 1234567.89; ...

Locale locales [] = { Locale.US, Locale.FRANCE, Locale.GERMANY };

for (int i = 0; i < locales.length; i++) { NumberFormat nf = NumberFormat.getNumberInstance (locales [i]);

System.out.println ("Formatted for " + locales [i] + ": " + nf.format (value)); }

This code fragment iterates through an array of Locale objects -- United States, France and Germany. For each Locale object, NumberFormat's getNumberInstance (Locale) static factory method is called to instantiate a number formatter. Once instantiated, the formatter's format (double) method is called to format the contents of the value variable according to each locale's conventions.

The next table shows the results of running a Java application that instantiates currency formatters for the U.S., France, Germany and Japan locales, and formats a floating-point number according to each locale's conventions. The source code to this application is located in example12.java.

Unformatted: 1234567.89

Formatted for en_US: ,234,567.89 Formatted for fr_FR: 1�?234�?567,89 F Formatted for de_DE: 1.234.567,89 DM Formatted for ja_JP: €1,234,567.89

The code behind this example is almost identical to the previous example's code. The only differences are the inclusion of the Japan locale and the static factory method that's called to instantiate a currency formatter: NumberFormat nf = NumberFormat.getCurrencyInstance (locales [i]);.

Here are the results of running a Java application that instantiates percent formatters for the U.S., France and Germany locales, and formats a floating point-number according to each locale's conventions. The source code to this application is located in example13.java.

Unformatted: 120.89

Formatted for en_US: 12,089% Formatted for fr_FR: 12�?089% Formatted for de_DE: 12.089%

The code behind this example is almost identical to the previous example's code. The only differences are the absence of the Japan locale and the static factory method that's called to instantiate a percent formatter: NumberFormat nf = NumberFormat.getPercentInstance (locales [i]);. Once again, since France uses a space character as its grouping (thousands) separator, this formatter places a non-breaking space character in the result.

NumberFormat's numeric, currency, and percentage formatters also can be used to parse locale-specific strings of numeric, currency or percentage values. This is accomplished through a numeric formatter's parse (String) method.

Figures 1a through 1e show the results of running a Java application that parses user-entered numeric, currency and percentage values for a variety of locales. The Java command line that was used to generate each set of results is shown at the top of each figure. The source code to this application is located in example14.java.

java example14 23.0

args [0] = 23.0

Locale = en_US

Using numeric parser.

Parsed result = 23.0

Figure 1a: Numeric parser results for United States locale

java example14 4,322.89 C

args [0] = 4,322.89 args [1] = C

Locale = en_US

Using currency parser.

Parsed result = 54322.89

Figure 1b: Currency parser results for United States locale

java example14 95.8% P

args [0] = 95.8% args [1] = P

Locale = en_US

Using percentage parser.

Parsed result = 0.958

Figure 1c: Percentage parser results for United States locale

java example14 134,89 N fr FR

args [0] = 134,89 args [1] = N args [2] = fr args [3] = FR

Locale = fr_FR

Using numeric parser.

Parsed result = 134.89

Figure 1d: Numeric parser results for France locale

java example14 "1.234,89 DM" C de

args [0] = 1.234,89 DM args [1] = C args [2] = de

Locale = de

Using currency parser.

Parsed result = 1234.89

Figure 1e: Currency parser results for Germany locale

The first parameter to the Example 14 application is a numeric string representing a number, a currency value, or a percentage. This string must be surrounded by double-quote characters if it contains embedded space characters. This is optionally followed by an uppercase letter that defines the kind of parser: C for currency, N for number, or P for percentage. The default is number. Following this parser code is an optional language ID and an optional country ID.

Detailed information about NumberFormat is available in the following class reference, located at Sun's Java Web site: http://java.sun.com/products/jdk/1.1/docs/api/java.text.NumberFormat.html.

So what happens if your code needs a number, currency, or percent formatter for a locale that's not supported? Java provides a solution via the DecimalFormat and DecimalFormatSymbols classes. (These classes are used internally by NumberFormat.)

DecimalFormat allows you to create your own patterns (structures that define ways of doing things) for controlling the visual representation of a formatted value. DecimalFormatSymbols allows you to define the actual characters that appear in this visual representation. Please consult The Java Tutorial (see Resources) for more information on using these classes.

Detailed information about DecimalFormat is available in the following class reference, located at Sun's Java Web site: http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html. And detailed information about DecimalFormatSymbols is available in the following class reference, located at Sun's Java Web site: http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormatSymbols.html.

Date formatters

A date formatter is an object that formats a date's components into a locale-specific representation.

Java's DateFormat umbrella class is used to instantiate date formatters. Since DateFormat is an abstract class, you must call a static factory method to return a date formatter. There are several factory methods.

  • getDateInstance ()
  • getDateInstance (int)
  • getDateInstance (int, Locale)
  • getTimeInstance ()
  • getTimeInstance (int)
  • getTimeInstance (int, Locale)
  • getDateTimeInstance ()
  • getDateTimeInstance (int, int)
  • getDateTimeInstance (int, int, Locale)
  • getInstance ()

Earlier, when I defined date, I mentioned that a date consists of several components -- day, month, hour, minute, and so on. These factory methods are used to format some or all of these components. For example, the getDateInstance methods format only the components whose length is greater than or equal to a day: day, month, year, and so on. The getTimeInstance methods format only the components whose length is less than a day -- hour, minute, second, and so on. If you want to format all of the components, use the getDateTimeInstance methods. Finally, the getInstance () method is a special case of getDateTimeInstance (int, int).

Dates are formatted by using formatting styles. There are five available styles:

  • DEFAULT
  • SHORT
  • MEDIUM
  • LONG
  • FULL

The DEFAULT style is the normal style that's used by a given locale. The SHORT style is completely numeric. The MEDIUM style allows for short month names. The LONG style allows for long month names. The FULL style provides everything. This table provides some examples.

StyleU.S. Locale DateU.S. Locale TimeU.S. Locale Date & TimeGerman Locale DateGerman Locale TimeGerman Locale Date & Time
SHORT 8/25/98 12:21 PM 8/25/98 12:21 PM 25.08.98 12:21 25.08.98 12:21
MEDIUM 25-Aug-98 12:21:55 PM 25-Aug-98 12:21:55 PM 25.08.1998 12:21:55 25.08.1998 12:21:55
LONG August 25, 1998 12:21:55 PM CDT August 25, 1998 12:21:55 PM CDT 25. August 1998 12:21:55 GMT-05:00 25. August 1998 12:21:55 GMT-05:00
FULL Tuesday, August 25, 1998 12:21:55 o'clock PM CDT Tuesday, August 25, 1998 12:21:55 o'clock PM CDT Dienstag, 25. August 1998 12.21 Uhr GMT-05:00 Dienstag, 25. August 1998 12.21 Uhr GMT-05:00

Below are the partial results of running a Java application that creates date formatters using the FULL formatting style. The source code to this application is located in example15.java.

Default Locale: en_US Date: Monday, August 17, 1998 Default Locale: en_US Time: 4:15:04 o'clock PM CDT Default Locale: en_US Date/Time: Monday, August 17, 1998 4:15:04 o'clock PM CDT

...

Locale: fi_FI Date: 17. elokuuta 1998 Locale: fi_FI Time: 16:15:04 GMT-05:00 Locale: fi_FI Date/Time: 17. elokuuta 1998 16:15:04 GMT-05:00

...

Locale: fr_CA Date: 17 aošt, 1998 Locale: fr_CA Time: 16 h 15 GMT-05:00 Locale: fr_CA Date/Time: 17 aošt, 1998 16 h 15 GMT-05:00

The following code fragment demonstrates how to create a date formatter:

// Get the current date.

Date now = new Date ();

// Get a date formatter for the default locale using the FULL date style.

DateFormat df = DateFormat.getDateInstance (DateFormat.FULL);

After the current date is obtained and stored in the now object, the getDateInstance (int) factory method is called. This method's single argment defines a formatting style. In this case, the FULL formatting style is represented by the DateFormat.FULL constant.

DateFormat's date formatters also can be used to parse locale-specific strings. This is accomplished through a date formatter's parse (String) method.

This applet parses user-entered dates and formats the results using date formatters. The source code to this applet is located in example16.java.

You need a Java-enabled browser to view this applet.

In the Input text field, enter a date, time, or date/time combination (as specified by the Formatter choice) using locale-specific conventions (as specified by the Locale choice). Press the FULL, LONG, MEDIUM, and SHORT buttons to parse the contents of the Input text field according to an appropriate style. (The entered text must be appropriate for a style.) If parsing is successful, the parsed text will be displayed in the Output text field. If it is not successful, an Unable to Parse! error message will be displayed in the Output text field.

IMPORTANT NOTE: Unfortunately, the applet above works erratically with JDK versions less than 1.1.6. This means that if you try to run this applet in a browser that does not support 1.1.6 or higher, parsing will not always work (you receive the Unable to Parse! message). For some reason, the Formatter and Locale drop-down listboxes are "crammed" together, with the lower-part of the Locale listbox missing. Occasionally, the contents of these listboxes are overwritten. In short, this applet works fine with the JDK 1.1.6 appletviewer program.

Detailed information about DateFormat is available in the following class reference, located at Sun's Java Web site: http://java.sun.com/products/jdk/1.1/docs/api/java.text.DateFormat.html.

Related:
1 2 3 4 5 Page 3
Page 3 of 5