Friday, May 15, 2015

Locale Evolution

"Locale" is used to performs locale-sensitive operations such as formatting numeric value; it is also used to tailors locale-sensitive information for a user who from different geographical, political, or cultural region. While we could choose which locale to use in our application, but in common, the application locale is based on the computer platform locale. In other words, the application is taking the default locale. This post does not cover every feature of locale. It is about the change of default locale's behavior on Windows platform along with the evolution from Java 6 to 8.

Locale in Java 6

In Java 6, Locale is the only instance that determines the value format as well as the information display. The locale data returned by Locale.getDefault() and the locale data used in NumberFormat.getInstance() in the same.

>> Window platform

Change of the Region and Language - Formats - Format (as shown in the image below), will change the default locale in our application.


NumberFormat format1 = NumberFormat.getNumberInstance();
String formattedValue = format1.format(88000);
System.out.println(formattedValue);
       
NumberFormat format2 = NumberFormat.getNumberInstance(Locale.getDefault());
Number parsedValue = format2.parse(formattedValue);
System.out.println(parsedValue);

No matter what Windows region-format setting we set, the numeric value that is handled by format1 and format2 object in the code snippet above always maintain its value. For example, if the region format is set to Portuguese (Portugal), then the formattedValue is 88.000 ("." is the grouping symbol in Portuguese locale); and the parsedValue is 88000. It is confirmed that, NumberFormat.getNumberInstance() and NumberFormat.getNumberInstance(Locale.getDefault()) behaves the same.

>> Locale provider

However, it is important to be aware that, Java application takes the locale data which is provided in JRE based on the setting above. The locale data is not come from the hosting platform. This is why the customized formats in the Windows Region-Format setting do not apply to the application. In the case where JRE itself does not support the requested locale, then Locale methods will look for the locale data from any installed locale sensitive service provider interfaces (SPIs). This order is fixed.

>> VM options

There is another way to set the application locale. This can be done by setting the language and country VM options as below when launching the Java application. VM options below will make the application to picks up Portuguese (Portugal) locale data from JRE. In this way, the Java application will ignore the Windows Region-Format setting.

-Duser.language=pt -Duser.country=PT

Locale in Java 7

Since Java 7, Locale comes in two categories. Locale.Category.Format is for formatting value; Locale.Category.Display is for displaying texts. The locale data returned by Locale.getDefault() is display locale. The locale data used in NumberFormat.getInstance() is format locale.

>> Window platform

Change of the Region and Language - Formats - Format will change the format locale data; Change of the Region and Language - Administrative - Change System Locale (as shown in the image below) will change the display locale data. In others words, an Java application could have two different default locale data at the same time.


Running the same code snippet again with Portuguese (Portugal) region format setting and English (US) system locale, we now get the different formatted value for both format objects.

// Region-format: Portuguese (Portugal)
NumberFormat format1 = NumberFormat.getumberInstance(); // taking format locale (Portuguese)
String formattedValue = format1.format(88000);
System.out.println(formattedValue); // output: 88.000
       
// System locale: English (US)
NumberFormat format2 = NumberFormat.getNumberInstance(Locale.getDefault());  // taking display locale (English)
Number parsedValue = format2.parse(formattedValue);
System.out.println(parsedValue); // output: 88

The value formattedValue and parsedValue has significant difference even thought they derived from the same numeric value. NumberFormat.getNumberInstance() and NumberFormat.getNumberInstance(Locale.getDefault()) is no longer behaves the same. The resolution is just let the format object to use its default format locale, and only supply locale data to it if you know what you are doing.

>> Locale provider

Same as Java 6.

>> VM options

Same as Java 6. But to be specific, setting the language and country VM options to, let's said Portuguese (Portugal) will make the format locale and display locale become Portuguese basis.

Locale in Java 8

Same as Java 7.

>> Window platform

Same as Java 7.

>> Locale provider

Besides JRE and SPI, there are two new locale data providers supported in Java 8.
  • Common Locale Data Repository (CLDR): Released by Unicode Consortium "to support the world's languages, with the largest and most extensive standard repository of locale data available.
  • Host: The current customized locale setting of the underlying operating system.

>> VM options

The language and country VM options effect are same as Java 7. Moreover, the order of locale providers searching is not fixed and could be specified using the VM options as below.

-Djava.locale.providers=SPI,HOST,CLDR,JRE

Calendar calendar = Calendar.getInstance();
DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); 
System.out.println(df.format(calendar.getTime()));

Run the code snippet above with different locale provider VM options on Windows platform will get the result as below:

HOST (Customized to MMMM dd, yyyy):- February 27, 2015 12:15:02 AM
JRE:- Friday, February 27, 2015 12:13:10 AM SGT
CLDR:- Friday, February 27, 2015 12:13:42 AM Singapore Standard Time

Related posts:
Text Collation

References:
http://stackoverflow.com/questions/24616848/get-number-format-from-os http://docs.oracle.com/javase/8/docs/technotes/guides/intl/enhancements.8.html http://docs.oracle.com/javase/8/docs/api/java/util/spi/LocaleServiceProvider.html http://docs.oracle.com/javase/7/docs/api/java/util/Locale.html

No comments: