From aaefd5666112c4a6fff58783c25cf9a75b468edd Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 28 Aug 2014 15:14:36 +0900 Subject: [PATCH] Add !string/ reference This CL introduces new text reference notation !string/ to refer a string resource on the fly. This notation is mainly used to represent action key labels may refer a string in a system locale in run-time. This notation is needed to implement Hinglish and Serbian-Latin keyboards that need to refer its own action key labels. Bug: 17169632 Bug: 9687668 Change-Id: I042f6bd04714e0e448cd92031730eb9fb422e6d3 --- .../keyboard/internal/KeyboardTextsSet.java | 92 +++--- .../keyboard/internal/KeyboardTextsTable.java | 122 +++++--- .../latin/utils/SubtypeLocaleUtils.java | 2 +- tests/res/values/donottranslate.xml | 18 +- .../KeyboardLayoutSetActionLabelBase.java | 6 +- .../KeyboardLayoutSetActionLabelKlpTests.java | 102 ++++++- .../internal/MoreKeySpecSplitTests.java | 200 ++---------- .../MoreKeySpecStringReferenceTests.java | 284 ++++++++++++++++++ .../donottranslate-more-keys.xml | 8 + .../res/values/donottranslate-more-keys.xml | 8 + 10 files changed, 547 insertions(+), 295 deletions(-) create mode 100644 tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecStringReferenceTests.java diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index cd6abeed3..f9297ac27 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -25,49 +25,42 @@ import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; -import java.util.HashMap; import java.util.Locale; +// TODO: Make this an immutable class. public final class KeyboardTextsSet { public static final String PREFIX_TEXT = "!text/"; + private static final String PREFIX_RESOURCE = "!string/"; public static final String SWITCH_TO_ALPHA_KEY_LABEL = "keylabel_to_alpha"; private static final char BACKSLASH = Constants.CODE_BACKSLASH; - private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; + private static final int MAX_REFERENCE_INDIRECTION = 10; + private Resources mResources; + private Locale mResourceLocale; + private String mResourcePackageName; private String[] mTextsTable; - // Resource name to text map. - private HashMap mResourceNameToTextsMap = new HashMap<>(); public void setLocale(final Locale locale, final Context context) { - mTextsTable = KeyboardTextsTable.getTextsTable(locale); final Resources res = context.getResources(); - final int referenceId = context.getApplicationInfo().labelRes; - final String resourcePackageName = res.getResourcePackageName(referenceId); - final RunInLocale job = new RunInLocale() { - @Override - protected Void job(final Resources resource) { - loadStringResourcesInternal(res, RESOURCE_NAMES, resourcePackageName); - return null; - } - }; // Null means the current system locale. - job.runInLocale(res, - SubtypeLocaleUtils.NO_LANGUAGE.equals(locale.toString()) ? null : locale); + final String resourcePackageName = res.getResourcePackageName( + context.getApplicationInfo().labelRes); + setLocale(locale, res, resourcePackageName); } @UsedForTesting - void loadStringResourcesInternal(final Resources res, final String[] resourceNames, + public void setLocale(final Locale locale, final Resources res, final String resourcePackageName) { - for (final String resName : resourceNames) { - final int resId = res.getIdentifier(resName, "string", resourcePackageName); - mResourceNameToTextsMap.put(resName, res.getString(resId)); - } + mResources = res; + // Null means the current system locale. + mResourceLocale = SubtypeLocaleUtils.NO_LANGUAGE.equals(locale.toString()) ? null : locale; + mResourcePackageName = resourcePackageName; + mTextsTable = KeyboardTextsTable.getTextsTable(locale); } public String getText(final String name) { - final String text = mResourceNameToTextsMap.get(name); - return (text != null) ? text : KeyboardTextsTable.getText(name, mTextsTable); + return KeyboardTextsTable.getText(name, mTextsTable); } private static int searchTextNameEnd(final String text, final int start) { @@ -93,13 +86,14 @@ public final class KeyboardTextsSet { StringBuilder sb; do { level++; - if (level >= MAX_STRING_REFERENCE_INDIRECTION) { - throw new RuntimeException("Too many " + PREFIX_TEXT + "name indirection: " + text); + if (level >= MAX_REFERENCE_INDIRECTION) { + throw new RuntimeException("Too many " + PREFIX_TEXT + " or " + PREFIX_RESOURCE + + " reference indirection: " + text); } - final int prefixLen = PREFIX_TEXT.length(); + final int prefixLength = PREFIX_TEXT.length(); final int size = text.length(); - if (size < prefixLen) { + if (size < prefixLength) { break; } @@ -110,10 +104,12 @@ public final class KeyboardTextsSet { if (sb == null) { sb = new StringBuilder(text.substring(0, pos)); } - final int end = searchTextNameEnd(text, pos + prefixLen); - final String name = text.substring(pos + prefixLen, end); - sb.append(getText(name)); - pos = end - 1; + pos = expandReference(text, pos, PREFIX_TEXT, sb); + } else if (text.startsWith(PREFIX_RESOURCE, pos)) { + if (sb == null) { + sb = new StringBuilder(text.substring(0, pos)); + } + pos = expandReference(text, pos, PREFIX_RESOURCE, sb); } else if (c == BACKSLASH) { if (sb != null) { // Append both escape character and escaped character. @@ -132,18 +128,24 @@ public final class KeyboardTextsSet { return TextUtils.isEmpty(text) ? null : text; } - // These texts' name should be aligned with the @string/ in - // values*/strings-action-keys.xml. - static final String[] RESOURCE_NAMES = { - // Labels for action. - "label_go_key", - "label_send_key", - "label_next_key", - "label_done_key", - "label_search_key", - "label_previous_key", - // Other labels. - "label_pause_key", - "label_wait_key", - }; + private int expandReference(final String text, final int pos, final String prefix, + final StringBuilder sb) { + final int prefixLength = prefix.length(); + final int end = searchTextNameEnd(text, pos + prefixLength); + final String name = text.substring(pos + prefixLength, end); + if (prefix.equals(PREFIX_TEXT)) { + sb.append(getText(name)); + } else { // PREFIX_RESOURCE + final String resourcePackageName = mResourcePackageName; + final RunInLocale getTextJob = new RunInLocale() { + @Override + protected String job(final Resources res) { + final int resId = res.getIdentifier(name, "string", resourcePackageName); + return res.getString(resId); + } + }; + sb.append(getTextJob.runInLocale(mResources, mResourceLocale)); + } + return end - 1; + } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java index 3c33320ea..192011384 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -209,48 +209,56 @@ public final class KeyboardTextsTable { /* 123: 1 */ "morekeys_less_than", /* 124: 1 */ "morekeys_greater_than", /* 125: 1 */ "morekeys_exclamation", - /* 126: 0 */ "morekeys_currency_generic", - /* 127: 0 */ "morekeys_symbols_1", - /* 128: 0 */ "morekeys_symbols_2", - /* 129: 0 */ "morekeys_symbols_3", - /* 130: 0 */ "morekeys_symbols_4", - /* 131: 0 */ "morekeys_symbols_5", - /* 132: 0 */ "morekeys_symbols_6", - /* 133: 0 */ "morekeys_symbols_7", - /* 134: 0 */ "morekeys_symbols_8", - /* 135: 0 */ "morekeys_symbols_9", - /* 136: 0 */ "morekeys_symbols_0", - /* 137: 0 */ "morekeys_am_pm", - /* 138: 0 */ "keyspec_settings", - /* 139: 0 */ "keyspec_shortcut", - /* 140: 0 */ "keyspec_action_next", - /* 141: 0 */ "keyspec_action_previous", - /* 142: 0 */ "keylabel_to_more_symbol", - /* 143: 0 */ "keylabel_tablet_to_more_symbol", - /* 144: 0 */ "keylabel_to_phone_numeric", - /* 145: 0 */ "keylabel_to_phone_symbols", - /* 146: 0 */ "keylabel_time_am", - /* 147: 0 */ "keylabel_time_pm", - /* 148: 0 */ "keyspec_popular_domain", - /* 149: 0 */ "morekeys_popular_domain", - /* 150: 0 */ "keyspecs_left_parenthesis_more_keys", - /* 151: 0 */ "keyspecs_right_parenthesis_more_keys", - /* 152: 0 */ "single_laqm_raqm", - /* 153: 0 */ "single_raqm_laqm", - /* 154: 0 */ "double_laqm_raqm", - /* 155: 0 */ "double_raqm_laqm", - /* 156: 0 */ "single_lqm_rqm", - /* 157: 0 */ "single_9qm_lqm", - /* 158: 0 */ "single_9qm_rqm", - /* 159: 0 */ "single_rqm_9qm", - /* 160: 0 */ "double_lqm_rqm", - /* 161: 0 */ "double_9qm_lqm", - /* 162: 0 */ "double_9qm_rqm", - /* 163: 0 */ "double_rqm_9qm", - /* 164: 0 */ "morekeys_single_quote", - /* 165: 0 */ "morekeys_double_quote", - /* 166: 0 */ "morekeys_tablet_double_quote", - /* 167: 0 */ "keyspec_emoji_action_key", + /* 126: 1 */ "label_go_key", + /* 127: 1 */ "label_send_key", + /* 128: 1 */ "label_next_key", + /* 129: 1 */ "label_done_key", + /* 130: 1 */ "label_search_key", + /* 131: 1 */ "label_previous_key", + /* 132: 1 */ "label_pause_key", + /* 133: 1 */ "label_wait_key", + /* 134: 0 */ "morekeys_currency_generic", + /* 135: 0 */ "morekeys_symbols_1", + /* 136: 0 */ "morekeys_symbols_2", + /* 137: 0 */ "morekeys_symbols_3", + /* 138: 0 */ "morekeys_symbols_4", + /* 139: 0 */ "morekeys_symbols_5", + /* 140: 0 */ "morekeys_symbols_6", + /* 141: 0 */ "morekeys_symbols_7", + /* 142: 0 */ "morekeys_symbols_8", + /* 143: 0 */ "morekeys_symbols_9", + /* 144: 0 */ "morekeys_symbols_0", + /* 145: 0 */ "morekeys_am_pm", + /* 146: 0 */ "keyspec_settings", + /* 147: 0 */ "keyspec_shortcut", + /* 148: 0 */ "keyspec_action_next", + /* 149: 0 */ "keyspec_action_previous", + /* 150: 0 */ "keylabel_to_more_symbol", + /* 151: 0 */ "keylabel_tablet_to_more_symbol", + /* 152: 0 */ "keylabel_to_phone_numeric", + /* 153: 0 */ "keylabel_to_phone_symbols", + /* 154: 0 */ "keylabel_time_am", + /* 155: 0 */ "keylabel_time_pm", + /* 156: 0 */ "keyspec_popular_domain", + /* 157: 0 */ "morekeys_popular_domain", + /* 158: 0 */ "keyspecs_left_parenthesis_more_keys", + /* 159: 0 */ "keyspecs_right_parenthesis_more_keys", + /* 160: 0 */ "single_laqm_raqm", + /* 161: 0 */ "single_raqm_laqm", + /* 162: 0 */ "double_laqm_raqm", + /* 163: 0 */ "double_raqm_laqm", + /* 164: 0 */ "single_lqm_rqm", + /* 165: 0 */ "single_9qm_lqm", + /* 166: 0 */ "single_9qm_rqm", + /* 167: 0 */ "single_rqm_9qm", + /* 168: 0 */ "double_lqm_rqm", + /* 169: 0 */ "double_9qm_lqm", + /* 170: 0 */ "double_9qm_rqm", + /* 171: 0 */ "double_rqm_9qm", + /* 172: 0 */ "morekeys_single_quote", + /* 173: 0 */ "morekeys_double_quote", + /* 174: 0 */ "morekeys_tablet_double_quote", + /* 175: 0 */ "keyspec_emoji_action_key", }; private static final String EMPTY = ""; @@ -379,6 +387,14 @@ public final class KeyboardTextsTable { /* morekeys_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_right_double_angle_quote", // U+00A1: "¡" INVERTED EXCLAMATION MARK /* morekeys_exclamation */ "\u00A1", + /* label_go_key */ "!string/label_go_key", + /* label_send_key */ "!string/label_send_key", + /* label_next_key */ "!string/label_next_key", + /* label_done_key */ "!string/label_done_key", + /* label_search_key */ "!string/label_search_key", + /* label_previous_key */ "!string/label_previous_key", + /* label_pause_key */ "!string/label_pause_key", + /* label_wait_key */ "!string/label_wait_key", /* morekeys_currency_generic */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1", // U+00B9: "¹" SUPERSCRIPT ONE // U+00BD: "½" VULGAR FRACTION ONE HALF @@ -1885,6 +1901,24 @@ public final class KeyboardTextsTable { /* ~ morekeys_s */ // U+20B9: "₹" INDIAN RUPEE SIGN /* keyspec_currency */ "\u20B9", + /* morekeys_y ~ */ + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, + /* ~ morekeys_exclamation */ + /* label_go_key */ "Go", + /* label_send_key */ "Send", + /* label_next_key */ "Next", + /* label_done_key */ "Done", + /* label_search_key */ "Search", + /* label_previous_key */ "Prev", + /* label_pause_key */ "Pause", + /* label_wait_key */ "Wait", }; /* Locale hr: Croatian */ @@ -3952,7 +3986,7 @@ public final class KeyboardTextsTable { private static final Object[] LOCALES_AND_TEXTS = { // "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */ - "DEFAULT", TEXTS_DEFAULT, /* 168/168 DEFAULT */ + "DEFAULT", TEXTS_DEFAULT, /* 176/176 DEFAULT */ "af" , TEXTS_af, /* 7/ 13 Afrikaans */ "ar" , TEXTS_ar, /* 55/110 Arabic */ "az_AZ" , TEXTS_az_AZ, /* 11/ 18 Azerbaijani (Azerbaijan) */ @@ -3974,7 +4008,7 @@ public final class KeyboardTextsTable { "fr" , TEXTS_fr, /* 13/ 62 French */ "gl_ES" , TEXTS_gl_ES, /* 7/ 8 Gallegan (Spain) */ "hi" , TEXTS_hi, /* 23/ 53 Hindi */ - "hi_ZZ" , TEXTS_hi_ZZ, /* 1/ 12 Hindi (ZZ) */ + "hi_ZZ" , TEXTS_hi_ZZ, /* 9/134 Hindi (ZZ) */ "hr" , TEXTS_hr, /* 9/ 20 Croatian */ "hu" , TEXTS_hu, /* 9/ 20 Hungarian */ "hy_AM" , TEXTS_hy_AM, /* 9/126 Armenian (Armenia) */ diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 96a6510fc..5a7f7662c 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -167,7 +167,7 @@ public final class SubtypeLocaleUtils { return nameId == null ? UNKNOWN_KEYBOARD_LAYOUT : nameId; } - private static Locale getDisplayLocaleOfSubtypeLocale(final String localeString) { + public static Locale getDisplayLocaleOfSubtypeLocale(final String localeString) { if (NO_LANGUAGE.equals(localeString)) { return sResources.getConfiguration().locale; } diff --git a/tests/res/values/donottranslate.xml b/tests/res/values/donottranslate.xml index 263d0af24..f26947608 100644 --- a/tests/res/values/donottranslate.xml +++ b/tests/res/values/donottranslate.xml @@ -50,13 +50,15 @@ " \\abc , d\\ef , gh\\i " "ab\\\\,d\\\\\\,,g\\,i" " ab\\\\ , d\\\\\\, , g\\,i " - !text/multiple_chars - x,!text/multiple_chars,y - !text/indirect_string - infinite,!text/infinite_indirection,loop - !TEXT/MULTIPLE_CHARS - x,!TEXT/MULTIPLE_CHARS,y - !TEXT/UPPER_INDIRECT_STRING - infinite,!TEXT/INFINITE_INDIRECTION,loop + !string/multiple_chars + x,!string/multiple_chars,y + !string/indirect_string + infinite,!string/infinite_indirection,loop + !STRING/MULTIPLE_CHARS + x,!STRING/MULTIPLE_CHARS,y + !STRING/UPPER_INDIRECT_STRING + infinite,!STRING/INFINITE_INDIRECTION,loop !fixedColumnOrder!2,!text/keyspec_action_previous,!text/keyspec_action_next + ActionNext + ActionPrevious diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java index 17cee29b3..22c22a00a 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java @@ -25,6 +25,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyVisual; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -64,10 +65,11 @@ abstract class KeyboardLayoutSetActionLabelBase extends KeyboardLayoutSetTestsBa } protected static Locale getLabelLocale(final InputMethodSubtype subtype) { - if (subtype.getLocale().equals(SubtypeLocaleUtils.NO_LANGUAGE)) { + final String localeString = subtype.getLocale(); + if (localeString.equals(SubtypeLocaleUtils.NO_LANGUAGE)) { return null; } - return SubtypeLocaleUtils.getSubtypeLocale(subtype); + return LocaleUtils.constructLocaleFromString(localeString); } public void testActionUnspecified() { diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java index 07d47053a..36b9c9cfc 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java @@ -22,15 +22,40 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.keyboard.internal.KeyboardTextsSet; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; +import java.util.ArrayList; import java.util.Locale; @MediumTest public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActionLabelBase { + // Filter a subtype whose name should be displayed using {@link Locale#ROOT}, such like + // Hinglish (hi_ZZ) and Serbian-Latn (sr_ZZ). + static final SubtypeFilter SUBTYPE_FILTER_NAME_IN_BASE_LOCALE = new SubtypeFilter() { + @Override + public boolean accept(final InputMethodSubtype subtype) { + return Locale.ROOT.equals( + SubtypeLocaleUtils.getDisplayLocaleOfSubtypeLocale(subtype.getLocale())); + } + }; + + private ArrayList mSubtypesWhoseNameIsDisplayedInItsLocale; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mSubtypesWhoseNameIsDisplayedInItsLocale = getSubtypesFilteredBy(new SubtypeFilter() { + @Override + public boolean accept(final InputMethodSubtype subtype) { + return !SUBTYPE_FILTER_NAME_IN_BASE_LOCALE.accept(subtype); + } + }); + } + @Override protected int getKeyboardThemeForTests() { return KeyboardTheme.THEME_ID_KLP; @@ -38,7 +63,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio @Override public void testActionGo() { - for (final InputMethodSubtype subtype : getAllSubtypesList()) { + for (final InputMethodSubtype subtype : mSubtypesWhoseNameIsDisplayedInItsLocale) { final String tag = "go " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final ExpectedActionKey expectedKey = ExpectedActionKey.newLabelKey( R.string.label_go_key, getLabelLocale(subtype), getContext()); @@ -48,7 +73,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio @Override public void testActionSend() { - for (final InputMethodSubtype subtype : getAllSubtypesList()) { + for (final InputMethodSubtype subtype : mSubtypesWhoseNameIsDisplayedInItsLocale) { final String tag = "send " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final ExpectedActionKey expectedKey = ExpectedActionKey.newLabelKey( R.string.label_send_key, getLabelLocale(subtype), getContext()); @@ -58,7 +83,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio @Override public void testActionNext() { - for (final InputMethodSubtype subtype : getAllSubtypesList()) { + for (final InputMethodSubtype subtype : mSubtypesWhoseNameIsDisplayedInItsLocale) { final String tag = "next " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final ExpectedActionKey expectedKey = ExpectedActionKey.newLabelKey( R.string.label_next_key, getLabelLocale(subtype), getContext()); @@ -68,7 +93,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio @Override public void testActionDone() { - for (final InputMethodSubtype subtype : getAllSubtypesList()) { + for (final InputMethodSubtype subtype : mSubtypesWhoseNameIsDisplayedInItsLocale) { final String tag = "done " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final ExpectedActionKey expectedKey = ExpectedActionKey.newLabelKey( R.string.label_done_key, getLabelLocale(subtype), getContext()); @@ -78,7 +103,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio @Override public void testActionPrevious() { - for (final InputMethodSubtype subtype : getAllSubtypesList()) { + for (final InputMethodSubtype subtype : mSubtypesWhoseNameIsDisplayedInItsLocale) { final String tag = "previous " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final ExpectedActionKey expectedKey = ExpectedActionKey.newLabelKey( R.string.label_previous_key, getLabelLocale(subtype), getContext()); @@ -105,7 +130,7 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio // Working variable to simulate system locale changing. private Locale mSystemLocale = Locale.getDefault(); - private void doTestActionKeysInLocale(final InputMethodSubtype subtype, + private void doTestActionKeysInLocaleWithStringResources(final InputMethodSubtype subtype, final Locale labelLocale, final Locale systemLocale) { // Simulate system locale changing, see {@link SystemBroadcastReceiver}. if (!systemLocale.equals(mSystemLocale)) { @@ -144,10 +169,10 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio final InputMethodSubtype italian = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( Locale.ITALIAN.toString(), SubtypeLocaleUtils.QWERTY); // An action label should be displayed in subtype's locale regardless of the system locale. - doTestActionKeysInLocale(italian, Locale.ITALIAN, Locale.US); - doTestActionKeysInLocale(italian, Locale.ITALIAN, Locale.FRENCH); - doTestActionKeysInLocale(italian, Locale.ITALIAN, Locale.ITALIAN); - doTestActionKeysInLocale(italian, Locale.ITALIAN, Locale.JAPANESE); + doTestActionKeysInLocaleWithStringResources(italian, Locale.ITALIAN, Locale.US); + doTestActionKeysInLocaleWithStringResources(italian, Locale.ITALIAN, Locale.FRENCH); + doTestActionKeysInLocaleWithStringResources(italian, Locale.ITALIAN, Locale.ITALIAN); + doTestActionKeysInLocaleWithStringResources(italian, Locale.ITALIAN, Locale.JAPANESE); } public void testNoLanguageSubtypeActionLabel() { @@ -155,9 +180,58 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio final InputMethodSubtype noLanguage = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY); // An action label of no language keyboard should be displayed in the system locale. - doTestActionKeysInLocale(noLanguage, Locale.US, Locale.US); - doTestActionKeysInLocale(noLanguage, Locale.FRENCH, Locale.FRENCH); - doTestActionKeysInLocale(noLanguage, Locale.ITALIAN, Locale.ITALIAN); - doTestActionKeysInLocale(noLanguage, Locale.JAPANESE, Locale.JAPANESE); + doTestActionKeysInLocaleWithStringResources(noLanguage, Locale.US, Locale.US); + doTestActionKeysInLocaleWithStringResources(noLanguage, Locale.FRENCH, Locale.FRENCH); + doTestActionKeysInLocaleWithStringResources(noLanguage, Locale.ITALIAN, Locale.ITALIAN); + doTestActionKeysInLocaleWithStringResources(noLanguage, Locale.JAPANESE, Locale.JAPANESE); + } + + private void doTestActionKeysInLocaleWithKeyboardTextsSet(final InputMethodSubtype subtype, + final Locale labelLocale, final Locale systemLocale) { + // Simulate system locale changing, see {@link SystemBroadcastReceiver}. + if (!systemLocale.equals(mSystemLocale)) { + KeyboardLayoutSet.onSystemLocaleChanged(); + mSystemLocale = systemLocale; + } + final KeyboardTextsSet textsSet = new KeyboardTextsSet(); + textsSet.setLocale(labelLocale, getContext()); + final ExpectedActionKey enterKey = ExpectedActionKey.newIconKey( + KeyboardIconsSet.NAME_ENTER_KEY); + final ExpectedActionKey goKey = ExpectedActionKey.newLabelKey( + textsSet.getText("label_go_key")); + final ExpectedActionKey searchKey = ExpectedActionKey.newIconKey( + KeyboardIconsSet.NAME_SEARCH_KEY); + final ExpectedActionKey sendKey = ExpectedActionKey.newLabelKey( + textsSet.getText("label_send_key")); + final ExpectedActionKey nextKey = ExpectedActionKey.newLabelKey( + textsSet.getText("label_next_key")); + final ExpectedActionKey doneKey = ExpectedActionKey.newLabelKey( + textsSet.getText("label_done_key")); + final ExpectedActionKey previousKey = ExpectedActionKey.newLabelKey( + textsSet.getText("label_previous_key")); + final String tag = "label=hi_ZZ system=" + systemLocale + + " " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + final RunInLocale job = new RunInLocale() { + @Override + public Void job(final Resources res) { + doTestActionKeys(subtype, tag, enterKey, enterKey, goKey, searchKey, sendKey, + nextKey, doneKey, previousKey); + return null; + } + }; + job.runInLocale(getContext().getResources(), systemLocale); + } + + public void testHinglishActionLabel() { + final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); + final Locale hi_ZZ = new Locale("hi", "ZZ"); + final InputMethodSubtype hinglish = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( + hi_ZZ.toString(), SubtypeLocaleUtils.QWERTY); + // An action label should be displayed in subtype's locale regardless of the system locale. + doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, hi_ZZ); + doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.US); + doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.FRENCH); + doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.ITALIAN); + doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.JAPANESE); } } diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java index 922d2a8c8..8f4648c52 100644 --- a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java @@ -16,52 +16,33 @@ package com.android.inputmethod.keyboard.internal; -import android.app.Instrumentation; import android.content.Context; import android.content.res.Resources; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.R; -import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; -@MediumTest -public class MoreKeySpecSplitTests extends InstrumentationTestCase { +@SmallTest +public class MoreKeySpecSplitTests extends AndroidTestCase { private static final Locale TEST_LOCALE = Locale.ENGLISH; - final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); + private final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); @Override protected void setUp() throws Exception { super.setUp(); - final Instrumentation instrumentation = getInstrumentation(); - final Context targetContext = instrumentation.getTargetContext(); - mTextsSet.setLocale(TEST_LOCALE, targetContext); - final String[] testResourceNames = getAllResourceIdNames( - com.android.inputmethod.latin.tests.R.string.class); - final Context testContext = instrumentation.getContext(); - final Resources testRes = testContext.getResources(); - final String testResPackageName = testRes.getResourcePackageName( - // This dummy raw resource is needed to be able to load string resources from a test - // APK successfully. - com.android.inputmethod.latin.tests.R.raw.dummy_resource_for_testing); - mTextsSet.loadStringResourcesInternal(testRes, testResourceNames, testResPackageName); + final Context targetContext = getContext(); + final Resources targetRes = targetContext.getResources(); + final String targetPackageName = targetRes.getResourcePackageName( + R.string.english_ime_name); + mTextsSet.setLocale(TEST_LOCALE, targetRes, targetPackageName); } - private static String[] getAllResourceIdNames(final Class resourceIdClass) { - final ArrayList names = new ArrayList<>(); - for (final Field field : resourceIdClass.getFields()) { - if (field.getType() == int.class) { - names.add(field.getName()); - } - } - return names.toArray(new String[names.size()]); - } - - private static void assertArrayEquals(final String message, final T[] expected, - final T[] actual) { + static void assertArrayEquals(final String message, final T[] expected, final T[] actual) { if (expected == actual) { return; } @@ -109,14 +90,6 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase { private static final String SURROGATE1 = PAIR1 + PAIR2; private static final String SURROGATE2 = PAIR1 + PAIR2 + PAIR3; - public void testResolveNullText() { - assertNull("resolve null", mTextsSet.resolveTextReference(null)); - } - - public void testResolveEmptyText() { - assertNull("resolve empty text", mTextsSet.resolveTextReference("!text/empty_string")); - } - public void testSplitZero() { assertTextArray("Empty string", ""); assertTextArray("Empty entry", ","); @@ -224,132 +197,14 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase { "\\!", "\\!TEXT/EMPTY_STRING"); } - public void testSplitResourceError() { - assertError("Incomplete resource name", "!text/", "!text/"); - assertError("Non existing resource", "!text/non_existing"); + public void testSplitTextReferenceError() { + assertError("Incomplete text name", "!text/", "!text/"); + assertError("Non existing text", "!text/non_existing"); } - public void testSplitResourceZero() { - assertTextArray("Empty string", - "!text/empty_string"); - } - - public void testSplitResourceSingle() { - assertTextArray("Single char", - "!text/single_char", "a"); - assertTextArray("Space", - "!text/space", " "); - assertTextArray("Single label", - "!text/single_label", "abc"); - assertTextArray("Spaces", - "!text/spaces", " "); - assertTextArray("Spaces in label", - "!text/spaces_in_label", "a b c"); - assertTextArray("Spaces at beginning of label", - "!text/spaces_at_beginning_of_label", " abc"); - assertTextArray("Spaces at end of label", - "!text/spaces_at_end_of_label", "abc "); - assertTextArray("label surrounded by spaces", - "!text/label_surrounded_by_spaces", " abc "); - - assertTextArray("Escape and single char", - "\\\\!text/single_char", "\\\\a"); - } - - public void testSplitResourceSingleEscaped() { - assertTextArray("Escaped char", - "!text/escaped_char", "\\a"); - assertTextArray("Escaped comma", - "!text/escaped_comma", "\\,"); - assertTextArray("Escaped comma escape", - "!text/escaped_comma_escape", "a\\,\\"); - assertTextArray("Escaped escape", - "!text/escaped_escape", "\\\\"); - assertTextArray("Escaped label", - "!text/escaped_label", "a\\bc"); - assertTextArray("Escaped label at beginning", - "!text/escaped_label_at_beginning", "\\abc"); - assertTextArray("Escaped label at end", - "!text/escaped_label_at_end", "abc\\"); - assertTextArray("Escaped label with comma", - "!text/escaped_label_with_comma", "a\\,c"); - assertTextArray("Escaped label with comma at beginning", - "!text/escaped_label_with_comma_at_beginning", "\\,bc"); - assertTextArray("Escaped label with comma at end", - "!text/escaped_label_with_comma_at_end", "ab\\,"); - assertTextArray("Escaped label with successive", - "!text/escaped_label_with_successive", "\\,\\\\bc"); - assertTextArray("Escaped label with escape", - "!text/escaped_label_with_escape", "a\\\\c"); - } - - public void testSplitResourceMulti() { - assertTextArray("Multiple chars", - "!text/multiple_chars", "a", "b", "c"); - assertTextArray("Multiple chars surrounded by spaces", - "!text/multiple_chars_surrounded_by_spaces", - " a ", " b ", " c "); - assertTextArray("Multiple labels", - "!text/multiple_labels", "abc", "def", "ghi"); - assertTextArray("Multiple labels surrounded by spaces", - "!text/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi "); - } - - public void testSplitResourcetMultiEscaped() { - assertTextArray("Multiple chars with comma", - "!text/multiple_chars_with_comma", - "a", "\\,", "c"); - assertTextArray("Multiple chars with comma surrounded by spaces", - "!text/multiple_chars_with_comma_surrounded_by_spaces", - " a ", " \\, ", " c "); - assertTextArray("Multiple labels with escape", - "!text/multiple_labels_with_escape", - "\\abc", "d\\ef", "gh\\i"); - assertTextArray("Multiple labels with escape surrounded by spaces", - "!text/multiple_labels_with_escape_surrounded_by_spaces", - " \\abc ", " d\\ef ", " gh\\i "); - assertTextArray("Multiple labels with comma and escape", - "!text/multiple_labels_with_comma_and_escape", - "ab\\\\", "d\\\\\\,", "g\\,i"); - assertTextArray("Multiple labels with comma and escape surrounded by spaces", - "!text/multiple_labels_with_comma_and_escape_surrounded_by_spaces", - " ab\\\\ ", " d\\\\\\, ", " g\\,i "); - } - - public void testSplitMultipleResources() { - assertTextArray("Literals and resources", - "1,!text/multiple_chars,z", "1", "a", "b", "c", "z"); - assertTextArray("Literals and resources and escape at end", - "\\1,!text/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\"); - assertTextArray("Multiple single resource chars and labels", - "!text/single_char,!text/single_label,!text/escaped_comma", - "a", "abc", "\\,"); - assertTextArray("Multiple single resource chars and labels 2", - "!text/single_char,!text/single_label,!text/escaped_comma_escape", - "a", "abc", "a\\,\\"); - assertTextArray("Multiple multiple resource chars and labels", - "!text/multiple_chars,!text/multiple_labels,!text/multiple_chars_with_comma", - "a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c"); - assertTextArray("Concatenated resources", - "!text/multiple_chars!text/multiple_labels!text/multiple_chars_with_comma", - "a", "b", "cabc", "def", "ghia", "\\,", "c"); - assertTextArray("Concatenated resource and literal", - "abc!text/multiple_labels", - "abcabc", "def", "ghi"); - } - - public void testSplitIndirectReference() { - assertTextArray("Indirect", - "!text/indirect_string", "a", "b", "c"); - assertTextArray("Indirect with literal", - "1,!text/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2"); - assertTextArray("Indirect2", - "!text/indirect2_string", "a", "b", "c"); - } - - public void testSplitInfiniteIndirectReference() { - assertError("Infinite indirection", - "1,!text/infinite_indirection,2", "1", "infinite", "", "loop", "2"); + public void testSplitEmptyTextReference() { + // Note that morekeys_q of English locale is empty. + assertTextArray("Empty string", "!text/morekeys_q"); } public void testLabelReferece() { @@ -360,12 +215,6 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase { assertTextArray("Settings as more key", "!text/keyspec_settings", "!icon/settings_key|!code/key_settings"); - - assertTextArray("Indirect naviagte actions as more key", - "!text/keyspec_indirect_navigate_actions", - "!fixedColumnOrder!2", - "!hasLabels!", "Prev|!code/key_action_previous", - "!hasLabels!", "Next|!code/key_action_next"); } public void testUselessUpperCaseSpecifier() { @@ -394,14 +243,6 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase { assertTextArray("INDIRECT2", "!TEXT/INDIRECT2_STRING", "!TEXT/INDIRECT2_STRING"); - assertTextArray("Upper indirect", - "!text/upper_indirect_string", "!TEXT/MULTIPLE_CHARS"); - assertTextArray("Upper indirect with literal", - "1,!text/upper_indirect_string_with_literal,2", - "1", "x", "!TEXT/MULTIPLE_CHARS", "y", "2"); - assertTextArray("Upper indirect2", - "!text/upper_indirect2_string", "!TEXT/UPPER_INDIRECT_STRING"); - assertTextArray("UPPER INDIRECT", "!TEXT/upper_INDIRECT_STRING", "!TEXT/upper_INDIRECT_STRING"); assertTextArray("Upper INDIRECT with literal", @@ -413,9 +254,6 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase { assertTextArray("INFINITE INDIRECTION", "1,!TEXT/INFINITE_INDIRECTION,2", "1", "!TEXT/INFINITE_INDIRECTION", "2"); - assertTextArray("Upper infinite indirection", - "1,!text/upper_infinite_indirection,2", - "1", "infinite", "!TEXT/INFINITE_INDIRECTION", "loop", "2"); assertTextArray("Upper INFINITE INDIRECTION", "1,!TEXT/UPPER_INFINITE_INDIRECTION,2", "1", "!TEXT/UPPER_INFINITE_INDIRECTION", "2"); diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecStringReferenceTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecStringReferenceTests.java new file mode 100644 index 000000000..e06ecaedf --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecStringReferenceTests.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.internal; + +import android.app.Instrumentation; +import android.content.Context; +import android.content.res.Resources; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.inputmethod.latin.tests.R; + +import java.util.Locale; + +@SmallTest +public class MoreKeySpecStringReferenceTests extends InstrumentationTestCase { + private static final Locale TEST_LOCALE = Locale.ENGLISH; + private final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); + + @Override + protected void setUp() throws Exception { + super.setUp(); + + final Instrumentation instrumentation = getInstrumentation(); + final Context testContext = instrumentation.getContext(); + final Resources testRes = testContext.getResources(); + final String testPackageName = testRes.getResourcePackageName(R.string.empty_string); + mTextsSet.setLocale(TEST_LOCALE, testRes, testPackageName); + } + + private void assertTextArray(final String message, final String value, + final String ... expectedArray) { + final String resolvedActual = mTextsSet.resolveTextReference(value); + final String[] actual = MoreKeySpec.splitKeySpecs(resolvedActual); + final String[] expected = (expectedArray.length == 0) ? null : expectedArray; + MoreKeySpecSplitTests.assertArrayEquals(message, expected, actual); + } + + private void assertError(final String message, final String value, final String ... expected) { + try { + assertTextArray(message, value, expected); + fail(message); + } catch (Exception pcpe) { + // success. + } + } + + public void testResolveNullText() { + assertEquals("resolve null", + mTextsSet.resolveTextReference(null), null); + } + + public void testResolveEmptyText() { + assertEquals("resolve empty text", + mTextsSet.resolveTextReference("!string/empty_string"), null); + } + + public void testSplitSingleEscaped() { + assertTextArray("Escaped !string", "\\!string", + "\\!string"); + assertTextArray("Escaped !string/", "\\!string/", + "\\!string/"); + assertTextArray("Escaped !STRING/", "\\!STRING/", + "\\!STRING/"); + assertTextArray("Escaped !string/name", "\\!string/empty_string", + "\\!string/empty_string"); + assertTextArray("Escaped !STRING/NAME", "\\!STRING/EMPTY_STRING", + "\\!STRING/EMPTY_STRING"); + } + + public void testSplitMultiEscaped() { + assertTextArray("Multiple escaped !string", "\\!,\\!string/empty_string", + "\\!", "\\!string/empty_string"); + assertTextArray("Multiple escaped !STRING", "\\!,\\!STRING/EMPTY_STRING", + "\\!", "\\!STRING/EMPTY_STRING"); + } + + public void testSplitStringReferenceError() { + assertError("Incomplete resource name", "!string/", "!string/"); + assertError("Non existing resource", "!string/non_existing"); + } + + public void testSplitEmptyStringReference() { + assertTextArray("Empty string", "!string/empty_string"); + } + + public void testSplitResourceSingle() { + assertTextArray("Single char", "!string/single_char", + "a"); + assertTextArray("Space", "!string/space", + " "); + assertTextArray("Single label", "!string/single_label", + "abc"); + assertTextArray("Spaces", "!string/spaces", + " "); + assertTextArray("Spaces in label", "!string/spaces_in_label", + "a b c"); + assertTextArray("Spaces at beginning of label", "!string/spaces_at_beginning_of_label", + " abc"); + assertTextArray("Spaces at end of label", "!string/spaces_at_end_of_label", + "abc "); + assertTextArray("label surrounded by spaces", "!string/label_surrounded_by_spaces", + " abc "); + assertTextArray("Escape and single char", "\\\\!string/single_char", + "\\\\a"); + } + + public void testSplitResourceSingleEscaped() { + assertTextArray("Escaped char", + "!string/escaped_char", "\\a"); + assertTextArray("Escaped comma", + "!string/escaped_comma", "\\,"); + assertTextArray("Escaped comma escape", + "!string/escaped_comma_escape", "a\\,\\"); + assertTextArray("Escaped escape", + "!string/escaped_escape", "\\\\"); + assertTextArray("Escaped label", + "!string/escaped_label", "a\\bc"); + assertTextArray("Escaped label at beginning", + "!string/escaped_label_at_beginning", "\\abc"); + assertTextArray("Escaped label at end", + "!string/escaped_label_at_end", "abc\\"); + assertTextArray("Escaped label with comma", + "!string/escaped_label_with_comma", "a\\,c"); + assertTextArray("Escaped label with comma at beginning", + "!string/escaped_label_with_comma_at_beginning", "\\,bc"); + assertTextArray("Escaped label with comma at end", + "!string/escaped_label_with_comma_at_end", "ab\\,"); + assertTextArray("Escaped label with successive", + "!string/escaped_label_with_successive", "\\,\\\\bc"); + assertTextArray("Escaped label with escape", + "!string/escaped_label_with_escape", "a\\\\c"); + } + + public void testSplitResourceMulti() { + assertTextArray("Multiple chars", + "!string/multiple_chars", "a", "b", "c"); + assertTextArray("Multiple chars surrounded by spaces", + "!string/multiple_chars_surrounded_by_spaces", + " a ", " b ", " c "); + assertTextArray("Multiple labels", + "!string/multiple_labels", "abc", "def", "ghi"); + assertTextArray("Multiple labels surrounded by spaces", + "!string/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi "); + } + + public void testSplitResourcetMultiEscaped() { + assertTextArray("Multiple chars with comma", + "!string/multiple_chars_with_comma", + "a", "\\,", "c"); + assertTextArray("Multiple chars with comma surrounded by spaces", + "!string/multiple_chars_with_comma_surrounded_by_spaces", + " a ", " \\, ", " c "); + assertTextArray("Multiple labels with escape", + "!string/multiple_labels_with_escape", + "\\abc", "d\\ef", "gh\\i"); + assertTextArray("Multiple labels with escape surrounded by spaces", + "!string/multiple_labels_with_escape_surrounded_by_spaces", + " \\abc ", " d\\ef ", " gh\\i "); + assertTextArray("Multiple labels with comma and escape", + "!string/multiple_labels_with_comma_and_escape", + "ab\\\\", "d\\\\\\,", "g\\,i"); + assertTextArray("Multiple labels with comma and escape surrounded by spaces", + "!string/multiple_labels_with_comma_and_escape_surrounded_by_spaces", + " ab\\\\ ", " d\\\\\\, ", " g\\,i "); + } + + public void testSplitMultipleResources() { + assertTextArray("Literals and resources", + "1,!string/multiple_chars,z", + "1", "a", "b", "c", "z"); + assertTextArray("Literals and resources and escape at end", + "\\1,!string/multiple_chars,z\\", + "\\1", "a", "b", "c", "z\\"); + assertTextArray("Multiple single resource chars and labels", + "!string/single_char,!string/single_label,!string/escaped_comma", + "a", "abc", "\\,"); + assertTextArray("Multiple single resource chars and labels 2", + "!string/single_char,!string/single_label,!string/escaped_comma_escape", + "a", "abc", "a\\,\\"); + assertTextArray("Multiple multiple resource chars and labels", + "!string/multiple_chars,!string/multiple_labels,!string/multiple_chars_with_comma", + "a", "b", "c", "abc", "def", "ghi", "a", "\\,", "c"); + assertTextArray("Concatenated resources", + "!string/multiple_chars!string/multiple_labels!string/multiple_chars_with_comma", + "a", "b", "cabc", "def", "ghia", "\\,", "c"); + assertTextArray("Concatenated resource and literal", + "abc!string/multiple_labels", + "abcabc", "def", "ghi"); + } + + public void testSplitIndirectReference() { + assertTextArray("Indirect", + "!string/indirect_string", "a", "b", "c"); + assertTextArray("Indirect with literal", + "1,!string/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2"); + assertTextArray("Indirect2", + "!string/indirect2_string", "a", "b", "c"); + } + + public void testSplitInfiniteIndirectReference() { + assertError("Infinite indirection", + "1,!string/infinite_indirection,2", "1", "infinite", "", "loop", "2"); + } + + public void testLabelReferece() { + assertTextArray("Indirect naviagte actions as more key", + "!string/keyspec_indirect_navigate_actions", + "!fixedColumnOrder!2", + "!hasLabels!", "ActionPrevious|!code/key_action_previous", + "!hasLabels!", "ActionNext|!code/key_action_next"); + } + + public void testUselessUpperCaseSpecifier() { + assertTextArray("EMPTY STRING", + "!STRING/EMPTY_STRING", "!STRING/EMPTY_STRING"); + + assertTextArray("SINGLE CHAR", + "!STRING/SINGLE_CHAR", "!STRING/SINGLE_CHAR"); + assertTextArray("Escape and SINGLE CHAR", + "\\\\!STRING/SINGLE_CHAR", "\\\\!STRING/SINGLE_CHAR"); + + assertTextArray("MULTIPLE CHARS", + "!STRING/MULTIPLE_CHARS", "!STRING/MULTIPLE_CHARS"); + + assertTextArray("Literals and RESOURCES", + "1,!STRING/MULTIPLE_CHARS,z", "1", "!STRING/MULTIPLE_CHARS", "z"); + assertTextArray("Multiple single RESOURCE chars and LABELS 2", + "!STRING/SINGLE_CHAR,!STRING/SINGLE_LABEL,!STRING/ESCAPED_COMMA_ESCAPE", + "!STRING/SINGLE_CHAR", "!STRING/SINGLE_LABEL", "!STRING/ESCAPED_COMMA_ESCAPE"); + + assertTextArray("INDIRECT", + "!STRING/INDIRECT_STRING", "!STRING/INDIRECT_STRING"); + assertTextArray("INDIRECT with literal", + "1,!STRING/INDIRECT_STRING_WITH_LITERAL,2", + "1", "!STRING/INDIRECT_STRING_WITH_LITERAL", "2"); + assertTextArray("INDIRECT2", + "!STRING/INDIRECT2_STRING", "!STRING/INDIRECT2_STRING"); + + assertTextArray("Upper indirect", + "!string/upper_indirect_string", "!STRING/MULTIPLE_CHARS"); + assertTextArray("Upper indirect with literal", + "1,!string/upper_indirect_string_with_literal,2", + "1", "x", "!STRING/MULTIPLE_CHARS", "y", "2"); + assertTextArray("Upper indirect2", + "!string/upper_indirect2_string", "!STRING/UPPER_INDIRECT_STRING"); + + assertTextArray("UPPER INDIRECT", + "!STRING/upper_INDIRECT_STRING", "!STRING/upper_INDIRECT_STRING"); + assertTextArray("Upper INDIRECT with literal", + "1,!STRING/upper_INDIRECT_STRING_WITH_LITERAL,2", + "1", "!STRING/upper_INDIRECT_STRING_WITH_LITERAL", "2"); + assertTextArray("Upper INDIRECT2", + "!STRING/upper_INDIRECT2_STRING", "!STRING/upper_INDIRECT2_STRING"); + + assertTextArray("INFINITE INDIRECTION", + "1,!STRING/INFINITE_INDIRECTION,2", "1", "!STRING/INFINITE_INDIRECTION", "2"); + + assertTextArray("Upper infinite indirection", + "1,!string/upper_infinite_indirection,2", + "1", "infinite", "!STRING/INFINITE_INDIRECTION", "loop", "2"); + assertTextArray("Upper INFINITE INDIRECTION", + "1,!STRING/UPPER_INFINITE_INDIRECTION,2", + "1", "!STRING/UPPER_INFINITE_INDIRECTION", "2"); + + assertTextArray("INDIRECT NAVIGATE ACTIONS AS MORE KEY", + "!STRING/INDIRECT_NAVIGATE_ACTIONS_AS_MORE_KEY", + "!STRING/INDIRECT_NAVIGATE_ACTIONS_AS_MORE_KEY"); + } +} diff --git a/tools/make-keyboard-text/res/values-hi-rZZ/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-hi-rZZ/donottranslate-more-keys.xml index 068639d77..50834e0fc 100644 --- a/tools/make-keyboard-text/res/values-hi-rZZ/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-hi-rZZ/donottranslate-more-keys.xml @@ -20,4 +20,12 @@ + Go + Send + Next + Done + Search + Prev + Pause + Wait diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml index c4a1b889e..b6da7d13d 100644 --- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml @@ -259,4 +259,12 @@ !fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes !fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes !icon/emoji_action_key|!code/key_emoji + !string/label_go_key + !string/label_send_key + !string/label_next_key + !string/label_done_key + !string/label_search_key + !string/label_previous_key + !string/label_pause_key + !string/label_wait_key