m0skit0
m0skit0

Reputation: 25873

Getting Locale variant for simplified chinese

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

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?

Upvotes: 13

Views: 3606

Answers (2)

Drakes
Drakes

Reputation: 23660

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:中文

Upvotes: 8

user180100
user180100

Reputation:

You could probably access the android internal resource: com.android.internal.R.array.special_locale_names the same way it's done in LocalePicker:

final Resources resources = context.getResources();
final String[] specialLocaleNames = resources.getStringArray(com.android.internal.R.array.special_locale_names);

But it's probably safer to use your own resource here (avoiding the use of internals)

Upvotes: 1

Related Questions