Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Locale variant for simplified chinese

Tags:

android

locale

How can I get simplified chinese description (简体)? From the available locale Locale.SIMPLIFIED_CHINESE, no method seems to return this description:

  • getDisplayLanguage() returns the correct language name, but without the variant.
  • getDisplayName() returns the correct language name and country, but also without the variant.
  • getDisplayVariant() returns an empty string.

I've also tried to build a new Locale using the different constructors, also to no avail.

new Locale("zh", "CN");
new Locale("zh", "CN", "Hans");

I've checked the Android source code for LocalePicker and I've concluded that it is loaded from the resources (special_locale_codes and special_locale_names).

Any solutions besides having to hardcode/include this string in my resources?

like image 803
m0skit0 Avatar asked Apr 09 '15 10:04

m0skit0


1 Answers

Let me explain my process on how I tackled this. First, I found this block of code in LocalePicker.java

private static String getDisplayName(Locale l, String[] specialLocaleCodes, String[] specialLocaleNames) {
    String code = l.toString();

    for (int i = 0; i < specialLocaleCodes.length; i++) {
        if (specialLocaleCodes[i].equals(code)) {
            return specialLocaleNames[i];
        }
    }
    return l.getDisplayName(l);
}

which takes in a Locale as you already know. Then it tries to find the locale code in the specialLocaleCodes string array. The specialLocaleNames you are seeking are obtained from arrays.xml as you've helpfully stated:

<string-array translatable="false" name="special_locale_codes">
    <item>ar_EG</item>
    <item>zh_CN</item>
    <item>zh_TW</item>
</string-array>

and the corresponding languages

<string-array translatable="false" name="special_locale_names">
    <item>العربية</item>
    <item>中文 (简体)</item>
    <item>中文 (繁體)</item>
</string-array>

Notice the code with the simplified Chinese is zh_CN and the last two characters are capitalized.

However,

Locale locale = new Locale("zh_CN");
System.out.println("Locale: " + locale);

prints

Locale: zh_cn

Notice the lower case. So there is no way specialLocaleCodes[i].equals(code) will return true. So then I poked around Locale.java and, long story short, we can bypass that case-changing jumble by doing this (and you MUST keep the 3rd parameter as an empty string for this to work):

Locale locale = new Locale("zh", "CN", "");
System.out.println("Locale: " + locale);

Prints

Locale: zh_CN

With this you should be able to do this:

Locale locale = new Locale("zh", "CN", "");
System.out.println("Name:" + locale.getDisplayName(locale));

Upon further inspection on Kitkat using this (thank you Andrew!)

int specialLocaleNamesId = Resources.getSystem().getIdentifier("special_locale_names", "array", "android");
String[] specialLocaleNames = Resources.getSystem().getStringArray(specialLocaleNamesId);

it was possible to print out

العربية,中文 (简体),中文 (繁體)

as expected. However, something in Kitkat is still preventing the correct string to display. Frustrating.


However, in Lollipop 5.0+ and Java 1.7 this works using forLanguageTag() in Locale.

Locale locale = Locale.forLanguageTag("zh-Hans");
System.out.println("getDisplayName:" + locale.getDisplayName(locale));
System.out.println("getDisplayLanguage:" + locale.getDisplayLanguage(locale));

which prints

getDisplayName:中文 (简体中文)
getDisplayLanguage:中文

like image 116
Drakes Avatar answered Sep 25 '22 13:09

Drakes