diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 68a8cabce..9c8bd3cd4 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -156,22 +156,20 @@ en_US en_GB - de_QY - zz_QY + *_QY + QY English (US) English (UK) @string/subtype_generic_qwerty - @string/subtype_qwerty + QWERTY %s %s (QWERTY) - - QWERTY com.google.android.inputmethod.latin.dictionarypack diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 4f038e1a5..a22c68cb8 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -252,6 +252,8 @@ English (UK) English (US) + + No language (QWERTY) Usability study mode diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 7a21a856b..e43fb32a4 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -312,7 +312,7 @@ android:imeSubtypeExtraValue="AsciiCapable" /> = 0) { - final String languageName = locale.getDisplayLanguage(locale); - return String.format(value, languageName); - } - return value; + if (sExceptionKeys[index].equals(key)) { + return sExceptionValues[index]; } } - return locale.getDisplayName(locale); + return null; + } + + // Get Locale's full display name in its locale. + // For example: + // "fr_CH" is converted to "Français (Suisse)". + // "de_QY" is converted to "Deutsche (QWERTY)". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getFullDisplayName(Locale locale) { + final String key; + if (locale.getLanguage().equals(NO_LANGUAGE)) { + key = locale.getCountry(); + } else if (locale.getCountry().equals(QWERTY)) { + key = "*_" + QWERTY; + } else { + key = locale.toString(); + } + final String value = lookupExceptionalLocale(key); + if (value == null) { + return toTitleCase(locale.getDisplayName(locale), locale); + } + if (value.indexOf("%s") >= 0) { + final String languageName = toTitleCase(locale.getDisplayLanguage(locale), locale); + return String.format(value, languageName); + } + return value; + } + + // Get Locale's middle display name in its locale. + // For example: + // "fr_CH" is converted to "Français". + // "de_QY" is converted to "Deutsche". (Any locale that has country code "QY") + // "zz_QY" is converted to "QWERTY". (The language code "zz" means "No language", thus just + // ends up with the keyboard layout name.) + public static String getMiddleDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return lookupExceptionalLocale(locale.getCountry()); + } else { + return toTitleCase(locale.getDisplayLanguage(locale), locale); + } + } + + // Get Locale's short display name in its locale. + // For example: + // "fr_CH" is converted to "Fr". + // "de_QY" is converted to "De". (Any locale that has country code "QY") + // "zz_QY" is converter to "QY". (The language code "zz" means "No language", thus just ends + // up with the keyboard layout name.) + public static String getShortDisplayName(Locale locale) { + if (NO_LANGUAGE.equals(locale.getLanguage())) { + return locale.getCountry(); + } else { + return toTitleCase(locale.getLanguage(), locale); + } + } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index e35364420..c2dafcf73 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -420,10 +420,6 @@ public class SubtypeSwitcher { return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); } - public String getInputLanguageName() { - return StringUtils.getDisplayLanguage(getInputLocale()); - } - ///////////////////////////// // Other utility functions // ///////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7b13e40c2..cd01bb146 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,6 +37,7 @@ import com.android.inputmethod.latin.Flag; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeLocale; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; import com.android.inputmethod.latin.WhitelistDictionary; @@ -325,8 +326,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService } else if (CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise - mSuggestions.set(i, StringUtils.toTitleCase(mSuggestions.get(i).toString(), - locale)); + mSuggestions.set(i, SubtypeLocale.toTitleCase( + mSuggestions.get(i).toString(), locale)); } } // This returns a String[], while toArray() returns an Object[] which cannot be cast diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index 089fdc52c..6180ff5f9 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -23,11 +23,14 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import java.util.ArrayList; -import java.util.List; import java.util.Locale; public class SubtypeLocaleTests extends AndroidTestCase { - private List mKeyboardSubtypes; + private static final Locale LOCALE_zz_QY = SubtypeLocale.LOCALE_NO_LANGUAGE_QWERTY; + private static final Locale LOCALE_de_QY = + new Locale(Locale.GERMAN.getLanguage(), SubtypeLocale.QWERTY); + + private ArrayList mSubtypesList; @Override protected void setUp() throws Exception { @@ -42,46 +45,111 @@ public class SubtypeLocaleTests extends AndroidTestCase { Context.INPUT_METHOD_SERVICE); for (final InputMethodInfo imi : imm.getInputMethodList()) { if (imi.getPackageName().equals(packageName)) { - mKeyboardSubtypes = new ArrayList(); + mSubtypesList = new ArrayList(); final int subtypeCount = imi.getSubtypeCount(); - for (int i = 0; i < subtypeCount; ++i) { - InputMethodSubtype subtype = imi.getSubtypeAt(i); - if (subtype.getMode().equals("keyboard")) { - mKeyboardSubtypes.add(subtype); - } + for (int i = 0; i < subtypeCount; i++) { + final InputMethodSubtype ims = imi.getSubtypeAt(i); + mSubtypesList.add(ims); } break; } } - assertNotNull("Can not find input method " + packageName, mKeyboardSubtypes); - assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0); + assertNotNull("Can not find input method " + packageName, mSubtypesList); + assertTrue("Can not find keyboard subtype", mSubtypesList.size() > 0); } - public void testSubtypeLocale() { + private static Locale getSubtypeLocale(InputMethodSubtype subtype) { + return LocaleUtils.constructLocaleFromString(subtype.getLocale()); + } + + private static Locale getKeyboardLocale(InputMethodSubtype subtype) { + final String subtypeLocaleString = subtype.containsExtraValueKey( + LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) + : subtype.getLocale(); + return LocaleUtils.constructLocaleFromString(subtypeLocaleString); + } + + public void testFullDisplayName() { final StringBuilder messages = new StringBuilder(); int failedCount = 0; - for (final InputMethodSubtype subtype : mKeyboardSubtypes) { - final Locale locale = LocaleUtils.constructLocaleFromString(subtype.getLocale()); - if (locale.getLanguage().equals("zz")) { + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { // This is special language name for language agnostic usage. continue; } - final String subtypeLocaleString = - subtype.containsExtraValueKey(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - ? subtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE) - : subtype.getLocale(); - final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(subtypeLocaleString); - // The subtype name in its locale. For example 'English (US)' or 'Deutsch (QWERTY)'. - final String subtypeName = SubtypeLocale.getFullDisplayName(subtypeLocale); - // The locale language name in its locale. - final String languageName = locale.getDisplayLanguage(locale); - if (!subtypeName.contains(languageName)) { + final String keyboardName = SubtypeLocale.getFullDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.contains(languageName)) { failedCount++; messages.append(String.format( - "subtype name is '%s' and should contain locale '%s' language name '%s'\n", - subtypeName, subtypeLocale, languageName)); + "locale %s: keyboard name '%s' should contain language name '%s'\n", + locale, keyboardName, languageName)); } } assertEquals(messages.toString(), 0, failedCount); } + + public void testFullDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getFullDisplayName(LOCALE_zz_QY)); + + final String de_QY = SubtypeLocale.getFullDisplayName(LOCALE_de_QY); + assertTrue("de_QY", de_QY.contains("(QWERTY")); + assertTrue("de_QY", de_QY.contains(Locale.GERMAN.getDisplayLanguage(Locale.GERMAN))); + } + + public void testMiddleDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getLanguage().equals(SubtypeLocale.NO_LANGUAGE)) { + // This is special language name for language agnostic usage. + continue; + } + final String keyboardName = SubtypeLocale.getMiddleDisplayName(locale); + final String languageName = SubtypeLocale.toTitleCase( + locale.getDisplayLanguage(locale), locale); + if (!keyboardName.equals(languageName)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language name '%s'\n", + locale, keyboardName, languageName)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testMiddleDisplayNameNoLanguage() { + assertEquals("zz_QY", "QWERTY", SubtypeLocale.getMiddleDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "Deutsch", SubtypeLocale.getMiddleDisplayName(LOCALE_de_QY)); + } + + public void testShortDisplayName() { + final StringBuilder messages = new StringBuilder(); + int failedCount = 0; + for (final InputMethodSubtype subtype : mSubtypesList) { + final Locale locale = getKeyboardLocale(subtype); + if (locale.getCountry().equals(SubtypeLocale.QWERTY)) { + // This is special country code for QWERTY keyboard. + continue; + } + final String keyboardName = SubtypeLocale.getShortDisplayName(locale); + final String languageCode = SubtypeLocale.toTitleCase(locale.getLanguage(), locale); + if (!keyboardName.equals(languageCode)) { + failedCount++; + messages.append(String.format( + "locale %s: keyboard name '%s' should be equals to language code '%s'\n", + locale, keyboardName, languageCode)); + } + } + assertEquals(messages.toString(), 0, failedCount); + } + + public void testShortDisplayNameNoLanguage() { + assertEquals("zz_QY", "QY", SubtypeLocale.getShortDisplayName(LOCALE_zz_QY)); + assertEquals("de_QY", "De", SubtypeLocale.getShortDisplayName(LOCALE_de_QY)); + } }