Hendra Anggrian
Hendra Anggrian

Reputation: 5858

java.util.Locale returns different language it is built with

Consider a simple test I've written in Kotlin:

class LocaleTest {

    @Test fun english() {
        val locale = Locale("en")
        assertEquals("English", locale.displayLanguage)
        assertEquals("en", locale.language)
    }

    @Test fun indonesia() {
        val locale = Locale("id")
        assertEquals("Indonesian", locale.displayLanguage)
        assertEquals("id", locale.language)
    }
}

The second test fails because it is expected to be id but actually in. How is this possible? The Locale was built with language id, shouldn't it be safe to assume that it will return the same language?

Upvotes: 6

Views: 2119

Answers (4)

Ruslan Akhundov
Ruslan Akhundov

Reputation: 2216

From the documentation:

ISO 639 is not a stable standard; some of the language codes it defines * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other * API on Locale will return only the OLD codes.

So id is a new one, however documentation specifically says that for this case in would be returned. Why is that? I believe, may be not to break old applications using in as expected output, so in other words to support backwards compatibility.

If you need to check if locale you are using is Indonesian then recommended way would probably be to create some static constant variable with specified locale, and to check equality with it.

So in some Util class(in Kotlin you can use companion object instead I think):

public static final Locale INDONESIAN_LOCALE = new Locale("id");

and when you need to check:

if (INDONESIAN_LOCALE.equals(receivedLocale)) {
     ...they are the same...
}

Upvotes: 2

daniu
daniu

Reputation: 14999

From the Javadoc:

Note: ISO 639 is not a stable standard— some languages' codes have changed. Locale's constructor recognizes both the new and the old codes for the languages whose codes have changed, but this function always returns the old code.

If you want to check for a specific language whose code has changed, don't do

 if (locale.getLanguage().equals("he")) // BAD!

Instead, do

if (locale.getLanguage().equals(new Locale("he").getLanguage()))

Upvotes: 3

JoshDM
JoshDM

Reputation: 5072

This is a known bug in Java that won't be fixed in order to maintain backwards-compatibility.

For more info: https://bugs.java.com/view_bug.do?bug_id=6457127

Upvotes: 1

nbokmans
nbokmans

Reputation: 5747

A look at the documentation for java.util.Locale's getLanguage() says the following:

public String getLanguage()

Returns the language code of this Locale.

Note: ISO 639 is not a stable standard— some languages' codes have changed. Locale's constructor recognizes both the new and the old codes for the languages whose codes have changed, but this function always returns the old code. If you want to check for a specific language whose code has changed, don't do

Source: https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html#getLanguage()

What this means is that at one point in time according to the ISO 639 standard, the Indonesian Locale was identified by in, however there have been changes since then which had the Indonesian Locale identifier change to id.

Upvotes: 2

Related Questions