What is the different from Locale.ITALY and Locale.ITALIAN

Locale.ITALIAN sets only Italian language, country is left unspecified. Locale.ITALY sets both Italian as language and Italy as country.

It depends on classes that use Locale how they will inteprete this combination. Eg DateFormat API says to format a date for a different Locale, specify it in the call to getDateInstance(). but it does not say how exactly language and country will be interpreted. From my experience DateFormat (and other JDK classes except ResourceBundle) use only language part and ignore country. That is you may create DateFormat for it_IT or it_US or it_UK locales the DateFormat output will be the same


tl;dr

Locale = ( human language + cultural norms of a country/region )

Best to specify both, when known.

Example: If you want Italian language (it) with the cultural norms of Italy (IT), use: new Locale( "it" , "IT" ). If you want Italian language with the cultural norms of Vatican City (VA), use: new Locale( "it" , "VA" ). If you want Italian language with the cultural norms of Switzerland, use: new Locale( "it" , "CH" ).

If you specify one part but not the other, Java must fall-back:

  • If you specify a locale with only a language but not a country, Java falls back to some implementation-defined set of cultural norms.
  • Vice-versa, if you specify a country but not the human language, Java falls back to some implementation-defined human language.

The details vary across implementations and versions of Java; behavior may vary. As of Java 9, Java implementations based on OpenJDK use by default the locale definitions provided by the Unicode Common Locale Data Repository (CLDR) project. The CLDR dataset is quite mature now. So no major changes are likely, but some changes may still occur in fresh updates.

Avoid the hard-coded constants in Locale. There are only a few, and they muddy the waters as to the distinction between language and culture. Rather than use either Locale.ITALIAN or Locale.ITALY, use new Locale as seen above.

Locale

A Locale object holds two pieces of information: The human language, and cultural norms.

Human language

The human language portion of a Locale specifies the language used in translation.

For example, when formatting a date-time value, the name of the month and name of the day-of-week are generated according to the human language. Monday in English, and lundi in French.

Cultural norms

The cultural norms portion specifies various rules to follow when localizing. These rules include punctuation, abbreviation, capitalization, element ordering, and such.

For example, Canada is a dual cultural country. So when formatting a date-time object, the date in Locale.CANADA_FRENCH the cultural norm is to format the date portion with the day-of-month coming before the name-of-month while in Locale.CANADA (English) the cultural norm is the opposite. See below for example.

Example code

Some example code using the dual cultures of Canada.

package work.basil.example;

import java.time.*;
import java.time.format.*;

import java.util.Locale;

public class TickTock {
    public static void main ( String[] args ) {
        TickTock app = new TickTock();
        app.doIt();
    }

    private void doIt ( ) {

        ZoneId z = ZoneId.of( "America/Montreal" );
        ZonedDateTime zdt = ZonedDateTime.now( z );

        FormatStyle fs = FormatStyle.MEDIUM;

        Locale lCanadaFrench = Locale.CANADA_FRENCH;
        DateTimeFormatter fCanadaFrench = DateTimeFormatter.ofLocalizedDateTime( fs ).withLocale( lCanadaFrench );
        String outputCanadaFrench = zdt.format( fCanadaFrench );

        Locale lCanadaEnglish = Locale.CANADA;
        DateTimeFormatter fCanadaEnglish = DateTimeFormatter.ofLocalizedDateTime( fs ).withLocale( lCanadaEnglish );
        String outputCanadaEnglish = zdt.format( fCanadaEnglish );

        System.out.println( zdt );
        System.out.println( outputCanadaFrench );
        System.out.println( outputCanadaEnglish );

    }
}

When run in Java 11 using Zulu by Azul Systems, built on OpenJDK, running on macOS Mojave.

2019-01-17T17:36:10.818469-05:00[America/Montreal]

17 janv. 2019 17 h 36 min 10 s

Jan. 17, 2019, 5:36:10 p.m.

Language-only

When you specify a locale with only a human language but no country/region for cultural norms, Java falls back onto some set of cultural norms as a default. The details are up to the particular implementation of Java. And those details are subject to change in successive versions of that implementation.

Common Locale Data Repository (CLDR)

Indeed, the details changed dramatically in implementations of Java based on the OpenJDK project. In OpenJDK 8, at least two sources of locale data were bundled: the legacy source and the much richer source from the Unicode Consortium (https://en.wikipedia.org/wiki/Unicode_Consortium), the Common Locale Data Repository (CLDR), with the legacy source used first. In OpenJDK 9 and later, a change was made (JEP 252) to always check the CLDR first for locale data. This change altered the behavior for some locales.

When you know the desired/expected cultural norms to be used, specify by indicating the country code. For example, rather than just ar for Arabic, specify the cultural norms of Saudi Arabia (ar-SA), Tunisia (ar-TN), or Morocco (ar-MA).

Variant

In addition to the grosser level of country code, you can also specify a locale with a variant, for a subculture. While not many variants were available in the legacy Java locale data, many many variants are provided in the CLDR.

For more info, read the JavaDoc for Locale and the CLDR documentation.

Constants

The Locale class has only a few locales hard-coded as named constants. In retrospect, including those constants was probably a poor design decision. You may want to ignore them and always use constructors (new Locale) or the factory methods.

For Italian language with cultural norms, specify both to make your code crystal-clear as to your intentions.

Locale locale = new Locale( "it" , "IT" ) ;  // Pass standard code for human language, and standard code for country (cultural norms). 

To see all constants, run this code. Be aware, as discussed above, available locales and their behavior may vary by implementation of Java.

for ( Locale locale : Locale.getAvailableLocales() ) {
    System.out.println( locale.toString() + "  Name: " + locale.getDisplayName( Locale.US ) );
}

Tags:

Java

Locale