Merge "change ResearchLoggerTests to check file"
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index c5ecca2..a0bef12 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Matig"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressief"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Baie aggressief"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Volgende woordvoorstelle"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Gebruik vorige woord om voorstelle te verbeter"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Volgende woordvoorspelling"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Gebruik vorige woord ook vir voorspelling"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gestoor"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Gaan"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Sleutelbordtema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engels (VK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Geen taal (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Bruikbaarheidstudie-modus"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Sleuteldruk se vibrasie-tydsduurinstellings"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Sleuteldruk se klankvolume-instellings"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 3450bec..2d898aa 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"መጠነኛ"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"ኃይለኛ"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"በጣም ቁጡ"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"የቀጣይ ቃል አስተያየቶች"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"ምክሮችን ለማሻሻል ቀዳሚ ቃል ተጠቀም"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"የቀጣይ ቃል ግምት"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"ለትንበያ የቀደመ ቃል እንዲሁ ተጠቀም"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ተቀምጧል"</string>
     <string name="label_go_key" msgid="1635148082137219148">"ሂድ"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"የቁልፍ ሰሌዳ ገጽታ"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"እንግሊዘኛ (የታላቋ ብሪታንያ)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"እንግሊዘኛ (ዩ.ኤስ)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"ቋንቋ አልባ (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"የተገልጋይነት ጥናት ሁነታ"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"ቁልፍ ተጫን በቅንጅቶች ወቅት ንዝረት"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"ቁልፍ ተጫን የድምጽ መጠን ቅንጅቶች"</string>
diff --git a/java/res/values-ar/keycodes.xml b/java/res/values-ar/keycodes.xml
deleted file mode 100644
index 1f65a7c..0000000
--- a/java/res/values-ar/keycodes.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+0029: ")" RIGHT PARENTHESIS -->
-    <integer name="keycode_for_left_parenthesis">0x0029</integer>
-    <!-- U+0028: "(" LEFT PARENTHESIS -->
-    <integer name="keycode_for_right_parenthesis">0x0028</integer>
-    <!-- U+003E: ">" GREATER-THAN SIGN -->
-    <integer name="keycode_for_less_than">0x003E</integer>
-    <!-- U+003C: "<" LESS-THAN SIGN -->
-    <integer name="keycode_for_greater_than">0x003C</integer>
-    <!-- U+005D: "]" RIGHT SQUARE BRACKET -->
-    <integer name="keycode_for_left_square_bracket">0x005D</integer>
-    <!-- U+005B: "[" LEFT SQUARE BRACKET -->
-    <integer name="keycode_for_right_square_bracket">0x005B</integer>
-    <!-- U+007D: "}" RIGHT CURLY BRACKET -->
-    <integer name="keycode_for_left_curly_bracket">0x007D</integer>
-    <!-- U+007B: "{" LEFT CURLY BRACKET -->
-    <integer name="keycode_for_right_curly_bracket">0x007B</integer>
-</resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 76a0778..d07a65b 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"معتدل"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"حاد"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"شديد الصرامة"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"اقتراحات الكلمات التالية"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"استخدام الكلمة السابقة لتحسين الاقتراحات"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"التنبؤ بالكلمات التالي"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"استخدام الكلمة السابقة أيضًا للتنبؤ"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string>
     <string name="label_go_key" msgid="1635148082137219148">"تنفيذ"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"مظهر لوحة المفاتيح"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"الإنجليزية (المملكة المتحدة)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"الإنجليزية (الولايات المتحدة)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"بدون لغة (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"وضع سهولة الاستخدام"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"إعدادات مدة اهتزاز الضغط على المفاتيح"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"إعدادات مستوى صوت الضغط على المفاتيح"</string>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
index bcf4152..7a2ce94 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Сціплы"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Агрэсіўны"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Вельмі агрэсіўны"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Падказкi для наступнага слова"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Выкарыстаць папярэдняе слова, каб палепшыць прапановы"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Падказка наступнага слова"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Выкарыстанне папярэдняга слова для падказак"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Захаваныя"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Пачаць"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Тэма клавіятуры"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Англійская (ЗК)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Англійская (ЗША)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Мова не выбрана (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Рэжым даследвання выкарыстальнасці"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Налады працягласцi вiбрацыi пры нацiску"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Налады гучнасцi пры нацiску"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index a2395d9..17073d2 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mírné"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivní"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Velmi agresivní"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Návrhy dalšího slova"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Použít předchozí slovo ke zlepšení návrhů"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Návrh dalšího slova"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Použít předchozí slovo také pro odhad"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Přejít"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Motiv klávesnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"angličtina (Spojené království)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"angličtina (USA)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Žádný jazyk (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim studie použitelnosti"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Nastavení trvání vibrace při stisku klávesy"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Nastavení hlasitosti zvuku při stisknutí klávesy"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index f4e617c..cd52660 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderat"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressiv"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Meget aggressiv"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Forslag til næste ord"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Brug forrige ord til at forbedre forslag"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Forudsigelse af næste ord"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Brug også tidligere ord til forudsigelse"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Gå"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturtema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannien)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ingen sprog (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tilstand for brugsstudie"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Indstillinger for varighed af vibration ved tastetryk"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Indstillinger for lydstyrke ved tastetryk"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index af2833e..ef86365 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressive"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Very aggressive"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Next word suggestions"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Use previous word to improve suggestion"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Next word prediction"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Use previous word also for prediction"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Go"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Keyboard theme"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"English (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"English (US)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"No language (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Usability study mode"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Key-press vibration duration settings"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Key-press sound volume settings"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 9115051..75b1fb4 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Muy agresivo"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sugerencias para la palabra siguiente"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Utiliza la palabra anterior para mejorar las sugerencias."</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Predicción de la palabra siguiente"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Usar la palabra anterior también para predicción."</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema del teclado"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inglés (Reino Unido)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inglés (EE.UU.)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ningún idioma (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudio de usabilidad"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Configuración de la duración de vibraciones al presionar las teclas"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Configuración del volumen de sonio al presionar las teclas"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 470a115..222cd53 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Parcial"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Muy agresiva"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sugerencias de la siguiente palabra"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Usar palabra anterior para mejorar las sugerencias"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Predicción de la siguiente palabra"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Utilizar también la palabra anterior para realizar la predicción"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema de teclado"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"inglés (Reino Unido)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"inglés (EE.UU.)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ningún idioma (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudio de usabilidad"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Ajustes de duración de vibración al pulsar tecla"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volumen de sonido al pulsar tecla"</string>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
index 8835917..cb21b4c 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mõõdukas"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressiivne"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Väga agressiivne"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Järgmise sõna soovitused"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Kasuta soovituste täiustamiseks eelmist sõna"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Järgmise sõna ennustus"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Kasuta ennustuseks ka eelmist sõna"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : salvestatud"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Mine"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatuuri teema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inglise (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inglise (USA)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Keel puudub (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kasutatavuse uurimisrežiim"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Klahvivajutuse vibratsiooni kestuse seaded"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Klahvivajutuse helitugevuse seaded"</string>
diff --git a/java/res/values-fa/keycodes.xml b/java/res/values-fa/keycodes.xml
deleted file mode 100644
index 1f65a7c..0000000
--- a/java/res/values-fa/keycodes.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+0029: ")" RIGHT PARENTHESIS -->
-    <integer name="keycode_for_left_parenthesis">0x0029</integer>
-    <!-- U+0028: "(" LEFT PARENTHESIS -->
-    <integer name="keycode_for_right_parenthesis">0x0028</integer>
-    <!-- U+003E: ">" GREATER-THAN SIGN -->
-    <integer name="keycode_for_less_than">0x003E</integer>
-    <!-- U+003C: "<" LESS-THAN SIGN -->
-    <integer name="keycode_for_greater_than">0x003C</integer>
-    <!-- U+005D: "]" RIGHT SQUARE BRACKET -->
-    <integer name="keycode_for_left_square_bracket">0x005D</integer>
-    <!-- U+005B: "[" LEFT SQUARE BRACKET -->
-    <integer name="keycode_for_right_square_bracket">0x005B</integer>
-    <!-- U+007D: "}" RIGHT CURLY BRACKET -->
-    <integer name="keycode_for_left_curly_bracket">0x007D</integer>
-    <!-- U+007B: "{" LEFT CURLY BRACKET -->
-    <integer name="keycode_for_right_curly_bracket">0x007B</integer>
-</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 6951ab4..5a6302f 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"متوسط"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"فعال"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"بسیار پرخاشگرانه"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"پیشنهادات کلمه بعدی"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"برای بهبود پیشنهاد از کلمه قبلی استفاده شود"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"پیش بینی کلمه بعدی"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"استفاده از کلمه قبلی برای پیش بینی"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string>
     <string name="label_go_key" msgid="1635148082137219148">"برو"</string>
@@ -125,8 +122,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"طرح زمینه صفحه کلید"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"انگیسی (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"انگیسی (US)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"هیچ کدام از زبانها (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"حالت بررسی قابلیت استفاده"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"تنظیمات مدت زمان لرزش فشار کلید"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"تنظیمات میزان صدای فشار کلید"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index bf018c1..96aadfb 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Simple"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Proactive"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Très exigeante"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Suggestions pour le mot suivant"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Améliorer les suggestions grâce au mot précédent"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Prédiction du mot suivant"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Utiliser le mot précédent pour la prédiction"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Thème du clavier"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Anglais (Royaume-Uni)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Anglais (États-Unis)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Pas de langue (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'étude de l\'utilisabilité"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Durée de vibration à chaque pression"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volume sonore à chaque pression"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index feb3b5f..093b22e 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Skromno"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivno"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Vrlo agresivno"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Prijedlozi za sljedeću riječ"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Upotrijebi prethodnu riječ radi poboljšanja prijedloga"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Predviđanje sljedeće riječi"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Upotrijebite prethodnu riječ i za predviđanje"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Idi"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema tipkovnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engleski (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engleski (SAD)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nema jezika (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način studije upotrebljivosti"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Postavke trajanja vibracije kod pritiska tipke"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Postavke glasnoće zvuka kod pritiska tipke"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index dcdcc59..a414821 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mérsékelt"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresszív"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Nagyon agresszív"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Következő szóra vonatkozó javaslatok"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Javaslatok fejlesztése az előző szó használatával"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Következő szó előrejelzése"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Az előző szó használata a prediktív bevitelhez is"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ugrás"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Billentyűzettéma"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"angol (brit)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"angol (amerikai)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nincs nyelv (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Használhatósági teszt"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Gombnyomás rezgési időtartamának beállításai"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Gombnyomás hangerejének beállításai"</string>
diff --git a/java/res/values-iw/keycodes.xml b/java/res/values-iw/keycodes.xml
deleted file mode 100644
index 1f65a7c..0000000
--- a/java/res/values-iw/keycodes.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- U+0029: ")" RIGHT PARENTHESIS -->
-    <integer name="keycode_for_left_parenthesis">0x0029</integer>
-    <!-- U+0028: "(" LEFT PARENTHESIS -->
-    <integer name="keycode_for_right_parenthesis">0x0028</integer>
-    <!-- U+003E: ">" GREATER-THAN SIGN -->
-    <integer name="keycode_for_less_than">0x003E</integer>
-    <!-- U+003C: "<" LESS-THAN SIGN -->
-    <integer name="keycode_for_greater_than">0x003C</integer>
-    <!-- U+005D: "]" RIGHT SQUARE BRACKET -->
-    <integer name="keycode_for_left_square_bracket">0x005D</integer>
-    <!-- U+005B: "[" LEFT SQUARE BRACKET -->
-    <integer name="keycode_for_right_square_bracket">0x005B</integer>
-    <!-- U+007D: "}" RIGHT CURLY BRACKET -->
-    <integer name="keycode_for_left_curly_bracket">0x007D</integer>
-    <!-- U+007B: "{" LEFT CURLY BRACKET -->
-    <integer name="keycode_for_right_curly_bracket">0x007B</integer>
-</resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 71fbb34..569f71d 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"מצומצם"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"מחמיר"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"מחמיר מאוד"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"הצעות המילה הבאה"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"השתמש במילה הקודמת כדי לשפר את ההצעות"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"חיזוי המילה הבאה"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"השתמש במילה הקודמת גם עבור חיזוי"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string>
     <string name="label_go_key" msgid="1635148082137219148">"בצע"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"עיצוב מקלדת"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"אנגלית (בריטניה)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"אנגלית (ארה\"ב)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"אין שפה (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"מצב מחקר שימושיות"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"הגדרות משך רטט בלחיצה על מקש"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"הגדרות עוצמת קול בלחיצה על מקש"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 703dca7..8c20b46 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"中"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"強"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"最も強い"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"次の入力候補"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"直前の単語から入力候補を予測します"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"次の入力候補を予測"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"前の語句も予測に使用"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string>
     <string name="label_go_key" msgid="1635148082137219148">"実行"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"キーボードのテーマ"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"英語(英国)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"英語(米国)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"言語設定なし(QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"使いやすさの研究モード"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"キー操作バイブの振動時間の設定"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"キー操作音の音量設定"</string>
diff --git a/java/res/values-ky/strings.xml b/java/res/values-ky/strings.xml
new file mode 100644
index 0000000..8592525
--- /dev/null
+++ b/java/res/values-ky/strings.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for english_ime_name (7252517407088836577) -->
+    <skip />
+    <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
+    <skip />
+    <!-- no translation found for english_ime_settings (6661589557206947774) -->
+    <skip />
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <!-- no translation found for spell_checker_service_name (7338064335159755926) -->
+    <skip />
+    <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
+    <skip />
+    <!-- no translation found for android_spell_checker_settings (5822324635435443689) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
+    <skip />
+    <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
+    <skip />
+    <!-- no translation found for sound_on_keypress (6093592297198243644) -->
+    <skip />
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <!-- no translation found for general_category (1859088467017573195) -->
+    <skip />
+    <!-- no translation found for correction_category (2236750915056607613) -->
+    <skip />
+    <!-- no translation found for misc_category (6894192814868233453) -->
+    <skip />
+    <!-- no translation found for advanced_settings (362895144495591463) -->
+    <skip />
+    <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
+    <skip />
+    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict (4435317977804180815) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
+    <skip />
+    <!-- no translation found for enable_span_insert (7204653105667167620) -->
+    <skip />
+    <!-- no translation found for enable_span_insert_summary (2947317657871394467) -->
+    <skip />
+    <!-- no translation found for auto_cap (1719746674854628252) -->
+    <skip />
+    <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
+    <skip />
+    <!-- no translation found for main_dictionary (4798763781818361168) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for auto_correction (4979925752001319458) -->
+    <skip />
+    <!-- no translation found for auto_correction_summary (5625751551134658006) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
+    <skip />
+    <!-- no translation found for bigram_prediction (3216364899483135294) -->
+    <skip />
+    <!-- no translation found for bigram_prediction_summary (1747261921174300098) -->
+    <skip />
+    <!-- no translation found for added_word (8993883354622484372) -->
+    <skip />
+    <string name="label_go_key" msgid="1635148082137219148">"Баруу"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Кийин"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Мурун"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Даяр"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Жибер"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <!-- no translation found for spoken_use_headphones (896961781287283493) -->
+    <skip />
+    <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
+    <skip />
+    <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
+    <skip />
+    <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift (244197883292549308) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
+    <skip />
+    <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
+    <skip />
+    <!-- no translation found for spoken_description_delete (8740376944276199801) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
+    <skip />
+    <!-- no translation found for spoken_description_settings (4627462689603838099) -->
+    <skip />
+    <!-- no translation found for spoken_description_tab (2667716002663482248) -->
+    <skip />
+    <!-- no translation found for spoken_description_space (2582521050049860859) -->
+    <skip />
+    <!-- no translation found for spoken_description_mic (615536748882611950) -->
+    <skip />
+    <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
+    <skip />
+    <!-- no translation found for spoken_description_return (8178083177238315647) -->
+    <skip />
+    <!-- no translation found for spoken_description_dot (40711082435231673) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
+    <skip />
+    <!-- no translation found for voice_input (3583258583521397548) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
+    <skip />
+    <!-- no translation found for configure_input_method (373356270290742459) -->
+    <skip />
+    <!-- no translation found for language_selection_title (1651299598555326750) -->
+    <skip />
+    <!-- no translation found for select_language (3693815588777926848) -->
+    <skip />
+    <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
+    <skip />
+    <!-- no translation found for has_dictionary (6071847973466625007) -->
+    <skip />
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (8451164783510487501) -->
+    <skip />
+    <!-- no translation found for subtype_en_GB (88170601942311355) -->
+    <skip />
+    <!-- no translation found for subtype_en_US (6160452336634534239) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
+    <skip />
+</resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index aa8c1b7..b08d059 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Vidutinis"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Atkaklus"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Labai agresyviai"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Kito žodžio pasiūlymai"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Naudoti ankstesnį žodį pasiūlymams patobulinti"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Kito žodžio numatymas"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Numatant naudoti ir ankstesnį žodį"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Pradėti"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Klaviatūros tema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Anglų k. (JK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Anglų k. (JAV)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nėra kalbos (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tinkamumo tyrimo režimas"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Vibracijos paspaudus mygtuką trukmės nustatymai"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Garso paspaudus mygtuką garsumo nustatymai"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index bc6a7be..c802340 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mērena"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresīva"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Ļoti radikāla"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Nākamā vārda ieteikumi"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Ieteikumu uzlabošanai izmantot iepriekšējo vārdu"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Nākamā vārda prognozēšana"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Izmantot iepriekšējo vārdu arī prognozēm"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Sākt"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tastatūras motīvs"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Angļu valoda (Lielbritānija)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Angļu valoda (ASV)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nav valodas (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Lietojamības izpētes režīms"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Taustiņu nospiešanas vibrācijas ilguma iestatījumi"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Taustiņu nospiešanas skaņas skaļuma iestatījumi"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index ad59c2f..7ba51bc 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Normaal"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressief"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Zeer agressief"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Volgende woordsuggesties"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Vorig woord gebruiken om suggesties te verbeteren"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Volgende woordvoorspelling"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Het voorgaande woord ook voor voorspelling gebruiken"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Start"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Toetsenbordthema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engels (GB)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engels (VS)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Geen taal (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus voor gebruiksvriendelijkheidsonderzoek"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Instellingen voor trillingsduur bij druk op een toets"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Instellingen voor geluidsvolume bij druk op een toets"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 3440c5c..49f7518 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Umiarkowana"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresywna"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Bardzo agresywna"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sugestie kolejnych słów"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Używaj poprzedniego wyrazu, by polepszyć sugestie"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Przewidywanie następnego wyrazu"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Przewiduj również na podstawie poprzedniego słowa"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Motyw klawiatury"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Angielska (Wielka Brytania)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Angielska (Stany Zjednoczone)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Brak języka (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tryb badania przydatności"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Czas trwania wibracji przy naciśnięciu"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Głośność dźwięku przy naciśnięciu"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 3fe58a8..1969888 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressivo"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Muito agressivo"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sugestões para a palavra seguinte"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Usar palavra anterior para melhorar as sugestões"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Previsão da palavra seguinte"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Use também a palavra anterior para prever"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inglês (Reino Unido)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inglês (EUA)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nenhum idioma (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo de utilização"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Configurações de duração da vibração ao tocar a tecla"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Configurações do volume ao tocar a tecla"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index dd830ce..80a6558 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderată"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivă"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Foarte agresiv"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sugestii pentru cuvântul următor"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Utilizaţi cuvântul anterior pentru a îmbunătăţi sugestiile"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Predicţia cuvântului următor"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Se utilizează şi cuvântul precedent pentru predicţii"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Temă pentru tastatură"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engleză (Marea Britanie)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engleză (S.U.A.)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nicio limbă (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modul Studiu privind utilizarea"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Setări pentru durata vibrării la apăsarea tastei"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Setări pentru volumul sunetului la apăsarea tastei"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 13d3ae1..4910df0 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умеренное"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Активное"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Очень активно"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Предложения для следующего слова"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Использовать предыдущее слово, чтобы улучшить предложения"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Подсказка для следующего слова"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Использовать предыдущее слово для прогнозирования"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Поиск"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Тема клавиатуры"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"английский (Великобритания)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"английский (США)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Нет языка (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим проверки удобства использования"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Настройки вибросигнала при нажатии клавиш"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Настройки громкости звука при нажатии клавиш"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index a8f108e..57bc3a0 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mierne"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresívne"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Veľmi agresívna"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Návrhy ďalšieho slova"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Na zlepšenie návrhov použiť predchádzajúce slovo"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Odhad ďalšieho slova"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Použiť predchádzajúce slovo aj pre predpoveď"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Hľadať"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Motív klávesnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Anglická klávesnica (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Anglická klávesnica (US)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Žiadny jazyk (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Režim štúdie použiteľnosti"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Nastavenia trvania vibrovania pri stlačení klávesu"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Nastavenia hlasitosti zvuku pri stlačení klávesu"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 9dc4844..890877f 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Zmerno"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Strogo"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Zelo strogo"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Predlogi naslednje besede"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Predloge izboljšaj s prejšnjo besedo"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Predvidevanje naslednje besede"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Uporabi prejšnjo besedo tudi za predvidevanje"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Pojdi"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema tipkovnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"angleščina (Združeno kraljestvo)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"angleščina (ZDA)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ni jezika (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Način za preučevanje uporabnosti"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Nastavitve za trajanje vibriranja ob pritisku tipke"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Nastavitve za glasnost zvoka ob pritisku tipke"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index b70f285..f21abd2 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умерено"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Агресивно"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Веома агресивно"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Предлози за следећу реч"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Користи претходну реч за побољшање предлога"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Предвиђање следеће речи"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Користи претходну реч и за предвиђање"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Иди"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Тема тастатуре"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"енглески (УК)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"енглески (САД)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Нема језика (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Режим за студију могућности коришћења"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Подешавања трајања вибрације при притиску на тастере"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Подешавања јачине звука при притиску на тастере"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 32bca02..918fa42 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Måttlig"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressiv"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Mycket aggressivt"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Föreslå nästa ord"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Förbättra förslagen med föregående ord"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Förutspå nästa ord"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Använd även föregående ord för att ge förslag"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Kör"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tangentbordstema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engelskt (brittiskt)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engelskt (amerikanskt)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Inget språk (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Läge för studie av användbarhet"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Inställningar för vibrationslängd vid knapptryck"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Volyminställningar för knappljud"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 1a835f1..39ecc02 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Ya wastani"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Ya hima"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Changamfu zaidi"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Mapendekezo ya neno lifuatalo"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Tumia neno la awali ili kuboresha mapendekezo"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Utabiri wa neno lifuatalo"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Tumia  neno la awali pia kwa udadisi"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Nenda"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Maandhari ya kibodi"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Kiingereza cha (Uingereza)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Kiingereza cha (Marekani)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Hakuna lugha (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modi ya uchunguzi wa utumizi"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Bonyeza mipangilio ya kipindi cha mtetemo"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Bonyeza mipangilio ya nguvu za sauti"</string>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 3595796..87838ad 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -71,7 +71,7 @@
     <string name="label_previous_key" msgid="1211868118071386787">"ก่อนหน้า"</string>
     <string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string>
     <string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string>
-    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"กขค"</string>
     <string name="label_to_symbol_key" msgid="8516904117128967293">"?123"</string>
     <string name="label_to_symbol_with_microphone_key" msgid="9035925553010061906">"123"</string>
     <string name="label_pause_key" msgid="181098308428035340">"หยุดชั่วคราว"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index bf6712c..2bf661f 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresibo"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Napaka-agresibo"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Mga paghuhula sa susunod na salita"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Gamitin ang naunang salita para mapahusay ang mga suhestiyon"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Paghuhula sa susunod na salita"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Gamitin ang nakaraang salita para din sa hula"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Punta"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema ng keyboard"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Ingles (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Ingles (Estados Unidos)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Walang wika (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Study mode ng pagiging kapaki-pakinabang"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Mga setting ng tagal ng vibration ng keypress"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Mga setting ng volume ng tunog ng keypress"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 5e79d82..abca632 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Ölçülü"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresif"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Çok geniş ölçekte"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Sonraki kelime önerileri"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Önerileri geliştirmek için önceki kelimeyi kullan"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Sonraki kelime tahmini"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Önceki kelimeyi de tahmin için kullan"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Git"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Klavye teması"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"İngilizce (BK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"İngilizce (ABD)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Dil yok (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Kullanılabilirlik çalışması modu"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Tuşa basma titreşim süresi ayarları"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Tuşa basma ses düzeyi ayarları"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 8bdc29c..362882e 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Đơn giản"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Linh hoạt"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Rất linh hoạt"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Đề xuất từ tiếp theo"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Sử dụng từ trước đó để cải tiến đề xuất"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Dự đoán từ tiếp theo"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Cũng sử dụng từ trước đó để dự đoán"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Tìm"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Chủ đề bàn phím"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Tiếng Anh (Anh)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Tiếng Anh (Mỹ)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Không có ngôn ngữ (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Chế độ nghiên cứu tính khả dụng"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Cài đặt thời gian rung khi nhấn phím"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Cài đặt âm lượng khi nhấn phím"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 7fa505c..73cec6e 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"小改"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"大改"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"改动极大"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"下一字词建议"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"使用上一字词改进建议"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"下一字词预测"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"结合前一个字词进行预测"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string>
     <string name="label_go_key" msgid="1635148082137219148">"开始"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"键盘主题"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"英语(英国)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"英语(美国)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"无语言(QWERTY 键盘)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"可用性研究模式"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"按键振动持续时间设置"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"按键音量设置"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 9610548..9691d59 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -61,12 +61,9 @@
     <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Thobekile"</string>
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Bukhali"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Nobudlova kakhulu"</string>
-    <!-- no translation found for bigram_suggestion (8169311444438922902) -->
-    <skip />
-    <!-- no translation found for bigram_suggestion_summary (6635527607242625713) -->
-    <skip />
-    <!-- no translation found for bigram_prediction (3216364899483135294) -->
-    <skip />
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Iziphakamiso zegama elilandelayo"</string>
+    <string name="bigram_suggestion_summary" msgid="6635527607242625713">"Sebenzisa igama elandulele ukuthuthukisa okusikiselwayo"</string>
+    <string name="bigram_prediction" msgid="3216364899483135294">"Ukuqagela kwegama elilandelayo"</string>
     <string name="bigram_prediction_summary" msgid="1747261921174300098">"Sebenzisa igama langaphambilini ukuze uqagele"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kulondoloziwe"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Iya"</string>
@@ -121,8 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Indikimba yekhibhodi"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"i-English(UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"i-English (US)"</string>
-    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
-    <skip />
+    <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Akunalimi (QWERTY)"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Imodi yesitadi yokusebenziseka"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Izilungiselelo ze-keypress vibration duraton"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Izilungiselelo zevolumu yomsindo wekeypress"</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 39d50e3..4ec1843 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -229,10 +229,14 @@
     </declare-styleable>
 
     <declare-styleable name="Keyboard_Key">
-        <!-- The unicode value that this key outputs. -->
-        <attr name="code" format="integer" />
-        <!-- The alternate unicode value that this key outputs while typing. -->
-        <attr name="altCode" format="integer" />
+        <!-- The unicode value that this key outputs.
+             Code value represented in hexadecimal prefixed with "0x" or code value reference using
+             "!code/<code_name>" notation. -->
+        <attr name="code" format="string" />
+        <!-- The alternate unicode value that this key outputs while typing.
+             Code value represented in hexadecimal prefixed with "0x" or code value reference using
+             "!code/<code_name>" notation. -->
+        <attr name="altCode" format="string" />
         <!-- The keys to display in the more keys keyboard. -->
         <attr name="moreKeys" format="string" />
         <!-- The keys to display in the more keys keyboard in addition to moreKeys.
@@ -271,10 +275,11 @@
             <flag name="alignLeft" value="0x01" />
             <flag name="alignRight" value="0x02" />
             <flag name="alignLeftOfCenter" value="0x08" />
-            <flag name="largeLetter" value="0x10" />
-            <flag name="fontNormal" value="0x20" />
-            <flag name="fontMonoSpace" value="0x40" />
+            <flag name="fontNormal" value="0x10" />
+            <flag name="fontMonoSpace" value="0x20" />
+            <flag name="followKeyLargeLetterRatio" value="0x40" />
             <flag name="followKeyLetterRatio" value="0x80" />
+            <flag name="followKeyLabelRatio" value="0xC0" />
             <flag name="followKeyHintLabelRatio" value="0x100" />
             <flag name="hasPopupHint" value="0x200" />
             <flag name="hasShiftedLetterHint" value="0x400" />
@@ -296,6 +301,7 @@
             <flag name="disableAdditionalMoreKeys" value="0x80000000" />
         </attr>
         <!-- The icon to display on the key instead of the label. -->
+        <!-- TODO: Use string format !icon/name. -->
         <attr name="keyIcon" format="enum">
             <!-- This should be aligned with the KeyboardIconsSet.ICON_* -->
             <enum name="iconUndefined" value="0" />
@@ -315,11 +321,13 @@
             <enum name="iconZwjKey" value="16" />
         </attr>
         <!-- The icon for disabled key -->
+        <!-- TODO: Use string format !icon/name. -->
         <attr name="keyIconDisabled" format="enum">
             <!-- This should be aligned with the KeyboardIconsSet.ICON_* -->
             <enum name="iconDisabledShortcutKey" value="12" />
         </attr>
         <!-- The icon to show in the popup preview. -->
+        <!-- TODO: Use string format !icon/name. -->
         <attr name="keyIconPreview" format="enum">
             <!-- This should be aligned with the KeyboardIconsSet.ICON_* -->
             <enum name="iconPreviewTabKey" value="13" />
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 9c8bd3c..bfe4232 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -45,24 +45,6 @@
     <!-- <string name="layout_switch_back_symbols">\"\'&#x2018;&#x2019;&#x201A;&#x201B;&#x201C;&#x201D;&#x201E;&#x201F;&#x00AB;&#x00BB;</string> -->
     <string name="layout_switch_back_symbols"></string>
 
-    <!-- Label for "switch to more symbol" modifier key.  Must be short to fit on key! -->
-    <string name="label_to_more_symbol_key">= \\ &lt;</string>
-    <!-- Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key! -->
-    <string name="label_to_more_symbol_for_tablet_key">~ \\ {</string>
-
-    <!-- Label for "Tab" key.  Must be short to fit on key! -->
-    <string name="label_tab_key">Tab</string>
-    <!-- Label for "switch to phone numeric" key.  Must be short to fit on key! -->
-    <string name="label_to_phone_numeric_key">123</string>
-    <!-- Label for "switch to phone symbols" key.  Must be short to fit on key! -->
-    <!-- U+FF0A: "*" FULLWIDTH ASTERISK
-         U+FF03: "#" FULLWIDTH NUMBER SIGN -->
-    <string name="label_to_phone_symbols_key">&#xFF0A;&#xFF03;</string>
-    <!-- Key label for "ante meridiem" -->
-    <string name="label_time_am">"AM"</string>
-    <!-- Key label for "post meridiem" -->
-    <string name="label_time_pm">"PM"</string>
-
     <!--  Always show the suggestion strip -->
     <string name="prefs_suggestion_visibility_show_value">0</string>
     <!--  Show the suggestion strip only on portrait mode -->
diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml
deleted file mode 100644
index f42495a..0000000
--- a/java/res/values/keycodes.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* 
-**
-** Copyright 2009, 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.
-*/
--->
-
-<resources>
-    <!-- These code should be aligned with Keyboard.CODE_*. -->
-    <integer name="key_tab">9</integer>
-    <integer name="key_enter">10</integer>
-    <integer name="key_space">32</integer>
-    <integer name="key_shift">-1</integer>
-    <integer name="key_switch_alpha_symbol">-2</integer>
-    <integer name="key_output_text">-3</integer>
-    <integer name="key_delete">-4</integer>
-    <integer name="key_settings">-5</integer>
-    <integer name="key_shortcut">-6</integer>
-    <integer name="key_action_enter">-7</integer>
-    <integer name="key_action_next">-8</integer>
-    <integer name="key_action_previous">-9</integer>
-    <integer name="key_language_switch">-10</integer>
-    <integer name="key_unspecified">-11</integer>
-    <!-- U+0028: "(" LEFT PARENTHESIS -->
-    <integer name="keycode_for_left_parenthesis">0x0028</integer>
-    <!-- U+0029: ")" RIGHT PARENTHESIS -->
-    <integer name="keycode_for_right_parenthesis">0x0029</integer>
-    <!-- U+003C: "<" LESS-THAN SIGN -->
-    <integer name="keycode_for_less_than">0x003C</integer>
-    <!-- U+003E: ">" GREATER-THAN SIGN -->
-    <integer name="keycode_for_greater_than">0x003E</integer>
-    <!-- U+005B: "[" LEFT SQUARE BRACKET -->
-    <integer name="keycode_for_left_square_bracket">0x005B</integer>
-    <!-- U+005D: "]" RIGHT SQUARE BRACKET -->
-    <integer name="keycode_for_right_square_bracket">0x005D</integer>
-    <!-- U+007B: "{" LEFT CURLY BRACKET -->
-    <integer name="keycode_for_left_curly_bracket">0x007B</integer>
-    <!-- U+007D: "}" RIGHT CURLY BRACKET -->
-    <integer name="keycode_for_right_curly_bracket">0x007D</integer>
-</resources>
diff --git a/java/res/xml-sw600dp/key_shortcut.xml b/java/res/xml-sw600dp/key_shortcut.xml
index d4c45ad..2114c67 100644
--- a/java/res/xml-sw600dp/key_shortcut.xml
+++ b/java/res/xml-sw600dp/key_shortcut.xml
@@ -29,7 +29,7 @@
             <Key
                 latin:keyStyle="shortcutKeyStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/settings_as_more_key"
+                latin:moreKeys="!label/settings_as_more_key"
                 latin:keyWidth="fillBoth" />
         </case>
         <case
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index 45e22fc..e0676e8 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -42,7 +42,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -52,7 +52,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOn" />
@@ -60,7 +60,7 @@
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKey"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -68,7 +68,7 @@
     </switch>
     <key-style
         latin:styleName="deleteKeyStyle"
-        latin:code="@integer/key_delete"
+        latin:code="!code/key_delete"
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
@@ -76,7 +76,7 @@
         latin:keyboardLayout="@xml/key_styles_enter" />
     <key-style
         latin:styleName="spaceKeyStyle"
-        latin:code="@integer/key_space"
+        latin:code="!code/key_space"
         latin:keyActionFlags="noKeyPreview" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
          U+200D: ZERO WIDTH JOINER -->
@@ -84,7 +84,7 @@
         latin:styleName="zwnjKeyStyle"
         latin:code="0x200C"
         latin:keyIcon="iconZwnjKey"
-        latin:moreKeys="\@icon/zwjKey|&#x200D;"
+        latin:moreKeys="!icon/zwjKey|&#x200D;"
         latin:keyLabelFlags="hasPopupHint"
         latin:keyActionFlags="noKeyPreview" />
     <key-style
@@ -92,10 +92,10 @@
         latin:keyLabel=":-)"
         latin:keyOutputText=":-) "
         latin:keyLabelFlags="hasPopupHint|preserveCase"
-        latin:moreKeys="@string/more_keys_for_smiley" />
+        latin:moreKeys="!label/more_keys_for_smiley" />
     <key-style
         latin:styleName="shortcutKeyStyle"
-        latin:code="@integer/key_shortcut"
+        latin:code="!code/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
         latin:keyLabelFlags="preserveCase"
@@ -103,7 +103,7 @@
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="settingsKeyStyle"
-        latin:code="@integer/key_settings"
+        latin:code="!code/key_settings"
         latin:keyIcon="iconSettingsKey"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
         latin:backgroundType="functional" />
@@ -114,7 +114,7 @@
         >
             <key-style
                 latin:styleName="tabKeyStyle"
-                latin:code="@integer/key_action_previous"
+                latin:code="!code/key_action_previous"
                 latin:keyIcon="iconTabKey"
                 latin:keyIconPreview="iconPreviewTabKey"
                 latin:backgroundType="functional" />
@@ -122,7 +122,7 @@
         <default>
             <key-style
                 latin:styleName="tabKeyStyle"
-                latin:code="@integer/key_tab"
+                latin:code="!code/key_tab"
                 latin:keyIcon="iconTabKey"
                 latin:keyIconPreview="iconPreviewTabKey"
                 latin:backgroundType="functional" />
@@ -130,36 +130,36 @@
     </switch>
     <key-style
         latin:styleName="toSymbolKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_symbol_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_symbol_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="toAlphaKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_alpha_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_alpha_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="toMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_more_symbol_for_tablet_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_more_symbol_for_tablet_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="backFromMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_symbol_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_symbol_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="comKeyStyle"
-        latin:keyLabel="@string/keylabel_for_popular_domain"
+        latin:keyLabel="!label/keylabel_for_popular_domain"
         latin:keyLabelFlags="fontNormal|hasPopupHint|preserveCase"
-        latin:keyOutputText="@string/keylabel_for_popular_domain"
-        latin:moreKeys="@string/more_keys_for_popular_domain" />
+        latin:keyOutputText="!label/keylabel_for_popular_domain"
+        latin:moreKeys="!label/more_keys_for_popular_domain" />
 </merge>
diff --git a/java/res/xml-sw600dp/keys_apostrophe_dash.xml b/java/res/xml-sw600dp/keys_apostrophe_dash.xml
index a53c1e4..faaae50 100644
--- a/java/res/xml-sw600dp/keys_apostrophe_dash.xml
+++ b/java/res/xml-sw600dp/keys_apostrophe_dash.xml
@@ -39,9 +39,9 @@
         </case>
         <default>
             <Key
-                latin:keyLabel="@string/keylabel_for_apostrophe"
-                latin:keyHintLabel="@string/keyhintlabel_for_apostrophe"
-                latin:moreKeys="@string/more_keys_for_apostrophe"
+                latin:keyLabel="!label/keylabel_for_apostrophe"
+                latin:keyHintLabel="!label/keyhintlabel_for_apostrophe"
+                latin:moreKeys="!label/more_keys_for_apostrophe"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </default>
     </switch>
@@ -54,9 +54,9 @@
         </case>
         <default>
             <Key
-                latin:keyLabel="@string/keylabel_for_dash"
-                latin:keyHintLabel="@string/keyhintlabel_for_dash"
-                latin:moreKeys="@string/more_keys_for_dash"
+                latin:keyLabel="!label/keylabel_for_dash"
+                latin:keyHintLabel="!label/keyhintlabel_for_dash"
+                latin:moreKeys="!label/more_keys_for_dash"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </default>
     </switch>
diff --git a/java/res/xml-sw600dp/keys_comma_period.xml b/java/res/xml-sw600dp/keys_comma_period.xml
index f5f307b..4a83cc8 100644
--- a/java/res/xml-sw600dp/keys_comma_period.xml
+++ b/java/res/xml-sw600dp/keys_comma_period.xml
@@ -32,14 +32,14 @@
         </case>
         <default>
             <Key
-                latin:keyLabel="@string/keylabel_for_tablet_comma"
-                latin:keyHintLabel="@string/keyhintlabel_for_tablet_comma"
-                latin:moreKeys="@string/more_keys_for_tablet_comma"
+                latin:keyLabel="!label/keylabel_for_tablet_comma"
+                latin:keyHintLabel="!label/keyhintlabel_for_tablet_comma"
+                latin:moreKeys="!label/more_keys_for_tablet_comma"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
             <Key
                 latin:keyLabel="."
-                latin:keyHintLabel="@string/keyhintlabel_for_tablet_period"
-                latin:moreKeys="@string/more_keys_for_tablet_period"
+                latin:keyHintLabel="!label/keyhintlabel_for_tablet_period"
+                latin:moreKeys="!label/more_keys_for_tablet_period"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </default>
     </switch>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols2.xml b/java/res/xml-sw600dp/rowkeys_symbols2.xml
index e0121a3..fd77416 100644
--- a/java/res/xml-sw600dp/rowkeys_symbols2.xml
+++ b/java/res/xml-sw600dp/rowkeys_symbols2.xml
@@ -26,13 +26,13 @@
     <Key
         latin:keyStyle="currencyKeyStyle" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_percent"
-        latin:moreKeys="@string/more_keys_for_symbols_percent" />
+        latin:keyLabel="!label/keylabel_for_symbols_percent"
+        latin:moreKeys="!label/more_keys_for_symbols_percent" />
     <Key
         latin:keyLabel="&amp;" />
     <Key
         latin:keyLabel="*"
-        latin:moreKeys="@string/more_keys_for_star" />
+        latin:moreKeys="!label/more_keys_for_star" />
     <!-- U+2013: "–" EN DASH
          U+2014: "—" EM DASH -->
     <Key
@@ -40,7 +40,7 @@
         latin:moreKeys="_,&#x2013;,&#x2014;" />
     <Key
         latin:keyLabel="+"
-        latin:moreKeys="@string/more_keys_for_plus" />
+        latin:moreKeys="!label/more_keys_for_plus" />
     <include
         latin:keyboardLayout="@xml/keys_parentheses" />
 </merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols3.xml b/java/res/xml-sw600dp/rowkeys_symbols3.xml
index 9293352..536ac05 100644
--- a/java/res/xml-sw600dp/rowkeys_symbols3.xml
+++ b/java/res/xml-sw600dp/rowkeys_symbols3.xml
@@ -41,11 +41,11 @@
         </default>
     </switch>
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_semicolon"
-        latin:moreKeys="@string/more_keys_for_symbols_semicolon" />
+        latin:keyLabel="!label/keylabel_for_symbols_semicolon"
+        latin:moreKeys="!label/more_keys_for_symbols_semicolon" />
     <Key
-        latin:keyLabel="@string/keylabel_for_comma"
-        latin:moreKeys="@string/more_keys_for_comma" />
+        latin:keyLabel="!label/keylabel_for_comma"
+        latin:moreKeys="!label/more_keys_for_comma" />
     <Key
         latin:keyLabel="." />
     <!-- U+00A1: "¡" INVERTED EXCLAMATION MARK -->
@@ -53,6 +53,6 @@
         latin:keyLabel="!"
         latin:moreKeys="&#x00A1;" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_question"
-        latin:moreKeys="@string/more_keys_for_symbols_question" />
+        latin:keyLabel="!label/keylabel_for_symbols_question"
+        latin:moreKeys="!label/more_keys_for_symbols_question" />
 </merge>
diff --git a/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml b/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml
index 356ee2f..914a449 100644
--- a/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml
+++ b/java/res/xml-sw600dp/rowkeys_symbols_shift1.xml
@@ -30,7 +30,7 @@
     <!-- U+2022: "•" BULLET -->
     <Key
         latin:keyLabel="&#x2022;"
-        latin:moreKeys="@string/more_keys_for_bullet" />
+        latin:moreKeys="!label/more_keys_for_bullet" />
     <!-- U+221A: "√" SQUARE ROOT -->
     <Key
         latin:keyLabel="&#x221A;" />
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index be5776b..00fda28 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -70,7 +70,7 @@
                 <Key
                     latin:keyLabel=","
                     latin:keyLabelFlags="hasPopupHint"
-                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:moreKeys="!label/more_keys_for_am_pm"
                     latin:keyStyle="numKeyStyle"
                     latin:keyWidth="9.25%p" />
             </case>
diff --git a/java/res/xml-sw600dp/rows_symbols4.xml b/java/res/xml-sw600dp/rows_symbols4.xml
index bfc9b2c..afa2652 100644
--- a/java/res/xml-sw600dp/rows_symbols4.xml
+++ b/java/res/xml-sw600dp/rows_symbols4.xml
@@ -37,7 +37,7 @@
             latin:keyWidth="39.750%p" />
         <Key
             latin:keyLabel="&quot;"
-            latin:moreKeys="@string/more_keys_for_tablet_double_quote" />
+            latin:moreKeys="!label/more_keys_for_tablet_double_quote" />
         <Key
             latin:keyLabel="_" />
         <Spacer
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index e1c2369..c3e2fd9 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -41,7 +41,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -51,7 +51,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOn" />
@@ -59,7 +59,7 @@
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKey"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -67,7 +67,7 @@
     </switch>
     <key-style
         latin:styleName="deleteKeyStyle"
-        latin:code="@integer/key_delete"
+        latin:code="!code/key_delete"
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
@@ -75,7 +75,7 @@
         latin:keyboardLayout="@xml/key_styles_enter" />
     <key-style
         latin:styleName="spaceKeyStyle"
-        latin:code="@integer/key_space"
+        latin:code="!code/key_space"
         latin:keyActionFlags="noKeyPreview" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
          U+200D: ZERO WIDTH JOINER -->
@@ -83,7 +83,7 @@
         latin:styleName="zwnjKeyStyle"
         latin:code="0x200C"
         latin:keyIcon="iconZwnjKey"
-        latin:moreKeys="\@icon/zwjKey|&#x200D;"
+        latin:moreKeys="!icon/zwjKey|&#x200D;"
         latin:keyLabelFlags="hasPopupHint"
         latin:keyActionFlags="noKeyPreview" />
     <key-style
@@ -91,10 +91,10 @@
         latin:keyLabel=":-)"
         latin:keyOutputText=":-) "
         latin:keyLabelFlags="hasPopupHint|preserveCase"
-        latin:moreKeys="@string/more_keys_for_smiley" />
+        latin:moreKeys="!label/more_keys_for_smiley" />
     <key-style
         latin:styleName="shortcutKeyStyle"
-        latin:code="@integer/key_shortcut"
+        latin:code="!code/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
         latin:keyLabelFlags="preserveCase"
@@ -102,7 +102,7 @@
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="settingsKeyStyle"
-        latin:code="@integer/key_settings"
+        latin:code="!code/key_settings"
         latin:keyIcon="iconSettingsKey"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
         latin:backgroundType="functional" />
@@ -113,52 +113,52 @@
         >
             <key-style
                 latin:styleName="tabKeyStyle"
-                latin:code="@integer/key_action_previous"
-                latin:keyLabel="@string/label_tab_key"
+                latin:code="!code/key_action_previous"
+                latin:keyLabel="!label/label_tab_key"
                 latin:keyLabelFlags="fontNormal|preserveCase"
                 latin:backgroundType="functional" />
         </case>
         <default>
             <key-style
                 latin:styleName="tabKeyStyle"
-                latin:code="@integer/key_tab"
-                latin:keyLabel="@string/label_tab_key"
+                latin:code="!code/key_tab"
+                latin:keyLabel="!label/label_tab_key"
                 latin:keyLabelFlags="fontNormal|preserveCase"
                 latin:backgroundType="functional" />
         </default>
     </switch>
     <key-style
         latin:styleName="toSymbolKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_symbol_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_symbol_key"
         latin:keyLabelFlags="fontNormal|preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="toAlphaKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_alpha_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_alpha_key"
         latin:keyLabelFlags="fontNormal|preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="toMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_more_symbol_for_tablet_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_more_symbol_for_tablet_key"
         latin:keyLabelFlags="fontNormal|preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="backFromMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_symbol_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_symbol_key"
         latin:keyLabelFlags="fontNormal|preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="comKeyStyle"
-        latin:keyLabel="@string/keylabel_for_popular_domain"
+        latin:keyLabel="!label/keylabel_for_popular_domain"
         latin:keyLabelFlags="fontNormal|hasPopupHint|preserveCase"
-        latin:keyOutputText="@string/keylabel_for_popular_domain"
-        latin:moreKeys="@string/more_keys_for_popular_domain" />
+        latin:keyOutputText="!label/keylabel_for_popular_domain"
+        latin:moreKeys="!label/more_keys_for_popular_domain" />
 </merge>
diff --git a/java/res/xml-sw768dp/keys_apostrophe_dash.xml b/java/res/xml-sw768dp/keys_apostrophe_dash.xml
index a53c1e4..faaae50 100644
--- a/java/res/xml-sw768dp/keys_apostrophe_dash.xml
+++ b/java/res/xml-sw768dp/keys_apostrophe_dash.xml
@@ -39,9 +39,9 @@
         </case>
         <default>
             <Key
-                latin:keyLabel="@string/keylabel_for_apostrophe"
-                latin:keyHintLabel="@string/keyhintlabel_for_apostrophe"
-                latin:moreKeys="@string/more_keys_for_apostrophe"
+                latin:keyLabel="!label/keylabel_for_apostrophe"
+                latin:keyHintLabel="!label/keyhintlabel_for_apostrophe"
+                latin:moreKeys="!label/more_keys_for_apostrophe"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </default>
     </switch>
@@ -54,9 +54,9 @@
         </case>
         <default>
             <Key
-                latin:keyLabel="@string/keylabel_for_dash"
-                latin:keyHintLabel="@string/keyhintlabel_for_dash"
-                latin:moreKeys="@string/more_keys_for_dash"
+                latin:keyLabel="!label/keylabel_for_dash"
+                latin:keyHintLabel="!label/keyhintlabel_for_dash"
+                latin:moreKeys="!label/more_keys_for_dash"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </default>
     </switch>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index 2eeb6c9..f868cbb 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -72,7 +72,7 @@
                 <Key
                     latin:keyLabel=","
                     latin:keyLabelFlags="hasPopupHint"
-                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:moreKeys="!label/more_keys_for_am_pm"
                     latin:keyStyle="numKeyStyle"
                     latin:keyWidth="8.047%p" />
             </case>
diff --git a/java/res/xml-sw768dp/rows_symbols4.xml b/java/res/xml-sw768dp/rows_symbols4.xml
index 19b36d6..dd1647b 100644
--- a/java/res/xml-sw768dp/rows_symbols4.xml
+++ b/java/res/xml-sw768dp/rows_symbols4.xml
@@ -37,7 +37,7 @@
             latin:keyWidth="37.500%p" />
         <Key
             latin:keyLabel="&quot;"
-            latin:moreKeys="@string/more_keys_for_tablet_double_quote" />
+            latin:moreKeys="!label/more_keys_for_tablet_double_quote" />
         <Key
             latin:keyLabel="_" />
         <switch>
diff --git a/java/res/xml/key_azerty_quote.xml b/java/res/xml/key_azerty_quote.xml
index 966ae6f..b8c51d3 100644
--- a/java/res/xml/key_azerty_quote.xml
+++ b/java/res/xml/key_azerty_quote.xml
@@ -31,7 +31,7 @@
         <default>
             <Key
                 latin:keyLabel="\'"
-                latin:moreKeys="\@string/more_keys_for_single_quote" />
+                latin:moreKeys="!label/more_keys_for_single_quote" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 8d01091..ec011d0 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -35,7 +35,7 @@
             <key-style
                 latin:styleName="f1MoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/settings_as_more_key"
+                latin:moreKeys="!label/settings_as_more_key"
                 latin:backgroundType="functional" />
         </default>
     </switch>
@@ -46,7 +46,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -56,7 +56,7 @@
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKeyShifted"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOn" />
@@ -64,7 +64,7 @@
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="@integer/key_shift"
+                latin:code="!code/key_shift"
                 latin:keyIcon="iconShiftKey"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="stickyOff" />
@@ -72,7 +72,7 @@
     </switch>
     <key-style
         latin:styleName="deleteKeyStyle"
-        latin:code="@integer/key_delete"
+        latin:code="!code/key_delete"
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
@@ -98,13 +98,13 @@
                 latin:keyLabel=":-)"
                 latin:keyOutputText=":-) "
                 latin:keyLabelFlags="hasPopupHint"
-                latin:moreKeys="@string/more_keys_for_smiley"
+                latin:moreKeys="!label/more_keys_for_smiley"
                 latin:backgroundType="functional" />
         </case>
     </switch>
     <key-style
         latin:styleName="spaceKeyStyle"
-        latin:code="@integer/key_space"
+        latin:code="!code/key_space"
         latin:keyActionFlags="noKeyPreview|enableLongPress"
         latin:backgroundType="functional" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
@@ -113,29 +113,29 @@
         latin:styleName="zwnjKeyStyle"
         latin:code="0x200C"
         latin:keyIcon="iconZwnjKey"
-        latin:moreKeys="\@icon/zwjKey|&#x200D;"
+        latin:moreKeys="!icon/zwjKey|&#x200D;"
         latin:keyLabelFlags="hasPopupHint"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="shortcutKeyStyle"
-        latin:code="@integer/key_shortcut"
+        latin:code="!code/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
-        latin:altCode="@integer/key_space"
+        latin:altCode="!code/key_space"
         latin:parentStyle="f1MoreKeysStyle" />
     <key-style
         latin:styleName="languageSwitchKeyStyle"
-        latin:code="@integer/key_language_switch"
+        latin:code="!code/key_language_switch"
         latin:keyIcon="iconLanguageSwitchKey"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping|enableLongPress"
-        latin:altCode="@integer/key_space"
+        latin:altCode="!code/key_space"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="tabKeyStyle"
-        latin:code="@integer/key_tab"
+        latin:code="!code/key_tab"
         latin:keyIcon="iconTabKey"
         latin:keyIconPreview="iconPreviewTabKey"
         latin:backgroundType="functional" />
@@ -143,7 +143,7 @@
          laid out as normal letter key. -->
     <key-style
         latin:styleName="nonSpecialBackgroundTabKeyStyle"
-        latin:code="@integer/key_tab"
+        latin:code="!code/key_tab"
         latin:keyIcon="iconTabKey"
         latin:keyIconPreview="iconPreviewTabKey" />
     <switch>
@@ -156,9 +156,9 @@
         >
             <key-style
                 latin:styleName="toSymbolKeyStyle"
-                latin:code="@integer/key_switch_alpha_symbol"
+                latin:code="!code/key_switch_alpha_symbol"
                 latin:keyIcon="iconShortcutForLabel"
-                latin:keyLabel="@string/label_to_symbol_with_microphone_key"
+                latin:keyLabel="!label/label_to_symbol_with_microphone_key"
                 latin:keyLabelFlags="withIconRight|preserveCase"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="functional" />
@@ -166,8 +166,8 @@
         <default>
             <key-style
                 latin:styleName="toSymbolKeyStyle"
-                latin:code="@integer/key_switch_alpha_symbol"
-                latin:keyLabel="@string/label_to_symbol_key"
+                latin:code="!code/key_switch_alpha_symbol"
+                latin:keyLabel="!label/label_to_symbol_key"
                 latin:keyLabelFlags="preserveCase"
                 latin:keyActionFlags="noKeyPreview"
                 latin:backgroundType="functional" />
@@ -175,30 +175,30 @@
     </switch>
     <key-style
         latin:styleName="toAlphaKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_alpha_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_alpha_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="toMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_more_symbol_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_more_symbol_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="backFromMoreSymbolKeyStyle"
-        latin:code="@integer/key_shift"
-        latin:keyLabel="@string/label_to_symbol_key"
+        latin:code="!code/key_shift"
+        latin:keyLabel="!label/label_to_symbol_key"
         latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional" />
     <key-style
         latin:styleName="punctuationKeyStyle"
         latin:keyLabel="."
-        latin:keyHintLabel="@string/keyhintlabel_for_punctuation"
+        latin:keyHintLabel="!label/keyhintlabel_for_punctuation"
         latin:keyLabelFlags="hasPopupHint|preserveCase"
-        latin:moreKeys="@string/more_keys_for_punctuation"
+        latin:moreKeys="!label/more_keys_for_punctuation"
         latin:backgroundType="functional" />
 </merge>
diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index bd1d959..6057d5b 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -86,7 +86,7 @@
             <key-style
                 latin:styleName="currencyKeyStyle"
                 latin:keyLabel="&#x20AA;"
-                latin:moreKeys="@string/more_keys_for_currency_general" />
+                latin:moreKeys="!label/more_keys_for_currency_general" />
             <key-style
                 latin:styleName="moreCurrency1KeyStyle"
                 latin:keyLabel="&#x00A3;" />
@@ -112,7 +112,7 @@
             <key-style
                 latin:styleName="currencyKeyStyle"
                 latin:keyLabel="&#xFDFC;"
-                latin:moreKeys="@string/more_keys_for_currency_general" />
+                latin:moreKeys="!label/more_keys_for_currency_general" />
             <key-style
                 latin:styleName="moreCurrency1KeyStyle"
                 latin:keyLabel="£" />
@@ -138,7 +138,7 @@
             <key-style
                 latin:styleName="currencyKeyStyle"
                 latin:keyLabel="&#x00A3;"
-                latin:moreKeys="@string/more_keys_for_currency_pound" />
+                latin:moreKeys="!label/more_keys_for_currency_pound" />
             <key-style
                 latin:styleName="moreCurrency1KeyStyle"
                 latin:keyLabel="&#x20AC;" />
diff --git a/java/res/xml/key_styles_currency_dollar.xml b/java/res/xml/key_styles_currency_dollar.xml
index 8dd8498..704970a 100644
--- a/java/res/xml/key_styles_currency_dollar.xml
+++ b/java/res/xml/key_styles_currency_dollar.xml
@@ -26,7 +26,7 @@
     <key-style
         latin:styleName="currencyKeyStyle"
         latin:keyLabel="$"
-        latin:moreKeys="@string/more_keys_for_currency_dollar" />
+        latin:moreKeys="!label/more_keys_for_currency_dollar" />
     <key-style
         latin:styleName="moreCurrency1KeyStyle"
         latin:keyLabel="&#x00A3;" />
diff --git a/java/res/xml/key_styles_currency_euro.xml b/java/res/xml/key_styles_currency_euro.xml
index 0573e09..074d4c0 100644
--- a/java/res/xml/key_styles_currency_euro.xml
+++ b/java/res/xml/key_styles_currency_euro.xml
@@ -26,7 +26,7 @@
     <key-style
         latin:styleName="currencyKeyStyle"
         latin:keyLabel="&#x20AC;"
-        latin:moreKeys="@string/more_keys_for_currency_euro" />
+        latin:moreKeys="!abel/more_keys_for_currency_euro" />
     <key-style
         latin:styleName="moreCurrency1KeyStyle"
         latin:keyLabel="&#x00A3;" />
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index e15a0be..f4c7ad4 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -30,7 +30,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/action_previous_as_more_key" />
+                latin:moreKeys="!label/action_previous_as_more_key" />
         </case>
         <case
             latin:imeAction="actionNext"
@@ -46,7 +46,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/action_next_as_more_key" />
+                latin:moreKeys="!label/action_next_as_more_key" />
         </case>
         <case
             latin:imeAction="actionPrevious"
@@ -63,7 +63,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,@string/action_previous_as_more_key,@string/action_next_as_more_key" />
+                latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!label/action_previous_as_more_key,!label/action_next_as_more_key" />
         </case>
         <case
             latin:navigateNext="true"
@@ -72,7 +72,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/action_next_as_more_key" />
+                latin:moreKeys="!label/action_next_as_more_key" />
         </case>
         <case
             latin:navigateNext="false"
@@ -81,7 +81,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="@string/action_previous_as_more_key" />
+                latin:moreKeys="!label/action_previous_as_more_key" />
         </case>
         <!-- naviagteNext="false" and navigatePrevious="false" -->
         <default>
@@ -92,15 +92,15 @@
     <!-- Enter key style -->
     <key-style
         latin:styleName="defaultEnterKeyStyle"
-        latin:code="@integer/key_enter"
+        latin:code="!code/key_enter"
         latin:keyIcon="iconReturnKey"
-        latin:keyLabelFlags="autoXScale|preserveCase"
+        latin:keyLabelFlags="autoXScale|preserveCase|followKeyLabelRatio"
         latin:keyActionFlags="noKeyPreview"
         latin:backgroundType="functional"
         latin:parentStyle="navigateMoreKeysStyle" />
     <key-style
         latin:styleName="defaultActionKeyStyle"
-        latin:code="@integer/key_action_enter"
+        latin:code="!code/key_action_enter"
         latin:keyIcon="iconUndefined"
         latin:backgroundType="action"
         latin:parentStyle="defaultEnterKeyStyle" />
@@ -119,7 +119,7 @@
         >
             <key-style
                 latin:styleName="enterKeyStyle"
-                latin:keyLabel="@string/label_go_key"
+                latin:keyLabel="!label/label_go_key"
                 latin:parentStyle="defaultActionKeyStyle" />
         </case>
         <case
@@ -127,7 +127,7 @@
         >
             <key-style
                 latin:styleName="enterKeyStyle"
-                latin:keyLabel="@string/label_next_key"
+                latin:keyLabel="!label/label_next_key"
                 latin:parentStyle="defaultActionKeyStyle" />
         </case>
         <case
@@ -135,7 +135,7 @@
         >
             <key-style
                 latin:styleName="enterKeyStyle"
-                latin:keyLabel="@string/label_previous_key"
+                latin:keyLabel="!label/label_previous_key"
                 latin:parentStyle="defaultActionKeyStyle" />
         </case>
         <case
@@ -143,7 +143,7 @@
         >
             <key-style
                 latin:styleName="enterKeyStyle"
-                latin:keyLabel="@string/label_done_key"
+                latin:keyLabel="!label/label_done_key"
                 latin:parentStyle="defaultActionKeyStyle" />
         </case>
         <case
@@ -151,7 +151,7 @@
         >
             <key-style
                 latin:styleName="enterKeyStyle"
-                latin:keyLabel="@string/label_send_key"
+                latin:keyLabel="!label/label_send_key"
                 latin:parentStyle="defaultActionKeyStyle" />
         </case>
         <case
diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml
index 1fc2169..16cfa84 100644
--- a/java/res/xml/key_styles_number.xml
+++ b/java/res/xml/key_styles_number.xml
@@ -26,7 +26,7 @@
         latin:keyActionFlags="noKeyPreview" />
     <key-style
         latin:styleName="numKeyStyle"
-        latin:keyLabelFlags="largeLetter|followKeyLetterRatio"
+        latin:keyLabelFlags="followKeyLargeLetterRatio"
         latin:parentStyle="numKeyBaseStyle" />
     <key-style
         latin:styleName="numModeKeyStyle"
@@ -34,7 +34,7 @@
         latin:parentStyle="numKeyBaseStyle" />
     <key-style
         latin:styleName="numFunctionalKeyStyle"
-        latin:keyLabelFlags="largeLetter|followKeyLetterRatio"
+        latin:keyLabelFlags="followKeyLargeLetterRatio"
         latin:backgroundType="functional"
         latin:parentStyle="numKeyBaseStyle" />
     <key-style
@@ -99,26 +99,26 @@
     <!-- Only for non-tablet device -->
     <key-style
         latin:styleName="numPhoneToSymbolKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_phone_symbols_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_phone_symbols_key"
         latin:parentStyle="numModeKeyStyle" />
     <key-style
         latin:styleName="numPhoneToNumericKeyStyle"
-        latin:code="@integer/key_switch_alpha_symbol"
-        latin:keyLabel="@string/label_to_phone_numeric_key"
+        latin:code="!code/key_switch_alpha_symbol"
+        latin:keyLabel="!label/label_to_phone_numeric_key"
         latin:parentStyle="numModeKeyStyle" />
     <!-- U+002C: "," COMMA -->
     <key-style
         latin:styleName="numPauseKeyStyle"
         latin:code="0x002C"
-        latin:keyLabel="@string/label_pause_key"
+        latin:keyLabel="!label/label_pause_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
     <!-- U+003B: ";" SEMICOLON -->
     <key-style
         latin:styleName="numWaitKeyStyle"
         latin:code="0x003B"
-        latin:keyLabel="@string/label_wait_key"
+        latin:keyLabel="!label/label_wait_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
     <key-style
@@ -127,7 +127,7 @@
         latin:parentStyle="tabKeyStyle" />
     <key-style
         latin:styleName="numSpaceKeyStyle"
-        latin:code="@integer/key_space"
+        latin:code="!code/key_space"
         latin:keyIcon="iconSpaceKeyForNumberLayout"
         latin:keyActionFlags="enableLongPress"
         latin:parentStyle="numKeyBaseStyle" />
diff --git a/java/res/xml/keys_curly_brackets.xml b/java/res/xml/keys_curly_brackets.xml
index d21a092..6a4b1a9 100644
--- a/java/res/xml/keys_curly_brackets.xml
+++ b/java/res/xml/keys_curly_brackets.xml
@@ -23,8 +23,8 @@
 >
     <Key
         latin:keyLabel="{"
-        latin:code="@integer/keycode_for_left_curly_bracket" />
+        latin:code="!code/key_left_curly_bracket" />
     <Key
         latin:keyLabel="}"
-        latin:code="@integer/keycode_for_right_curly_bracket" />
+        latin:code="!code/key_right_curly_bracket" />
 </merge>
diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml
index 8961d9c..7c154cb 100644
--- a/java/res/xml/keys_less_greater.xml
+++ b/java/res/xml/keys_less_greater.xml
@@ -23,10 +23,10 @@
 >
     <Key
         latin:keyLabel="&lt;"
-        latin:code="@integer/keycode_for_less_than"
-        latin:moreKeys="@string/more_keys_for_less_than" />
+        latin:code="!code/key_less_than"
+        latin:moreKeys="!label/more_keys_for_less_than" />
     <Key
         latin:keyLabel="&gt;"
-        latin:code="@integer/keycode_for_greater_than"
-        latin:moreKeys="@string/more_keys_for_greater_than" />
+        latin:code="!code/key_greater_than"
+        latin:moreKeys="!label/more_keys_for_greater_than" />
 </merge>
diff --git a/java/res/xml/keys_parentheses.xml b/java/res/xml/keys_parentheses.xml
index 6853bf1..17d7285 100644
--- a/java/res/xml/keys_parentheses.xml
+++ b/java/res/xml/keys_parentheses.xml
@@ -23,10 +23,10 @@
 >
     <Key
         latin:keyLabel="("
-        latin:code="@integer/keycode_for_left_parenthesis"
-        latin:moreKeys="@string/more_keys_for_left_parenthesis" />
+        latin:code="!code/key_left_parenthesis"
+        latin:moreKeys="!label/more_keys_for_left_parenthesis" />
     <Key
         latin:keyLabel=")"
-        latin:code="@integer/keycode_for_right_parenthesis"
-        latin:moreKeys="@string/more_keys_for_right_parenthesis" />
+        latin:code="!code/key_right_parenthesis"
+        latin:moreKeys="!label/more_keys_for_right_parenthesis" />
 </merge>
diff --git a/java/res/xml/keys_square_brackets.xml b/java/res/xml/keys_square_brackets.xml
index 44387c3..5c128fd 100644
--- a/java/res/xml/keys_square_brackets.xml
+++ b/java/res/xml/keys_square_brackets.xml
@@ -23,8 +23,8 @@
 >
     <Key
         latin:keyLabel="["
-        latin:code="@integer/keycode_for_left_square_bracket" />
+        latin:code="!code/key_left_square_bracket" />
     <Key
         latin:keyLabel="]"
-        latin:code="@integer/keycode_for_right_square_bracket" />
+        latin:code="!code/key_right_square_bracket" />
 </merge>
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index b2b47e9..c085180 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -51,9 +51,9 @@
             <!-- latin:hasShortcutKey="false" -->
             <default>
                 <Key
-                    latin:keyLabel="@string/keylabel_for_comma"
+                    latin:keyLabel="!label/keylabel_for_comma"
                     latin:keyLabelFlags="hasPopupHint"
-                    latin:additionalMoreKeys="@string/more_keys_for_comma"
+                    latin:additionalMoreKeys="!label/more_keys_for_comma"
                     latin:keyStyle="f1MoreKeysStyle" />
             </default>
         </switch>
diff --git a/java/res/xml/rowkeys_azerty1.xml b/java/res/xml/rowkeys_azerty1.xml
index 9983432..50a0162 100644
--- a/java/res/xml/rowkeys_azerty1.xml
+++ b/java/res/xml/rowkeys_azerty1.xml
@@ -25,47 +25,47 @@
         latin:keyLabel="a"
         latin:keyHintLabel="1"
         latin:additionalMoreKeys="1"
-        latin:moreKeys="@string/more_keys_for_a" />
+        latin:moreKeys="!label/more_keys_for_a" />
     <Key
         latin:keyLabel="z"
         latin:keyHintLabel="2"
         latin:additionalMoreKeys="2"
-        latin:moreKeys="@string/more_keys_for_z" />
+        latin:moreKeys="!label/more_keys_for_z" />
     <Key
         latin:keyLabel="e"
         latin:keyHintLabel="3"
         latin:additionalMoreKeys="3"
-        latin:moreKeys="@string/more_keys_for_e" />
+        latin:moreKeys="!label/more_keys_for_e" />
     <Key
         latin:keyLabel="r"
         latin:keyHintLabel="4"
         latin:additionalMoreKeys="4"
-        latin:moreKeys="@string/more_keys_for_r" />
+        latin:moreKeys="!label/more_keys_for_r" />
     <Key
         latin:keyLabel="t"
         latin:keyHintLabel="5"
         latin:additionalMoreKeys="5"
-        latin:moreKeys="@string/more_keys_for_t" />
+        latin:moreKeys="!label/more_keys_for_t" />
     <Key
         latin:keyLabel="y"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6"
-        latin:moreKeys="@string/more_keys_for_y" />
+        latin:moreKeys="!label/more_keys_for_y" />
     <Key
         latin:keyLabel="u"
         latin:keyHintLabel="7"
         latin:additionalMoreKeys="7"
-        latin:moreKeys="@string/more_keys_for_u" />
+        latin:moreKeys="!label/more_keys_for_u" />
     <Key
         latin:keyLabel="i"
         latin:keyHintLabel="8"
         latin:additionalMoreKeys="8"
-        latin:moreKeys="@string/more_keys_for_i" />
+        latin:moreKeys="!label/more_keys_for_i" />
     <Key
         latin:keyLabel="o"
         latin:keyHintLabel="9"
         latin:additionalMoreKeys="9"
-        latin:moreKeys="@string/more_keys_for_o" />
+        latin:moreKeys="!label/more_keys_for_o" />
     <Key
         latin:keyLabel="p"
         latin:keyHintLabel="0"
diff --git a/java/res/xml/rowkeys_azerty2.xml b/java/res/xml/rowkeys_azerty2.xml
index ff0b062..f453c24 100644
--- a/java/res/xml/rowkeys_azerty2.xml
+++ b/java/res/xml/rowkeys_azerty2.xml
@@ -25,27 +25,27 @@
         latin:keyLabel="q" />
     <Key
         latin:keyLabel="s"
-        latin:moreKeys="@string/more_keys_for_s" />
+        latin:moreKeys="!label/more_keys_for_s" />
     <Key
         latin:keyLabel="d"
-        latin:moreKeys="@string/more_keys_for_d" />
+        latin:moreKeys="!label/more_keys_for_d" />
     <Key
         latin:keyLabel="f" />
     <Key
         latin:keyLabel="g"
-        latin:moreKeys="@string/more_keys_for_g" />
+        latin:moreKeys="!label/more_keys_for_g" />
     <Key
         latin:keyLabel="h"
-        latin:moreKeys="@string/more_keys_for_h" />
+        latin:moreKeys="!label/more_keys_for_h" />
     <Key
         latin:keyLabel="j"
-        latin:moreKeys="@string/more_keys_for_j" />
+        latin:moreKeys="!label/more_keys_for_j" />
     <Key
         latin:keyLabel="k"
-        latin:moreKeys="@string/more_keys_for_k" />
+        latin:moreKeys="!label/more_keys_for_k" />
     <Key
         latin:keyLabel="l"
-        latin:moreKeys="@string/more_keys_for_l" />
+        latin:moreKeys="!label/more_keys_for_l" />
     <Key
         latin:keyLabel="m" />
 </merge>
diff --git a/java/res/xml/rowkeys_azerty3.xml b/java/res/xml/rowkeys_azerty3.xml
index b81c3c5..35e9b19 100644
--- a/java/res/xml/rowkeys_azerty3.xml
+++ b/java/res/xml/rowkeys_azerty3.xml
@@ -23,20 +23,20 @@
 >
     <Key
         latin:keyLabel="w"
-        latin:moreKeys="@string/more_keys_for_w" />
+        latin:moreKeys="!label/more_keys_for_w" />
     <Key
         latin:keyLabel="x" />
     <Key
         latin:keyLabel="c"
-        latin:moreKeys="@string/more_keys_for_c" />
+        latin:moreKeys="!label/more_keys_for_c" />
     <Key
         latin:keyLabel="v"
-        latin:moreKeys="@string/more_keys_for_v" />
+        latin:moreKeys="!label/more_keys_for_v" />
     <Key
         latin:keyLabel="b" />
     <Key
         latin:keyLabel="n"
-        latin:moreKeys="@string/more_keys_for_n" />
+        latin:moreKeys="!label/more_keys_for_n" />
     <include
         latin:keyboardLayout="@xml/key_azerty_quote" />
 </merge>
diff --git a/java/res/xml/rowkeys_east_slavic1.xml b/java/res/xml/rowkeys_east_slavic1.xml
index 04c6ef6..dd83c02 100644
--- a/java/res/xml/rowkeys_east_slavic1.xml
+++ b/java/res/xml/rowkeys_east_slavic1.xml
@@ -36,7 +36,7 @@
         latin:keyLabel="&#x0443;"
         latin:keyHintLabel="3"
         latin:additionalMoreKeys="3"
-        latin:moreKeys="@string/more_keys_for_cyrillic_u" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_u" />
     <!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
     <Key
         latin:keyLabel="&#x043A;"
@@ -47,13 +47,13 @@
         latin:keyLabel="&#x0435;"
         latin:keyHintLabel="5"
         latin:additionalMoreKeys="5"
-        latin:moreKeys="@string/more_keys_for_cyrillic_ye" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_ye" />
     <!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
     <Key
         latin:keyLabel="&#x043D;"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6"
-        latin:moreKeys="@string/more_keys_for_cyrillic_en" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_en" />
     <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
     <Key
         latin:keyLabel="&#x0433;"
@@ -65,7 +65,7 @@
         latin:keyHintLabel="8"
         latin:additionalMoreKeys="8" />
     <Key
-        latin:keyLabel="@string/keylabel_for_east_slavic_row1_9"
+        latin:keyLabel="!label/keylabel_for_east_slavic_row1_9"
         latin:keyHintLabel="9"
         latin:additionalMoreKeys="9" />
     <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
@@ -76,5 +76,5 @@
     <!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
     <Key
         latin:keyLabel="&#x0445;"
-        latin:moreKeys="@string/more_keys_for_cyrillic_ha" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_ha" />
 </merge>
diff --git a/java/res/xml/rowkeys_east_slavic2.xml b/java/res/xml/rowkeys_east_slavic2.xml
index 57b0373..75d7d93 100644
--- a/java/res/xml/rowkeys_east_slavic2.xml
+++ b/java/res/xml/rowkeys_east_slavic2.xml
@@ -25,8 +25,8 @@
     <Key
         latin:keyLabel="&#x0444;" />
     <Key
-        latin:keyLabel="@string/keylabel_for_east_slavic_row2_1"
-        latin:moreKeys="@string/more_keys_for_east_slavic_row2_1" />
+        latin:keyLabel="!label/keylabel_for_east_slavic_row2_1"
+        latin:moreKeys="!label/more_keys_for_east_slavic_row2_1" />
     <!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
     <Key
         latin:keyLabel="&#x0432;" />
@@ -42,7 +42,7 @@
     <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
     <Key
         latin:keyLabel="&#x043E;"
-        latin:moreKeys="@string/more_keys_for_cyrillic_o" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_o" />
     <!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
     <Key
         latin:keyLabel="&#x043B;" />
diff --git a/java/res/xml/rowkeys_east_slavic3.xml b/java/res/xml/rowkeys_east_slavic3.xml
index b0f7aed..a05e92d 100644
--- a/java/res/xml/rowkeys_east_slavic3.xml
+++ b/java/res/xml/rowkeys_east_slavic3.xml
@@ -34,14 +34,14 @@
     <Key
         latin:keyLabel="&#x043C;" />
     <Key
-        latin:keyLabel="@string/keylabel_for_east_slavic_row3_5" />
+        latin:keyLabel="!label/keylabel_for_east_slavic_row3_5" />
     <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
     <Key
         latin:keyLabel="&#x0442;" />
     <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN -->
     <Key
         latin:keyLabel="&#x044C;"
-        latin:moreKeys="@string/more_keys_for_cyrillic_soft_sign" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_soft_sign" />
     <!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
     <Key
         latin:keyLabel="&#x0431;" />
diff --git a/java/res/xml/rowkeys_nordic1.xml b/java/res/xml/rowkeys_nordic1.xml
index 056895f..ff29369 100644
--- a/java/res/xml/rowkeys_nordic1.xml
+++ b/java/res/xml/rowkeys_nordic1.xml
@@ -24,5 +24,5 @@
     <include
         latin:keyboardLayout="@xml/rowkeys_qwerty1" />
     <Key
-        latin:keyLabel="@string/keylabel_for_nordic_row1_11" />
+        latin:keyLabel="!label/keylabel_for_nordic_row1_11" />
 </merge>
diff --git a/java/res/xml/rowkeys_nordic2.xml b/java/res/xml/rowkeys_nordic2.xml
index 0033ea1..52bb2f1 100644
--- a/java/res/xml/rowkeys_nordic2.xml
+++ b/java/res/xml/rowkeys_nordic2.xml
@@ -24,9 +24,9 @@
     <include
         latin:keyboardLayout="@xml/rowkeys_qwerty2" />
     <Key
-        latin:keyLabel="@string/keylabel_for_nordic_row2_10"
-        latin:moreKeys="@string/more_keys_for_nordic_row2_10" />
+        latin:keyLabel="!label/keylabel_for_nordic_row2_10"
+        latin:moreKeys="!label/more_keys_for_nordic_row2_10" />
     <Key
-        latin:keyLabel="@string/keylabel_for_nordic_row2_11"
-        latin:moreKeys="@string/more_keys_for_nordic_row2_11" />
+        latin:keyLabel="!label/keylabel_for_nordic_row2_11"
+        latin:moreKeys="!label/more_keys_for_nordic_row2_11" />
 </merge>
diff --git a/java/res/xml/rowkeys_qwerty1.xml b/java/res/xml/rowkeys_qwerty1.xml
index 19067a7..8fb60db 100644
--- a/java/res/xml/rowkeys_qwerty1.xml
+++ b/java/res/xml/rowkeys_qwerty1.xml
@@ -29,42 +29,42 @@
         latin:keyLabel="w"
         latin:keyHintLabel="2"
         latin:additionalMoreKeys="2"
-        latin:moreKeys="@string/more_keys_for_w" />
+        latin:moreKeys="!label/more_keys_for_w" />
     <Key
         latin:keyLabel="e"
         latin:keyHintLabel="3"
         latin:additionalMoreKeys="3"
-        latin:moreKeys="@string/more_keys_for_e" />
+        latin:moreKeys="!label/more_keys_for_e" />
     <Key
         latin:keyLabel="r"
         latin:keyHintLabel="4"
         latin:additionalMoreKeys="4"
-        latin:moreKeys="@string/more_keys_for_r" />
+        latin:moreKeys="!label/more_keys_for_r" />
     <Key
         latin:keyLabel="t"
         latin:keyHintLabel="5"
         latin:additionalMoreKeys="5"
-        latin:moreKeys="@string/more_keys_for_t" />
+        latin:moreKeys="!label/more_keys_for_t" />
     <Key
         latin:keyLabel="y"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6"
-        latin:moreKeys="@string/more_keys_for_y" />
+        latin:moreKeys="!label/more_keys_for_y" />
     <Key
         latin:keyLabel="u"
         latin:keyHintLabel="7"
         latin:additionalMoreKeys="7"
-        latin:moreKeys="@string/more_keys_for_u" />
+        latin:moreKeys="!label/more_keys_for_u" />
     <Key
         latin:keyLabel="i"
         latin:keyHintLabel="8"
         latin:additionalMoreKeys="8"
-        latin:moreKeys="@string/more_keys_for_i" />
+        latin:moreKeys="!label/more_keys_for_i" />
     <Key
         latin:keyLabel="o"
         latin:keyHintLabel="9"
         latin:additionalMoreKeys="9"
-        latin:moreKeys="@string/more_keys_for_o" />
+        latin:moreKeys="!label/more_keys_for_o" />
     <Key
         latin:keyLabel="p"
         latin:keyHintLabel="0"
diff --git a/java/res/xml/rowkeys_qwerty2.xml b/java/res/xml/rowkeys_qwerty2.xml
index 2fa8214..a29f331 100644
--- a/java/res/xml/rowkeys_qwerty2.xml
+++ b/java/res/xml/rowkeys_qwerty2.xml
@@ -23,28 +23,28 @@
 >
     <Key
         latin:keyLabel="a"
-        latin:moreKeys="@string/more_keys_for_a" />
+        latin:moreKeys="!label/more_keys_for_a" />
     <Key
         latin:keyLabel="s"
-        latin:moreKeys="@string/more_keys_for_s" />
+        latin:moreKeys="!label/more_keys_for_s" />
     <Key
         latin:keyLabel="d"
-        latin:moreKeys="@string/more_keys_for_d" />
+        latin:moreKeys="!label/more_keys_for_d" />
     <Key
         latin:keyLabel="f" />
     <Key
         latin:keyLabel="g"
-        latin:moreKeys="@string/more_keys_for_g" />
+        latin:moreKeys="!label/more_keys_for_g" />
     <Key
         latin:keyLabel="h"
-        latin:moreKeys="@string/more_keys_for_h" />
+        latin:moreKeys="!label/more_keys_for_h" />
     <Key
         latin:keyLabel="j"
-        latin:moreKeys="@string/more_keys_for_j" />
+        latin:moreKeys="!label/more_keys_for_j" />
     <Key
         latin:keyLabel="k"
-        latin:moreKeys="@string/more_keys_for_k" />
+        latin:moreKeys="!label/more_keys_for_k" />
     <Key
         latin:keyLabel="l"
-        latin:moreKeys="@string/more_keys_for_l" />
+        latin:moreKeys="!label/more_keys_for_l" />
 </merge>
diff --git a/java/res/xml/rowkeys_qwerty3.xml b/java/res/xml/rowkeys_qwerty3.xml
index 932ea6f..afe43f6 100644
--- a/java/res/xml/rowkeys_qwerty3.xml
+++ b/java/res/xml/rowkeys_qwerty3.xml
@@ -23,20 +23,20 @@
 >
     <Key
         latin:keyLabel="z"
-        latin:moreKeys="@string/more_keys_for_z" />
+        latin:moreKeys="!label/more_keys_for_z" />
     <Key
         latin:keyLabel="x" />
     <Key
         latin:keyLabel="c"
-        latin:moreKeys="@string/more_keys_for_c" />
+        latin:moreKeys="!label/more_keys_for_c" />
     <Key
         latin:keyLabel="v"
-        latin:moreKeys="@string/more_keys_for_v" />
+        latin:moreKeys="!label/more_keys_for_v" />
     <Key
         latin:keyLabel="b" />
     <Key
         latin:keyLabel="n"
-        latin:moreKeys="@string/more_keys_for_n" />
+        latin:moreKeys="!label/more_keys_for_n" />
     <Key
         latin:keyLabel="m" />
 </merge>
diff --git a/java/res/xml/rowkeys_qwertz1.xml b/java/res/xml/rowkeys_qwertz1.xml
index 3e11a7a..1278896 100644
--- a/java/res/xml/rowkeys_qwertz1.xml
+++ b/java/res/xml/rowkeys_qwertz1.xml
@@ -29,42 +29,42 @@
         latin:keyLabel="w"
         latin:keyHintLabel="2"
         latin:additionalMoreKeys="2"
-        latin:moreKeys="@string/more_keys_for_w" />
+        latin:moreKeys="!label/more_keys_for_w" />
     <Key
         latin:keyLabel="e"
         latin:keyHintLabel="3"
         latin:additionalMoreKeys="3"
-        latin:moreKeys="@string/more_keys_for_e" />
+        latin:moreKeys="!label/more_keys_for_e" />
     <Key
         latin:keyLabel="r"
         latin:keyHintLabel="4"
         latin:additionalMoreKeys="4"
-        latin:moreKeys="@string/more_keys_for_r" />
+        latin:moreKeys="!label/more_keys_for_r" />
     <Key
         latin:keyLabel="t"
         latin:keyHintLabel="5"
         latin:additionalMoreKeys="5"
-        latin:moreKeys="@string/more_keys_for_t" />
+        latin:moreKeys="!label/more_keys_for_t" />
     <Key
         latin:keyLabel="z"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6"
-        latin:moreKeys="@string/more_keys_for_z" />
+        latin:moreKeys="!label/more_keys_for_z" />
      <Key
         latin:keyLabel="u"
         latin:keyHintLabel="7"
         latin:additionalMoreKeys="7"
-        latin:moreKeys="@string/more_keys_for_u" />
+        latin:moreKeys="!label/more_keys_for_u" />
     <Key
         latin:keyLabel="i"
         latin:keyHintLabel="8"
         latin:additionalMoreKeys="8"
-        latin:moreKeys="@string/more_keys_for_i" />
+        latin:moreKeys="!label/more_keys_for_i" />
     <Key
         latin:keyLabel="o"
         latin:keyHintLabel="9"
         latin:additionalMoreKeys="9"
-        latin:moreKeys="@string/more_keys_for_o" />
+        latin:moreKeys="!label/more_keys_for_o" />
     <Key
         latin:keyLabel="p"
         latin:keyHintLabel="0"
diff --git a/java/res/xml/rowkeys_qwertz3.xml b/java/res/xml/rowkeys_qwertz3.xml
index d37cee6..e969665 100644
--- a/java/res/xml/rowkeys_qwertz3.xml
+++ b/java/res/xml/rowkeys_qwertz3.xml
@@ -23,20 +23,20 @@
 >
     <Key
         latin:keyLabel="y"
-        latin:moreKeys="@string/more_keys_for_y" />
+        latin:moreKeys="!label/more_keys_for_y" />
     <Key
         latin:keyLabel="x" />
     <Key
         latin:keyLabel="c"
-        latin:moreKeys="@string/more_keys_for_c" />
+        latin:moreKeys="!label/more_keys_for_c" />
     <Key
         latin:keyLabel="v"
-        latin:moreKeys="@string/more_keys_for_v" />
+        latin:moreKeys="!label/more_keys_for_v" />
     <Key
         latin:keyLabel="b" />
     <Key
         latin:keyLabel="n"
-        latin:moreKeys="@string/more_keys_for_n" />
+        latin:moreKeys="!label/more_keys_for_n" />
     <Key
         latin:keyLabel="m" />
 </merge>
diff --git a/java/res/xml/rowkeys_south_slavic1.xml b/java/res/xml/rowkeys_south_slavic1.xml
index e3cb89c..7c9a3bc 100644
--- a/java/res/xml/rowkeys_south_slavic1.xml
+++ b/java/res/xml/rowkeys_south_slavic1.xml
@@ -36,7 +36,7 @@
         latin:keyLabel="&#x0435;"
         latin:keyHintLabel="3"
         latin:additionalMoreKeys="3"
-        latin:moreKeys="@string/more_keys_for_cyrillic_ie" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_ie" />
     <!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
     <Key
         latin:keyLabel="&#x0440;"
@@ -48,7 +48,7 @@
         latin:keyHintLabel="5"
         latin:additionalMoreKeys="5" />
     <Key
-        latin:keyLabel="@string/keylabel_for_south_slavic_row1_6"
+        latin:keyLabel="!label/keylabel_for_south_slavic_row1_6"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6" />
     <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
@@ -61,7 +61,7 @@
         latin:keyLabel="&#x0438;"
         latin:keyHintLabel="8"
         latin:additionalMoreKeys="8"
-        latin:moreKeys="@string/more_keys_for_cyrillic_i" />
+        latin:moreKeys="!label/more_keys_for_cyrillic_i" />
     <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
     <Key
         latin:keyLabel="&#x043E;"
diff --git a/java/res/xml/rowkeys_south_slavic2.xml b/java/res/xml/rowkeys_south_slavic2.xml
index 5a7ecd4..e489208 100644
--- a/java/res/xml/rowkeys_south_slavic2.xml
+++ b/java/res/xml/rowkeys_south_slavic2.xml
@@ -52,5 +52,5 @@
     <Key
         latin:keyLabel="&#x0447;" />
     <Key
-        latin:keyLabel="@string/keylabel_for_south_slavic_row2_11" />
+        latin:keyLabel="!label/keylabel_for_south_slavic_row2_11" />
 </merge>
diff --git a/java/res/xml/rowkeys_south_slavic3.xml b/java/res/xml/rowkeys_south_slavic3.xml
index 97ff51e..d668ddf 100644
--- a/java/res/xml/rowkeys_south_slavic3.xml
+++ b/java/res/xml/rowkeys_south_slavic3.xml
@@ -22,7 +22,7 @@
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
     <Key
-        latin:keyLabel="@string/keylabel_for_south_slavic_row3_1" />
+        latin:keyLabel="!label/keylabel_for_south_slavic_row3_1" />
     <!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE -->
     <Key
         latin:keyLabel="&#x045F;" />
@@ -42,7 +42,7 @@
     <Key
         latin:keyLabel="&#x043C;" />
     <Key
-        latin:keyLabel="@string/keylabel_for_south_slavic_row3_8" />
+        latin:keyLabel="!label/keylabel_for_south_slavic_row3_8" />
     <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
     <Key
         latin:keyLabel="&#x0436;" />
diff --git a/java/res/xml/rowkeys_symbols1.xml b/java/res/xml/rowkeys_symbols1.xml
index f6d6243..f9f8bb1 100644
--- a/java/res/xml/rowkeys_symbols1.xml
+++ b/java/res/xml/rowkeys_symbols1.xml
@@ -22,43 +22,43 @@
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_1"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_1"
-        latin:moreKeys="@string/more_keys_for_symbols_1" />
+        latin:keyLabel="!label/keylabel_for_symbols_1"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_1"
+        latin:moreKeys="!label/more_keys_for_symbols_1" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_2"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_2"
-        latin:moreKeys="@string/more_keys_for_symbols_2" />
+        latin:keyLabel="!label/keylabel_for_symbols_2"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_2"
+        latin:moreKeys="!label/more_keys_for_symbols_2" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_3"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_3"
-        latin:moreKeys="@string/more_keys_for_symbols_3" />
+        latin:keyLabel="!label/keylabel_for_symbols_3"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_3"
+        latin:moreKeys="!label/more_keys_for_symbols_3" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_4"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_4"
-        latin:moreKeys="@string/more_keys_for_symbols_4" />
+        latin:keyLabel="!label/keylabel_for_symbols_4"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_4"
+        latin:moreKeys="!label/more_keys_for_symbols_4" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_5"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_5"
-        latin:moreKeys="@string/more_keys_for_symbols_5" />
+        latin:keyLabel="!label/keylabel_for_symbols_5"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_5"
+        latin:moreKeys="!label/more_keys_for_symbols_5" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_6"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_6"
-        latin:moreKeys="@string/more_keys_for_symbols_6" />
+        latin:keyLabel="!label/keylabel_for_symbols_6"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_6"
+        latin:moreKeys="!label/more_keys_for_symbols_6" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_7"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_7"
-        latin:moreKeys="@string/more_keys_for_symbols_7" />
+        latin:keyLabel="!label/keylabel_for_symbols_7"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_7"
+        latin:moreKeys="!label/more_keys_for_symbols_7" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_8"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_8"
-        latin:moreKeys="@string/more_keys_for_symbols_8" />
+        latin:keyLabel="!label/keylabel_for_symbols_8"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_8"
+        latin:moreKeys="!label/more_keys_for_symbols_8" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_9"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_9"
-        latin:moreKeys="@string/more_keys_for_symbols_9" />
+        latin:keyLabel="!label/keylabel_for_symbols_9"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_9"
+        latin:moreKeys="!label/more_keys_for_symbols_9" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_0"
-        latin:additionalMoreKeys="@string/additional_more_keys_for_symbols_0"
-        latin:moreKeys="@string/more_keys_for_symbols_0" />
+        latin:keyLabel="!label/keylabel_for_symbols_0"
+        latin:additionalMoreKeys="!label/additional_more_keys_for_symbols_0"
+        latin:moreKeys="!label/more_keys_for_symbols_0" />
 </merge>
diff --git a/java/res/xml/rowkeys_symbols2.xml b/java/res/xml/rowkeys_symbols2.xml
index 1092421..47865a9 100644
--- a/java/res/xml/rowkeys_symbols2.xml
+++ b/java/res/xml/rowkeys_symbols2.xml
@@ -28,21 +28,21 @@
     <Key
         latin:keyStyle="currencyKeyStyle" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_percent"
-        latin:moreKeys="@string/more_keys_for_symbols_percent" />
+        latin:keyLabel="!label/keylabel_for_symbols_percent"
+        latin:moreKeys="!label/more_keys_for_symbols_percent" />
     <Key
         latin:keyLabel="&amp;" />
     <Key
         latin:keyLabel="*"
-        latin:moreKeys="@string/more_keys_for_star" />
+        latin:moreKeys="!label/more_keys_for_star" />
     <!-- U+2013: "–" EN DASH
-             U+2014: "—" EM DASH -->
+         U+2014: "—" EM DASH -->
     <Key
         latin:keyLabel="-"
         latin:moreKeys="_,&#x2013;,&#x2014;" />
     <Key
         latin:keyLabel="+"
-        latin:moreKeys="@string/more_keys_for_plus" />
+        latin:moreKeys="!label/more_keys_for_plus" />
     <include
         latin:keyboardLayout="@xml/keys_parentheses" />
 </merge>
diff --git a/java/res/xml/rowkeys_symbols3.xml b/java/res/xml/rowkeys_symbols3.xml
index 1a484d4..4cef6b2 100644
--- a/java/res/xml/rowkeys_symbols3.xml
+++ b/java/res/xml/rowkeys_symbols3.xml
@@ -31,20 +31,20 @@
         latin:moreKeys="&#x00A1;" />
     <Key
         latin:keyLabel="&quot;"
-        latin:moreKeys="@string/more_keys_for_double_quote" />
+        latin:moreKeys="!label/more_keys_for_double_quote" />
     <Key
         latin:keyLabel="\'"
-        latin:moreKeys="@string/more_keys_for_single_quote" />
+        latin:moreKeys="!label/more_keys_for_single_quote" />
     <Key
         latin:keyLabel=":" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_semicolon"
-        latin:moreKeys="@string/more_keys_for_symbols_semicolon" />
+        latin:keyLabel="!label/keylabel_for_symbols_semicolon"
+        latin:moreKeys="!label/more_keys_for_symbols_semicolon" />
     <Key
         latin:keyLabel="/" />
     <Key
-        latin:keyLabel="@string/keylabel_for_symbols_question"
-        latin:moreKeys="@string/more_keys_for_symbols_question" />
+        latin:keyLabel="!label/keylabel_for_symbols_question"
+        latin:moreKeys="!label/more_keys_for_symbols_question" />
     <Key
         latin:keyStyle="deleteKeyStyle"
         latin:keyWidth="fillRight"
diff --git a/java/res/xml/rowkeys_symbols_shift1.xml b/java/res/xml/rowkeys_symbols_shift1.xml
index cc00aeb..af3e87e 100644
--- a/java/res/xml/rowkeys_symbols_shift1.xml
+++ b/java/res/xml/rowkeys_symbols_shift1.xml
@@ -30,7 +30,7 @@
     <!-- U+2022: "•" BULLET -->
     <Key
         latin:keyLabel="&#x2022;"
-        latin:moreKeys="@string/more_keys_for_bullet" />
+        latin:moreKeys="!label/more_keys_for_bullet" />
     <!-- U+221A: "√" SQUARE ROOT -->
     <Key
         latin:keyLabel="&#x221A;" />
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index 6f9429c..7015bb2 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -61,7 +61,7 @@
                 <Key
                     latin:keyLabel="."
                     latin:keyLabelFlags="hasPopupHint"
-                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:moreKeys="!label/more_keys_for_am_pm"
                     latin:keyStyle="numFunctionalKeyStyle"
                     latin:keyWidth="fillRight" />
             </case>
diff --git a/java/res/xml/rows_symbols4.xml b/java/res/xml/rows_symbols4.xml
index 3e26650..de7e043 100644
--- a/java/res/xml/rows_symbols4.xml
+++ b/java/res/xml/rows_symbols4.xml
@@ -37,9 +37,9 @@
             <!-- latin:hasShortcutKey="false" -->
             <default>
                 <Key
-                    latin:keyLabel="@string/keylabel_for_comma"
+                    latin:keyLabel="!label/keylabel_for_comma"
                     latin:keyLabelFlags="hasPopupHint"
-                    latin:additionalMoreKeys="@string/more_keys_for_comma"
+                    latin:additionalMoreKeys="!label/more_keys_for_comma"
                     latin:keyStyle="f1MoreKeysStyle" />
             </default>
         </switch>
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 0a2b010..fa7ec5c 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -26,6 +26,7 @@
 import android.util.Xml;
 
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
 import com.android.inputmethod.keyboard.internal.KeyStyles;
 import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
@@ -59,10 +60,12 @@
     private static final int LABEL_FLAGS_ALIGN_LEFT = 0x01;
     private static final int LABEL_FLAGS_ALIGN_RIGHT = 0x02;
     private static final int LABEL_FLAGS_ALIGN_LEFT_OF_CENTER = 0x08;
-    private static final int LABEL_FLAGS_LARGE_LETTER = 0x10;
-    private static final int LABEL_FLAGS_FONT_NORMAL = 0x20;
-    private static final int LABEL_FLAGS_FONT_MONO_SPACE = 0x40;
-    public static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80;
+    private static final int LABEL_FLAGS_FONT_NORMAL = 0x10;
+    private static final int LABEL_FLAGS_FONT_MONO_SPACE = 0x20;
+    private static final int LABEL_FLAGS_FOLLOW_KEY_RATIO_MASK = 0x1C0;
+    private static final int LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO = 0x40;
+    private static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80;
+    private static final int LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO = 0xC0;
     private static final int LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100;
     private static final int LABEL_FLAGS_HAS_POPUP_HINT = 0x200;
     private static final int LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT = 0x400;
@@ -104,7 +107,7 @@
     /** Text to output when pressed. This can be multiple characters, like ".com" */
     public final CharSequence mOutputText;
     /** More keys */
-    public final String[] mMoreKeys;
+    public final MoreKeySpec[] mMoreKeys;
     /** More keys column number and flags */
     private final int mMoreKeysColumnAndFlags;
     private static final int MORE_KEYS_COLUMN_MASK = 0x000000ff;
@@ -140,15 +143,12 @@
     private boolean mEnabled = true;
 
     /**
-     * This constructor is being used only for key in more keys keyboard.
+     * This constructor is being used only for keys in more keys keyboard.
      */
-    public Key(Resources res, Keyboard.Params params, String moreKeySpec,
-            int x, int y, int width, int height, int labelFlags) {
-        this(params, KeySpecParser.getLabel(moreKeySpec), null,
-                KeySpecParser.getIconId(moreKeySpec),
-                KeySpecParser.getCode(res, moreKeySpec),
-                KeySpecParser.getOutputText(moreKeySpec),
-                x, y, width, height, labelFlags);
+    public Key(Keyboard.Params params, MoreKeySpec moreKeySpec, int x, int y, int width, int height,
+            int labelFlags) {
+        this(params, moreKeySpec.mLabel, null, moreKeySpec.mIconId, moreKeySpec.mCode,
+                moreKeySpec.mOutputText, x, y, width, height, labelFlags);
     }
 
     /**
@@ -191,11 +191,11 @@
      * @param row the row that this key belongs to. row's x-coordinate will be the right edge of
      *        this key.
      * @param parser the XML parser containing the attributes for this key
-     * @param keyStyles active key styles set
      * @throws XmlPullParserException
      */
     public Key(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
-            XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
+            XmlPullParser parser) throws XmlPullParserException {
+        final KeyStyles keyStyles = params.mKeyStyles;
         final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
         final int keyHeight = row.mRowHeight;
         mVerticalGap = params.mVerticalGap;
@@ -212,7 +212,7 @@
                 throw new XmlParseUtils.ParseException(
                         "Unknown key style: " + styleName, parser);
         } else {
-            style = KeyStyles.getEmptyKeyStyle();
+            style = keyStyles.getEmptyKeyStyle();
         }
 
         final float keyXPos = row.getKeyX(keyAttr);
@@ -278,13 +278,15 @@
         moreKeys = KeySpecParser.insertAddtionalMoreKeys(moreKeys, additionalMoreKeys);
         if (moreKeys != null) {
             actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
+            mMoreKeys = new MoreKeySpec[moreKeys.length];
             for (int i = 0; i < moreKeys.length; i++) {
-                moreKeys[i] = adjustCaseOfStringForKeyboardId(
-                        moreKeys[i], preserveCase, params.mId);
+                mMoreKeys[i] = new MoreKeySpec(adjustCaseOfStringForKeyboardId(
+                        moreKeys[i], preserveCase, params.mId), params.mCodesSet);
             }
+        } else {
+            mMoreKeys = null;
         }
         mActionFlags = actionFlags;
-        mMoreKeys = moreKeys;
 
         if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) {
             mLabel = params.mId.mCustomActionLabel;
@@ -300,8 +302,9 @@
         }
         String outputText = adjustCaseOfStringForKeyboardId(style.getString(
                 keyAttr, R.styleable.Keyboard_Key_keyOutputText), preserveCase, params.mId);
-        final int code = style.getInt(
-                keyAttr, R.styleable.Keyboard_Key_code, Keyboard.CODE_UNSPECIFIED);
+        final int code = KeySpecParser.parseCode(style.getString(
+                keyAttr, R.styleable.Keyboard_Key_code),
+                params.mCodesSet, Keyboard.CODE_UNSPECIFIED);
         // Choose the first letter of the label as primary code if not specified.
         if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText)
                 && !TextUtils.isEmpty(mLabel)) {
@@ -331,9 +334,10 @@
             mCode = adjustCaseOfCodeForKeyboardId(code, preserveCase, params.mId);
         }
         mOutputText = outputText;
-        mAltCode = adjustCaseOfCodeForKeyboardId(style.getInt(keyAttr,
-                R.styleable.Keyboard_Key_altCode, Keyboard.CODE_UNSPECIFIED), preserveCase,
-                params.mId);
+        mAltCode = adjustCaseOfCodeForKeyboardId(KeySpecParser.parseCode(style.getString(
+                keyAttr, R.styleable.Keyboard_Key_altCode),
+                params.mCodesSet, Keyboard.CODE_UNSPECIFIED),
+                preserveCase, params.mId);
         mHashCode = computeHashCode(this);
 
         keyAttr.recycle();
@@ -496,16 +500,17 @@
     }
 
     public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) {
-        if (StringUtils.codePointCount(mLabel) > 1
-                && (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
-                        | LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) {
-            return label;
-        } else if ((mLabelFlags & LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO) != 0) {
-            return hintLabel;
-        } else if ((mLabelFlags & LABEL_FLAGS_LARGE_LETTER) != 0) {
+        switch (mLabelFlags & LABEL_FLAGS_FOLLOW_KEY_RATIO_MASK) {
+        case LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO:
             return largeLetter;
-        } else {
+        case LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO:
             return letter;
+        case LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO:
+            return label;
+        case LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO:
+            return hintLabel;
+        default: // No follow key ratio flag specified.
+            return StringUtils.codePointCount(mLabel) == 1 ? letter : label;
         }
     }
 
@@ -561,6 +566,12 @@
         return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_HAS_LABELS) != 0;
     }
 
+    public int getMoreKeyLabelFlags() {
+        return hasLabelsInMoreKeys()
+                ? LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO
+                : LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO;
+    }
+
     public boolean needsDividersInMoreKeys() {
         return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NEEDS_DIVIDERS) != 0;
     }
@@ -707,8 +718,8 @@
 
     public static class Spacer extends Key {
         public Spacer(Resources res, Keyboard.Params params, Keyboard.Builder.Row row,
-                XmlPullParser parser, KeyStyles keyStyles) throws XmlPullParserException {
-            super(res, params, row, parser, keyStyles);
+                XmlPullParser parser) throws XmlPullParserException {
+            super(res, params, row, parser);
         }
 
         /**
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 950b5e9..58225e9 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -28,9 +28,13 @@
 import android.view.InflateException;
 
 import com.android.inputmethod.keyboard.internal.KeyStyles;
+import com.android.inputmethod.keyboard.internal.KeyboardCodesSet;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.KeyboardLabelsSet;
 import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeLocale;
 import com.android.inputmethod.latin.Utils;
 import com.android.inputmethod.latin.XmlParseUtils;
 
@@ -42,6 +46,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Locale;
 
 /**
  * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
@@ -238,6 +243,9 @@
         public final ArrayList<Key> mShiftKeys = new ArrayList<Key>();
         public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<Key>();
         public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
+        public final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
+        public final KeyboardLabelsSet mLabelsSet = new KeyboardLabelsSet();
+        public final KeyStyles mKeyStyles = new KeyStyles(mLabelsSet);
 
         public KeyboardLayoutSet.KeysCache mKeysCache;
 
@@ -498,7 +506,6 @@
         private boolean mLeftEdge;
         private boolean mTopEdge;
         private Key mRightEdgeKey = null;
-        private final KeyStyles mKeyStyles = new KeyStyles();
 
         /**
          * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
@@ -775,6 +782,20 @@
 
                 params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0);
                 params.mIconsSet.loadIcons(keyboardAttr);
+                final String language = params.mId.mLocale.getLanguage();
+                params.mCodesSet.setLanguage(language);
+                params.mLabelsSet.setLanguage(language);
+                final RunInLocale<Void> job = new RunInLocale<Void>() {
+                    @Override
+                    protected Void job(Resources res) {
+                        params.mLabelsSet.loadStringResources(mContext);
+                        return null;
+                    }
+                };
+                // Null means the current system locale.
+                final Locale locale = language.equals(SubtypeLocale.NO_LANGUAGE)
+                        ? null : params.mId.mLocale;
+                job.runInLocale(mResources, locale);
 
                 final int resourceId = keyboardAttr.getResourceId(
                         R.styleable.Keyboard_touchPositionCorrectionData, 0);
@@ -884,7 +905,7 @@
                 XmlParseUtils.checkEndTag(TAG_KEY, parser);
                 if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY);
             } else {
-                final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
+                final Key key = new Key(mResources, mParams, row, parser);
                 if (DEBUG) {
                     startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY,
                             (key.isEnabled() ? "" : " disabled"), key,
@@ -901,8 +922,7 @@
                 XmlParseUtils.checkEndTag(TAG_SPACER, parser);
                 if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER);
             } else {
-                final Key.Spacer spacer = new Key.Spacer(
-                        mResources, mParams, row, parser, mKeyStyles);
+                final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser);
                 if (DEBUG) startEndTag("<%s />", TAG_SPACER);
                 XmlParseUtils.checkEndTag(TAG_SPACER, parser);
                 endKey(spacer);
@@ -1207,7 +1227,7 @@
                         skip ? " skipped" : "");
                 }
                 if (!skip)
-                    mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
+                    mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
             } finally {
                 keyStyleAttr.recycle();
                 keyAttrs.recycle();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 51cd905..803a294 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -29,12 +29,10 @@
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams;
-import com.android.inputmethod.keyboard.internal.KeySpecParser;
 import com.android.inputmethod.latin.InputTypeUtils;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
@@ -65,9 +63,7 @@
 
     private static final String DEFAULT_KEYBOARD_LAYOUT_SET = "qwerty";
     private static final char KEYBOARD_LAYOUT_SET_LOCALE_DELIMITER = ':';
-    private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "xml/keyboard_layout_set_";
-    private static final int DEFAULT_KEYBOARD_LAYOUT_SET_RESOURCE_ID =
-            R.xml.keyboard_layout_set_qwerty;
+    private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_";
 
     private final Context mContext;
     private final Params mParams;
@@ -185,14 +181,7 @@
                 builder.setAutoGenerate(sKeysCache);
             }
             final int keyboardXmlId = elementParams.mKeyboardXmlId;
-            final RunInLocale<Void> job = new RunInLocale<Void>() {
-                @Override
-                protected Void job(Resources res) {
-                    builder.load(keyboardXmlId, id);
-                    return null;
-                }
-            };
-            job.runInLocale(context.getResources(), id.mLocale);
+            builder.load(keyboardXmlId, id);
             builder.setTouchPositionCorrectionEnabled(mParams.mTouchPositionCorrectionEnabled);
             builder.setProximityCharsCorrectionEnabled(
                     elementParams.mProximityCharsCorrectionEnabled);
@@ -319,21 +308,15 @@
                 throw new RuntimeException("Screen geometry is not specified");
             if (mParams.mLocale == null)
                 throw new RuntimeException("KeyboardLayoutSet subtype is not specified");
+            final String packageName = mResources.getResourcePackageName(
+                    R.xml.keyboard_layout_set_qwerty);
             final String keyboardLayoutSetName = mParams.mKeyboardLayoutSetName;
-            final int xmlId = KeySpecParser.getResourceId(
-                    mResources, keyboardLayoutSetName, DEFAULT_KEYBOARD_LAYOUT_SET_RESOURCE_ID);
-            final RunInLocale<Void> job = new RunInLocale<Void>() {
-                @Override
-                protected Void job(Resources res) {
-                    try {
-                        parseKeyboardLayoutSet(res, xmlId);
-                    } catch (Exception e) {
-                        throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName);
-                    }
-                    return null;
-                }
-            };
-            job.runInLocale(mResources, mParams.mLocale);
+            final int xmlId = mResources.getIdentifier(keyboardLayoutSetName, "xml", packageName);
+            try {
+                parseKeyboardLayoutSet(mResources, xmlId);
+            } catch (Exception e) {
+                throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName);
+            }
             return new KeyboardLayoutSet(mContext, mParams);
         }
 
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 98da1eb..5ebf92c 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -41,7 +41,6 @@
 import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
 import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
-import com.android.inputmethod.keyboard.internal.KeySpecParser;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
@@ -560,7 +559,7 @@
         }
         final int primaryCode = parentKey.mCode;
         if (parentKey.hasEmbeddedMoreKey()) {
-            final int embeddedCode = KeySpecParser.getCode(getResources(), parentKey.mMoreKeys[0]);
+            final int embeddedCode = parentKey.mMoreKeys[0].mCode;
             tracker.onLongPressed();
             invokeCodeInput(embeddedCode);
             invokeReleaseKey(primaryCode);
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 72a5d0f..7154086 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -19,7 +19,7 @@
 import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
 
-import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StringUtils;
@@ -301,8 +301,8 @@
                     ? view.mKeyDrawParams.mKeyLabelSize
                     : view.mKeyDrawParams.mKeyLetterSize);
             int maxWidth = minKeyWidth;
-            for (String moreKeySpec : parentKey.mMoreKeys) {
-                final String label = KeySpecParser.getLabel(moreKeySpec);
+            for (final MoreKeySpec spec : parentKey.mMoreKeys) {
+                final String label = spec.mLabel;
                 // If the label is single letter, minKeyWidth is enough to hold the label.
                 if (label != null && StringUtils.codePointCount(label) > 1) {
                     final int width = (int)view.getLabelWidth(label, paint) + padding;
@@ -332,17 +332,14 @@
         @Override
         public MoreKeysKeyboard build() {
             final MoreKeysKeyboardParams params = mParams;
-            // moreKeyFlags == 0 means that the rendered text size will be determined by its
-            // label's code point count.
-            final int moreKeyFlags = mParentKey.hasLabelsInMoreKeys() ? 0
-                    : Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO;
-            final String[] moreKeys = mParentKey.mMoreKeys;
+            final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags();
+            final MoreKeySpec[] moreKeys = mParentKey.mMoreKeys;
             for (int n = 0; n < moreKeys.length; n++) {
-                final String moreKeySpec = moreKeys[n];
+                final MoreKeySpec moreKeySpec = moreKeys[n];
                 final int row = n / params.mNumColumns;
                 final int x = params.getX(n, row);
                 final int y = params.getY(row);
-                final Key key = new Key(mResources, params, moreKeySpec, x, y,
+                final Key key = new Key(params, moreKeySpec, x, y,
                         params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags);
                 params.markAsEdgeKey(key, row);
                 params.onAddKey(key);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 4abd887..2981a8e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -16,28 +16,30 @@
 
 package com.android.inputmethod.keyboard.internal;
 
-import android.content.res.Resources;
 import android.text.TextUtils;
 
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 
 /**
- * String parser of moreKeys attribute of Key.
- * The string is comma separated texts each of which represents one "more key".
- * - String resource can be embedded into specification @string/name. This is done before parsing
- *   comma.
+ * The string parser of more keys specification.
+ * The specification is comma separated texts each of which represents one "more key".
+ * The specification might have label or string resource reference in it. These references are
+ * expanded before parsing comma.
+ * - Label reference should be a string representation of label (!label/label_name)
+ * - String resource reference should be a string representation of resource (!label/resource_name)
  * Each "more key" specification is one of the following:
- * - A single letter (Letter)
  * - Label optionally followed by keyOutputText or code (keyLabel|keyOutputText).
- * - Icon followed by keyOutputText or code (@icon/icon_name|@integer/key_code)
+ * - Icon followed by keyOutputText or code (!icon/icon_name|!code/code_name)
+ *   - Icon should be a string representation of icon (!icon/icon_name).
+ *   - Code should be a code point presented by hexadecimal string prefixed with "0x", or a string
+ *     representation of code (!code/code_name).
  * Special character, comma ',' backslash '\', and bar '|' can be escaped by '\' character.
- * Note that the character '@' and '\' are also parsed by XML parser and CSV parser as well.
+ * Note that the '\' is also parsed by XML parser and CSV parser as well.
  * See {@link KeyboardIconsSet} about icon_name.
  */
 public class KeySpecParser {
@@ -48,14 +50,27 @@
     // Constants for parsing.
     private static int COMMA = ',';
     private static final char ESCAPE_CHAR = '\\';
-    private static final char PREFIX_AT = '@';
-    private static final char SUFFIX_SLASH = '/';
-    private static final String PREFIX_STRING = PREFIX_AT + "string" + SUFFIX_SLASH;
     private static final char LABEL_END = '|';
-    private static final String PREFIX_ICON = PREFIX_AT + "icon" + SUFFIX_SLASH;
-    private static final String PREFIX_CODE = PREFIX_AT + "integer" + SUFFIX_SLASH;
+    private static final String PREFIX_LABEL = "!label/";
+    private static final String PREFIX_ICON = "!icon/";
+    private static final String PREFIX_CODE = "!code/";
+    private static final String PREFIX_HEX = "0x";
     private static final String ADDITIONAL_MORE_KEY_MARKER = "%";
 
+    public static class MoreKeySpec {
+        public final int mCode;
+        public final String mLabel;
+        public final String mOutputText;
+        public final int mIconId;
+
+        public MoreKeySpec(final String moreKeySpec, final KeyboardCodesSet codesSet) {
+            mCode = getCode(moreKeySpec, codesSet);
+            mLabel = getLabel(moreKeySpec);
+            mOutputText = getOutputText(moreKeySpec);
+            mIconId = getIconId(moreKeySpec);
+        }
+    }
+
     private KeySpecParser() {
         // Intentional empty constructor for utility class.
     }
@@ -144,7 +159,7 @@
         return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1));
     }
 
-    public static String getOutputText(String moreKeySpec) {
+    private static String getOutputText(String moreKeySpec) {
         if (hasCode(moreKeySpec)) {
             return null;
         }
@@ -168,17 +183,13 @@
         return (StringUtils.codePointCount(label) == 1) ? null : label;
     }
 
-    public static int getCode(Resources res, String moreKeySpec) {
+    private static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) {
         if (hasCode(moreKeySpec)) {
             final int end = indexOfLabelEnd(moreKeySpec, 0);
             if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
                 throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec);
             }
-            final int resId = getResourceId(res,
-                    moreKeySpec.substring(end + /* LABEL_END */1 + /* PREFIX_AT */1),
-                    R.string.english_ime_name);
-            final int code = res.getInteger(resId);
-            return code;
+            return parseCode(moreKeySpec.substring(end + 1), codesSet, Keyboard.CODE_UNSPECIFIED);
         }
         final String outputText = getOutputTextInternal(moreKeySpec);
         if (outputText != null) {
@@ -197,7 +208,18 @@
         return Keyboard.CODE_OUTPUT_TEXT;
     }
 
-    public static int getIconId(String moreKeySpec) {
+    public static int parseCode(String text, KeyboardCodesSet codesSet, int defCode) {
+        if (text == null) return defCode;
+        if (text.startsWith(PREFIX_CODE)) {
+            return codesSet.getCode(text.substring(PREFIX_CODE.length()));
+        } else if (text.startsWith(PREFIX_HEX)) {
+            return Integer.parseInt(text.substring(PREFIX_HEX.length()), 16);
+        } else {
+            return Integer.parseInt(text);
+        }
+    }
+
+    private static int getIconId(String moreKeySpec) {
         if (hasIcon(moreKeySpec)) {
             final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length());
             final String name = moreKeySpec.substring(PREFIX_ICON.length(), end);
@@ -318,17 +340,7 @@
         }
     }
 
-    public static int getResourceId(Resources res, String name, int packageNameResId) {
-        String packageName = res.getResourcePackageName(packageNameResId);
-        int resId = res.getIdentifier(name, null, packageName);
-        if (resId == 0) {
-            throw new RuntimeException("Unknown resource: " + name);
-        }
-        return resId;
-    }
-
-    private static String resolveStringResource(String rawText, Resources res,
-            int packageNameResId) {
+    public static String resolveLabelReference(String rawText, KeyboardLabelsSet labelsSet) {
         int level = 0;
         String text = rawText;
         StringBuilder sb;
@@ -339,21 +351,20 @@
             }
 
             final int size = text.length();
-            if (size < PREFIX_STRING.length()) {
+            if (size < PREFIX_LABEL.length()) {
                 return text;
             }
 
             sb = null;
             for (int pos = 0; pos < size; pos++) {
                 final char c = text.charAt(pos);
-                if (c == PREFIX_AT && text.startsWith(PREFIX_STRING, pos)) {
+                if (text.startsWith(PREFIX_LABEL, pos) && labelsSet != null) {
                     if (sb == null) {
                         sb = new StringBuilder(text.substring(0, pos));
                     }
-                    final int end = searchResourceNameEnd(text, pos + PREFIX_STRING.length());
-                    final String resName = text.substring(pos + 1, end);
-                    final int resId = getResourceId(res, resName, packageNameResId);
-                    sb.append(res.getString(resId));
+                    final int end = searchLabelNameEnd(text, pos + PREFIX_LABEL.length());
+                    final String name = text.substring(pos + PREFIX_LABEL.length(), end);
+                    sb.append(labelsSet.getLabel(name));
                     pos = end - 1;
                 } else if (c == ESCAPE_CHAR) {
                     if (sb != null) {
@@ -374,7 +385,7 @@
         return text;
     }
 
-    private static int searchResourceNameEnd(String text, int start) {
+    private static int searchLabelNameEnd(String text, int start) {
         final int size = text.length();
         for (int pos = start; pos < size; pos++) {
             final char c = text.charAt(pos);
@@ -387,8 +398,8 @@
         return size;
     }
 
-    public static String[] parseCsvString(String rawText, Resources res, int packageNameResId) {
-        final String text = resolveStringResource(rawText, res, packageNameResId);
+    public static String[] parseCsvString(String rawText, KeyboardLabelsSet labelsSet) {
+        final String text = resolveLabelReference(rawText, labelsSet);
         final int size = text.length();
         if (size == 0) {
             return null;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 9e5c227..8e0b216 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -34,24 +34,55 @@
 
     private final HashMap<String, DeclaredKeyStyle> mStyles =
             new HashMap<String, DeclaredKeyStyle>();
-    private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle();
 
-    public interface KeyStyle {
-        public String[] getStringArray(TypedArray a, int index);
-        public String getString(TypedArray a, int index);
-        public int getInt(TypedArray a, int index, int defaultValue);
-        public int getFlag(TypedArray a, int index);
+    private final KeyboardLabelsSet mLabelsSet;
+    private final KeyStyle mEmptyKeyStyle;
+
+    public KeyStyles(KeyboardLabelsSet labelsSet) {
+        mLabelsSet = labelsSet;
+        mEmptyKeyStyle = new EmptyKeyStyle(labelsSet);
     }
 
-    static class EmptyKeyStyle implements KeyStyle {
+    public static abstract class KeyStyle {
+        protected final KeyboardLabelsSet mLabelsSet;
+
+        public KeyStyle(KeyboardLabelsSet labelsSet) {
+            mLabelsSet = labelsSet;
+        }
+
+        public abstract String[] getStringArray(TypedArray a, int index);
+        public abstract String getString(TypedArray a, int index);
+        public abstract int getInt(TypedArray a, int index, int defaultValue);
+        public abstract int getFlag(TypedArray a, int index);
+
+        protected String parseString(TypedArray a, int index) {
+            if (a.hasValue(index)) {
+                return KeySpecParser.resolveLabelReference(a.getString(index), mLabelsSet);
+            }
+            return null;
+        }
+
+        protected String[] parseStringArray(TypedArray a, int index) {
+            if (a.hasValue(index)) {
+                return KeySpecParser.parseCsvString(a.getString(index), mLabelsSet);
+            }
+            return null;
+        }
+    }
+
+    private static class EmptyKeyStyle extends KeyStyle {
+        public EmptyKeyStyle(KeyboardLabelsSet labelsSet) {
+            super(labelsSet);
+        }
+
         @Override
         public String[] getStringArray(TypedArray a, int index) {
-            return KeyStyles.parseStringArray(a, index);
+            return parseStringArray(a, index);
         }
 
         @Override
         public String getString(TypedArray a, int index) {
-            return a.getString(index);
+            return parseString(a, index);
         }
 
         @Override
@@ -65,9 +96,13 @@
         }
     }
 
-    static class DeclaredKeyStyle implements KeyStyle {
+    private static class DeclaredKeyStyle extends KeyStyle {
         private final HashMap<Integer, Object> mStyleAttributes = new HashMap<Integer, Object>();
 
+        public DeclaredKeyStyle(KeyboardLabelsSet labelsSet) {
+            super(labelsSet);
+        }
+
         @Override
         public String[] getStringArray(TypedArray a, int index) {
             if (a.hasValue(index)) {
@@ -79,7 +114,7 @@
         @Override
         public String getString(TypedArray a, int index) {
             if (a.hasValue(index)) {
-                return a.getString(index);
+                return parseString(a, index);
             }
             return (String)mStyleAttributes.get(index);
         }
@@ -102,8 +137,8 @@
 
         void readKeyAttributes(TypedArray keyAttr) {
             // TODO: Currently not all Key attributes can be declared as style.
-            readInt(keyAttr, R.styleable.Keyboard_Key_code);
-            readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
+            readString(keyAttr, R.styleable.Keyboard_Key_code);
+            readString(keyAttr, R.styleable.Keyboard_Key_altCode);
             readString(keyAttr, R.styleable.Keyboard_Key_keyLabel);
             readString(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
             readString(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
@@ -120,7 +155,7 @@
 
         private void readString(TypedArray a, int index) {
             if (a.hasValue(index)) {
-                mStyleAttributes.put(index, a.getString(index));
+                mStyleAttributes.put(index, parseString(a, index));
             }
         }
 
@@ -131,16 +166,15 @@
         }
 
         private void readFlag(TypedArray a, int index) {
-            final Integer value = (Integer)mStyleAttributes.get(index);
             if (a.hasValue(index)) {
+                final Integer value = (Integer)mStyleAttributes.get(index);
                 mStyleAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
             }
         }
 
         private void readStringArray(TypedArray a, int index) {
-            final String[] value = parseStringArray(a, index);
-            if (value != null) {
-                mStyleAttributes.put(index, value);
+            if (a.hasValue(index)) {
+                mStyleAttributes.put(index, parseStringArray(a, index));
             }
         }
 
@@ -149,14 +183,6 @@
         }
     }
 
-    static String[] parseStringArray(TypedArray a, int index) {
-        if (a.hasValue(index)) {
-            return KeySpecParser.parseCsvString(
-                    a.getString(index), a.getResources(), R.string.english_ime_name);
-        }
-        return null;
-    }
-
     public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
             XmlPullParser parser) throws XmlPullParserException {
         final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
@@ -169,7 +195,7 @@
             }
         }
 
-        final DeclaredKeyStyle style = new DeclaredKeyStyle();
+        final DeclaredKeyStyle style = new DeclaredKeyStyle(mLabelsSet);
         if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
             final String parentStyle = keyStyleAttr.getString(
                     R.styleable.Keyboard_KeyStyle_parentStyle);
@@ -188,7 +214,7 @@
         return mStyles.get(styleName);
     }
 
-    public static KeyStyle getEmptyKeyStyle() {
-        return EMPTY_KEY_STYLE;
+    public KeyStyle getEmptyKeyStyle() {
+        return mEmptyKeyStyle;
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
new file mode 100644
index 0000000..736a96c
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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 com.android.inputmethod.keyboard.Keyboard;
+
+import java.util.HashMap;
+
+public class KeyboardCodesSet {
+    private static final HashMap<String, int[]> sLanguageToCodesMap =
+            new HashMap<String, int[]>();
+    private static final HashMap<String, Integer> sNameToIdMap = new HashMap<String, Integer>();
+
+    private int[] mCodes = DEFAULT;
+
+    public void setLanguage(final String language) {
+        final int[] codes = sLanguageToCodesMap.get(language);
+        mCodes = (codes != null) ? codes : DEFAULT;
+    }
+
+    public int getCode(final String name) {
+        final Integer id = sNameToIdMap.get(name);
+        if (id == null) throw new RuntimeException("Unknown key code: " + name);
+        return mCodes[id];
+    }
+
+    private static final String[] ID_TO_NAME = {
+        "key_tab",
+        "key_enter",
+        "key_space",
+        "key_shift",
+        "key_switch_alpha_symbol",
+        "key_output_text",
+        "key_delete",
+        "key_settings",
+        "key_shortcut",
+        "key_action_enter",
+        "key_action_next",
+        "key_action_previous",
+        "key_language_switch",
+        "key_unspecified",
+        "key_left_parenthesis",
+        "key_right_parenthesis",
+        "key_less_than",
+        "key_greater_than",
+        "key_left_square_bracket",
+        "key_right_square_bracket",
+        "key_left_curly_bracket",
+        "key_right_curly_bracket",
+    };
+
+    private static final int CODE_LEFT_PARENTHESIS = '(';
+    private static final int CODE_RIGHT_PARENTHESIS = ')';
+    private static final int CODE_LESS_THAN_SIGN = '<';
+    private static final int CODE_GREATER_THAN_SIGN = '>';
+    private static final int CODE_LEFT_SQUARE_BRACKET = '[';
+    private static final int CODE_RIGHT_SQUARE_BRACKET = ']';
+    private static final int CODE_LEFT_CURLY_BRACKET = '{';
+    private static final int CODE_RIGHT_CURLY_BRACKET = '}';
+
+    private static final int[] DEFAULT = {
+        Keyboard.CODE_TAB,
+        Keyboard.CODE_ENTER,
+        Keyboard.CODE_SPACE,
+        Keyboard.CODE_SHIFT,
+        Keyboard.CODE_SWITCH_ALPHA_SYMBOL,
+        Keyboard.CODE_OUTPUT_TEXT,
+        Keyboard.CODE_DELETE,
+        Keyboard.CODE_SETTINGS,
+        Keyboard.CODE_SHORTCUT,
+        Keyboard.CODE_ACTION_ENTER,
+        Keyboard.CODE_ACTION_NEXT,
+        Keyboard.CODE_ACTION_PREVIOUS,
+        Keyboard.CODE_LANGUAGE_SWITCH,
+        Keyboard.CODE_UNSPECIFIED,
+        CODE_LEFT_PARENTHESIS,
+        CODE_RIGHT_PARENTHESIS,
+        CODE_LESS_THAN_SIGN,
+        CODE_GREATER_THAN_SIGN,
+        CODE_LEFT_SQUARE_BRACKET,
+        CODE_RIGHT_SQUARE_BRACKET,
+        CODE_LEFT_CURLY_BRACKET,
+        CODE_RIGHT_CURLY_BRACKET,
+    };
+
+    private static final int[] RTL = {
+        DEFAULT[0],
+        DEFAULT[1],
+        DEFAULT[2],
+        DEFAULT[3],
+        DEFAULT[4],
+        DEFAULT[5],
+        DEFAULT[6],
+        DEFAULT[7],
+        DEFAULT[8],
+        DEFAULT[9],
+        DEFAULT[10],
+        DEFAULT[11],
+        DEFAULT[12],
+        DEFAULT[13],
+        CODE_RIGHT_PARENTHESIS,
+        CODE_LEFT_PARENTHESIS,
+        CODE_GREATER_THAN_SIGN,
+        CODE_LESS_THAN_SIGN,
+        CODE_RIGHT_SQUARE_BRACKET,
+        CODE_LEFT_SQUARE_BRACKET,
+        CODE_RIGHT_CURLY_BRACKET,
+        CODE_LEFT_CURLY_BRACKET,
+    };
+
+    private static final String LANGUAGE_DEFAULT = "DEFAULT";
+    private static final String LANGUAGE_ARABIC = "ar";
+    private static final String LANGUAGE_PERSIAN = "fa";
+    private static final String LANGUAGE_HEBREW = "iw";
+
+    private static final Object[] LANGUAGE_AND_CODES = {
+        LANGUAGE_DEFAULT, DEFAULT,
+        LANGUAGE_ARABIC, RTL,
+        LANGUAGE_PERSIAN, RTL,
+        LANGUAGE_HEBREW, RTL,
+    };
+
+    static {
+        for (int i = 0; i < ID_TO_NAME.length; i++) {
+            sNameToIdMap.put(ID_TO_NAME[i], i);
+        }
+
+        for (int i = 0; i < LANGUAGE_AND_CODES.length; i += 2) {
+            final String language = (String)LANGUAGE_AND_CODES[i];
+            final int[] codes = (int[])LANGUAGE_AND_CODES[i + 1];
+            sLanguageToCodesMap.put(language, codes);
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java
new file mode 100644
index 0000000..a46f3bf
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java
@@ -0,0 +1,2477 @@
+/*
+ * Copyright (C) 2012 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.content.Context;
+import android.content.res.Resources;
+
+import com.android.inputmethod.latin.R;
+
+import java.util.HashMap;
+
+/**
+ * !!!!! DO NOT EDIT THIS FILE !!!!!
+ * This file is generated by tools/makelabel.
+ */
+public final class KeyboardLabelsSet {
+    // Language to labels map.
+    private static final HashMap<String, String[]> sLocaleToLabelsMap =
+            new HashMap<String, String[]>();
+    private static final HashMap<String, Integer> sNameToIdMap = new HashMap<String, Integer>();
+
+    private String[] mLabels;
+    // Resource name to label map.
+    private HashMap<String, String> mResourceNameToLabelsMap = new HashMap<String, String>();
+
+    public void setLanguage(final String language) {
+        mLabels = sLocaleToLabelsMap.get(language);
+        if (mLabels == null) {
+            mLabels = LANGUAGE_DEFAULT;
+        }
+    }
+
+    public void loadStringResources(Context context) {
+        loadStringResourcesInternal(context, RESOURCE_NAMES, R.string.english_ime_name);
+    }
+
+    /* package for test */
+    void loadStringResourcesInternal(Context context, final String[] resourceNames,
+            int referenceId) {
+        final Resources res = context.getResources();
+        final String packageName = res.getResourcePackageName(referenceId);
+        for (final String resName : resourceNames) {
+            final int resId = res.getIdentifier(resName, "string", packageName);
+            mResourceNameToLabelsMap.put(resName, res.getString(resId));
+        }
+    }
+
+    public String getLabel(final String name) {
+        if (mResourceNameToLabelsMap.containsKey(name)) {
+            return mResourceNameToLabelsMap.get(name);
+        }
+        final Integer id = sNameToIdMap.get(name);
+        if (id == null) throw new RuntimeException("Unknown label: " + name);
+        final String label = (id < mLabels.length) ? mLabels[id] : null;
+        return (label == null) ? LANGUAGE_DEFAULT[id] : label;
+    }
+
+    private static final String[] RESOURCE_NAMES = {
+        // These labels' name should be aligned with the @string/<name> in values/strings.xml.
+        // Labels for action.
+        "label_go_key",
+        // "label_search_key",
+        "label_send_key",
+        "label_next_key",
+        "label_done_key",
+        "label_previous_key",
+        // Other labels.
+        "label_to_alpha_key",
+        "label_to_symbol_key",
+        "label_to_symbol_with_microphone_key",
+        "label_pause_key",
+        "label_wait_key",
+    };
+
+    private static final String[] NAMES = {
+        /*  0 */ "more_keys_for_a",
+        /*  1 */ "more_keys_for_e",
+        /*  2 */ "more_keys_for_i",
+        /*  3 */ "more_keys_for_o",
+        /*  4 */ "more_keys_for_u",
+        /*  5 */ "more_keys_for_s",
+        /*  6 */ "more_keys_for_n",
+        /*  7 */ "more_keys_for_c",
+        /*  8 */ "more_keys_for_y",
+        /*  9 */ "more_keys_for_d",
+        /* 10 */ "more_keys_for_r",
+        /* 11 */ "more_keys_for_t",
+        /* 12 */ "more_keys_for_z",
+        /* 13 */ "more_keys_for_k",
+        /* 14 */ "more_keys_for_l",
+        /* 15 */ "more_keys_for_g",
+        /* 16 */ "more_keys_for_v",
+        /* 17 */ "more_keys_for_h",
+        /* 18 */ "more_keys_for_j",
+        /* 19 */ "more_keys_for_w",
+        /* 20 */ "keylabel_for_nordic_row1_11",
+        /* 21 */ "keylabel_for_nordic_row2_10",
+        /* 22 */ "keylabel_for_nordic_row2_11",
+        /* 23 */ "more_keys_for_nordic_row2_10",
+        /* 24 */ "more_keys_for_nordic_row2_11",
+        /* 25 */ "keylabel_for_east_slavic_row1_9",
+        /* 26 */ "keylabel_for_east_slavic_row2_1",
+        /* 27 */ "keylabel_for_east_slavic_row3_5",
+        /* 28 */ "more_keys_for_cyrillic_u",
+        /* 29 */ "more_keys_for_cyrillic_ye",
+        /* 30 */ "more_keys_for_cyrillic_en",
+        /* 31 */ "more_keys_for_cyrillic_ha",
+        /* 32 */ "more_keys_for_east_slavic_row2_1",
+        /* 33 */ "more_keys_for_cyrillic_o",
+        /* 34 */ "more_keys_for_cyrillic_soft_sign",
+        /* 35 */ "keylabel_for_south_slavic_row1_6",
+        /* 36 */ "keylabel_for_south_slavic_row2_11",
+        /* 37 */ "keylabel_for_south_slavic_row3_1",
+        /* 38 */ "keylabel_for_south_slavic_row3_8",
+        /* 39 */ "more_keys_for_cyrillic_ie",
+        /* 40 */ "more_keys_for_cyrillic_i",
+        /* 41 */ "more_keys_for_single_quote",
+        /* 42 */ "more_keys_for_double_quote",
+        /* 43 */ "more_keys_for_tablet_double_quote",
+        /* 44 */ "more_keys_for_currency_dollar",
+        /* 45 */ "more_keys_for_currency_euro",
+        /* 46 */ "more_keys_for_currency_pound",
+        /* 47 */ "more_keys_for_currency_general",
+        /* 48 */ "more_keys_for_smiley",
+        /* 49 */ "more_keys_for_punctuation",
+        /* 50 */ "keyhintlabel_for_punctuation",
+        /* 51 */ "keylabel_for_popular_domain",
+        /* 52 */ "more_keys_for_popular_domain",
+        /* 53 */ "keylabel_for_symbols_1",
+        /* 54 */ "keylabel_for_symbols_2",
+        /* 55 */ "keylabel_for_symbols_3",
+        /* 56 */ "keylabel_for_symbols_4",
+        /* 57 */ "keylabel_for_symbols_5",
+        /* 58 */ "keylabel_for_symbols_6",
+        /* 59 */ "keylabel_for_symbols_7",
+        /* 60 */ "keylabel_for_symbols_8",
+        /* 61 */ "keylabel_for_symbols_9",
+        /* 62 */ "keylabel_for_symbols_0",
+        /* 63 */ "additional_more_keys_for_symbols_1",
+        /* 64 */ "additional_more_keys_for_symbols_2",
+        /* 65 */ "additional_more_keys_for_symbols_3",
+        /* 66 */ "additional_more_keys_for_symbols_4",
+        /* 67 */ "additional_more_keys_for_symbols_5",
+        /* 68 */ "additional_more_keys_for_symbols_6",
+        /* 69 */ "additional_more_keys_for_symbols_7",
+        /* 70 */ "additional_more_keys_for_symbols_8",
+        /* 71 */ "additional_more_keys_for_symbols_9",
+        /* 72 */ "additional_more_keys_for_symbols_0",
+        /* 73 */ "more_keys_for_symbols_1",
+        /* 74 */ "more_keys_for_symbols_2",
+        /* 75 */ "more_keys_for_symbols_3",
+        /* 76 */ "more_keys_for_symbols_4",
+        /* 77 */ "more_keys_for_symbols_5",
+        /* 78 */ "more_keys_for_symbols_6",
+        /* 79 */ "more_keys_for_symbols_7",
+        /* 80 */ "more_keys_for_symbols_8",
+        /* 81 */ "more_keys_for_symbols_9",
+        /* 82 */ "more_keys_for_symbols_0",
+        /* 83 */ "more_keys_for_am_pm",
+        /* 84 */ "settings_as_more_key",
+        /* 85 */ "keylabel_for_comma",
+        /* 86 */ "more_keys_for_comma",
+        /* 87 */ "action_next_as_more_key",
+        /* 88 */ "action_previous_as_more_key",
+        /* 89 */ "keylabel_for_symbols_question",
+        /* 90 */ "keylabel_for_symbols_semicolon",
+        /* 91 */ "keylabel_for_symbols_percent",
+        /* 92 */ "more_keys_for_symbols_question",
+        /* 93 */ "more_keys_for_symbols_semicolon",
+        /* 94 */ "more_keys_for_symbols_percent",
+        /* 95 */ "keylabel_for_tablet_comma",
+        /* 96 */ "keyhintlabel_for_tablet_comma",
+        /* 97 */ "more_keys_for_tablet_comma",
+        /* 98 */ "keyhintlabel_for_tablet_period",
+        /* 99 */ "more_keys_for_tablet_period",
+        /* 100 */ "keylabel_for_apostrophe",
+        /* 101 */ "keylabel_for_dash",
+        /* 102 */ "keyhintlabel_for_apostrophe",
+        /* 103 */ "keyhintlabel_for_dash",
+        /* 104 */ "more_keys_for_apostrophe",
+        /* 105 */ "more_keys_for_dash",
+        /* 106 */ "more_keys_for_bullet",
+        /* 107 */ "more_keys_for_star",
+        /* 108 */ "more_keys_for_plus",
+        /* 109 */ "more_keys_for_left_parenthesis",
+        /* 110 */ "more_keys_for_right_parenthesis",
+        /* 111 */ "more_keys_for_less_than",
+        /* 112 */ "more_keys_for_greater_than",
+        /* 113 */ "label_to_more_symbol_key",
+        /* 114 */ "label_to_more_symbol_for_tablet_key",
+        /* 115 */ "label_tab_key",
+        /* 116 */ "label_to_phone_numeric_key",
+        /* 117 */ "label_to_phone_symbols_key",
+        /* 118 */ "label_time_am",
+        /* 119 */ "label_time_pm",
+    };
+
+    private static final String EMPTY = "";
+
+    /* Default labels */
+    private static final String[] LANGUAGE_DEFAULT = {
+        /* 0~ */
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        EMPTY, EMPTY,
+        /* ~40 */
+        /* 41 */ "!fixedColumnOrder!4,\u2018,\u2019,\u201A,\u201B",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;</string>
+        /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+        // U+00A2: "¢" CENT SIGN
+        // U+00A3: "£" POUND SIGN
+        // U+20AC: "€" EURO SIGN
+        // U+00A5: "¥" YEN SIGN
+        // U+20B1: "₱" PESO SIGN
+        /* 44 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+        /* 45 */ "\u00A2,\u00A3,$,\u00A5,\u20B1",
+        /* 46 */ "\u00A2,$,\u20AC,\u00A5,\u20B1",
+        /* 47 */ "\u00A2,$,\u20AC,\u00A3,\u00A5,\u20B1",
+        /* 48 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+        /* 49 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
+        /* 50 */ EMPTY,
+        /* 51 */ ".com",
+        // popular web domains for the locale - most popular, displayed on the keyboard
+        /* 52 */ "!hasLabels!,.net,.org,.gov,.edu",
+        /* 53 */ "1",
+        /* 54 */ "2",
+        /* 55 */ "3",
+        /* 56 */ "4",
+        /* 57 */ "5",
+        /* 58 */ "6",
+        /* 59 */ "7",
+        /* 60 */ "8",
+        /* 61 */ "9",
+        /* 62 */ "0",
+        /* 63~ */
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        /* ~72 */
+        // U+00B9: "¹" SUPERSCRIPT ONE
+        // U+00BD: "½" VULGAR FRACTION ONE HALF
+        // U+2153: "⅓" VULGAR FRACTION ONE THIRD
+        // U+00BC: "¼" VULGAR FRACTION ONE QUARTER
+        // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
+        /* 73 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+        // U+00B2: "²" SUPERSCRIPT TWO
+        // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
+        /* 74 */ "\u00B2,\u2154",
+        // U+00B3: "³" SUPERSCRIPT THREE
+        // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
+        // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
+        /* 75 */ "\u00B3,\u00BE,\u215C",
+        // U+2074: "⁴" SUPERSCRIPT FOUR
+        /* 76 */ "\u2074",
+        // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
+        /* 77 */ "\u215D",
+        /* 78 */ EMPTY,
+        // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+        /* 79 */ "\u215E",
+        /* 80 */ EMPTY,
+        /* 81 */ EMPTY,
+        // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
+        // U+2205: "∅" EMPTY SET
+        /* 82 */ "\u207F,\u2205",
+        /* 83 */ "!fixedColumnOrder!2,!hasLabels!,!label/label_time_am,!label/label_time_pm",
+        /* 84 */ "!icon/settingsKey|!code/key_settings",
+        /* 85 */ ",",
+        /* 86 */ EMPTY,
+        /* 87 */ "!hasLabels!,!label/label_next_key|!code/key_action_next",
+        /* 88 */ "!hasLabels!,!label/label_previous_key|!code/key_action_previous",
+        /* 89 */ "?",
+        /* 90 */ ";",
+        /* 91 */ "%",
+        // U+00BF: "¿" INVERTED QUESTION MARK
+        /* 92 */ "\u00BF",
+        /* 93 */ EMPTY,
+        // U+2030: "‰" PER MILLE SIGN
+        /* 94 */ "\u2030",
+        /* 95 */ ",",
+        /* 96 */ "!",
+        /* 97 */ "!",
+        /* 98 */ "?",
+        /* 99 */ "?",
+        /* 100 */ "\'",
+        /* 101 */ "-",
+        /* 102 */ "\"",
+        /* 103 */ "_",
+        /* 104 */ "\"",
+        /* 105 */ "_",
+        // U+266A: "♪" EIGHTH NOTE
+        // U+2665: "♥" BLACK HEART SUIT
+        // U+2660: "♠" BLACK SPADE SUIT
+        // U+2666: "♦" BLACK DIAMOND SUIT
+        // U+2663: "♣" BLACK CLUB SUIT
+        /* 106 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+        // U+2020: "†" DAGGER
+        // U+2021: "‡" DOUBLE DAGGER
+        // U+2605: "★" BLACK STAR
+        /* 107 */ "\u2020,\u2021,\u2605",
+        // U+00B1: "±" PLUS-MINUS SIGN
+        /* 108 */ "\u00B1",
+        // The all letters need to be mirrored are found at
+        // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
+        /* 109 */ "!fixedColumnOrder!3,<,{,[",
+        /* 110 */ "!fixedColumnOrder!3,>,},]",
+        // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        // U+2264: "≤" LESS-THAN OR EQUAL TO
+        // U+2265: "≥" GREATER-THAN EQUAL TO
+        // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // The following characters don't need BIDI mirroring.
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+        /* 111 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
+        /* 112 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
+        // Label for "switch to more symbol" modifier key.  Must be short to fit on key!
+        /* 113 */ "= \\ <",
+        // Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key!
+        /* 114 */ "~ \\ {",
+        // Label for "Tab" key.  Must be short to fit on key!
+        /* 115 */ "Tab",
+        // Label for "switch to phone numeric" key.  Must be short to fit on key!
+        /* 116 */ "123",
+        // Label for "switch to phone symbols" key.  Must be short to fit on key!  U+FF0A: "*" FULLWIDTH ASTERISK
+        // U+FF03: "#" FULLWIDTH NUMBER SIGN
+        /* 117 */ "\uFF0A\uFF03",
+        // Key label for "ante meridiem"
+        /* 118 */ "AM",
+        // Key label for "post meridiem"
+        /* 119 */ "PM",
+    };
+
+    /* Language ar: Arabic */
+    private static final String[] LANGUAGE_ar = {
+        /* 0~ */
+        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,
+        /* ~41 */
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
+        /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+        /* 44~ */
+        null, null, null, null, null,
+        /* ~48 */
+        // U+061F: "؟" ARABIC QUESTION MARK
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON  U+0650: "ِ" ARABIC KASRA
+        // U+064E: "َ" ARABIC FATHA
+        // U+064D: "ٍ" ARABIC KASRATAN
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0655: "ٕ" ARABIC HAMZA BELOW
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE  U+064F: "ُ" ARABIC DAMMA
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+0640: "ـ" ARABIC TATWEEL  In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 49 */ "!fixedColumnOrder!8,\",\',-,:,!,\u061F,\u060C,\u061B,\u0650,\u064E,\u064D,\u064B,\u0656,\u0670,\u0655,\u0654,\u064F,\u064C,\u0651,\u0652,\u0653,\u0640\u0640\u0640|\u0640,/",
+        /* 50 */ "\u064B",
+        /* 51 */ null,
+        /* 52 */ null,
+        // U+0661: "١" ARABIC-INDIC DIGIT ONE
+        /* 53 */ "\u0661",
+        // U+0662: "٢" ARABIC-INDIC DIGIT TWO
+        /* 54 */ "\u0662",
+        // U+0663: "٣" ARABIC-INDIC DIGIT THREE
+        /* 55 */ "\u0663",
+        // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
+        /* 56 */ "\u0664",
+        // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
+        /* 57 */ "\u0665",
+        // U+0666: "٦" ARABIC-INDIC DIGIT SIX
+        /* 58 */ "\u0666",
+        // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
+        /* 59 */ "\u0667",
+        // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
+        /* 60 */ "\u0668",
+        // U+0669: "٩" ARABIC-INDIC DIGIT NINE
+        /* 61 */ "\u0669",
+        // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
+        /* 62 */ "\u0660",
+        /* 63 */ "1",
+        /* 64 */ "2",
+        /* 65 */ "3",
+        /* 66 */ "4",
+        /* 67 */ "5",
+        /* 68 */ "6",
+        /* 69 */ "7",
+        /* 70 */ "8",
+        /* 71 */ "9",
+        // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+        // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+        /* 72 */ "0,\u066B,\u066C",
+        /* 73~ */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~84 */
+        // U+060C: "،" ARABIC COMMA
+        /* 85 */ "\u060C",
+        /* 86 */ "\\,",
+        /* 87 */ null,
+        /* 88 */ null,
+        /* 89 */ "\u061F",
+        /* 90 */ "\u061B",
+        // U+066A: "٪" ARABIC PERCENT SIGN
+        /* 91 */ "\u066A",
+        /* 92 */ "?",
+        /* 93 */ ";",
+        // U+2030: "‰" PER MILLE SIGN
+        /* 94 */ "%,\u2030",
+        /* 95~ */
+        null, null, null, null, null,
+        /* ~99 */
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON
+        // U+061F: "؟" ARABIC QUESTION MARK
+        /* 100 */ "\u060C",
+        /* 101 */ ".",
+        /* 102 */ "\u061F",
+        /* 103 */ "\u064B",
+        /* 104 */ "\u061F,\u061B,!,:,-,/,\',\"",
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+064F: "ُ" ARABIC DAMMA  U+0650: "ِ" ARABIC KASRA
+        // U+064E: "َ" ARABIC FATHA
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0640: "ـ" ARABIC TATWEEL
+        // U+064D: "ٍ" ARABIC KASRATAN  U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE
+        // U+0655: "ٕ" ARABIC HAMZA BELOW  In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 105 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,\u0670",
+        // U+266A: "♪" EIGHTH NOTE
+        /* 106 */ "\u266A",
+        // U+2605: "★" BLACK STAR
+        // U+066D: "٭" ARABIC FIVE POINTED STAR
+        /* 107 */ "\u2605,\u066D",
+        /* 108 */ null,
+        // The all letters need to be mirrored are found at
+        // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt  U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
+        // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS  TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS  TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS
+        /* 109 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 110 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+        // U+2264: "≤" LESS-THAN OR EQUAL TO
+        // U+2265: "≥" GREATER-THAN EQUAL TO
+        // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        // The following characters don't need BIDI mirroring.
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+        /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+    };
+
+    /* Language be: Belarusian */
+    private static final String[] LANGUAGE_be = {
+        /* 0~ */
+        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,
+        /* ~24 */
+        // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U
+        /* 25 */ "\u045E",
+        // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+        /* 26 */ "\u044B",
+        // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+        /* 27 */ "\u0456",
+        /* 28~ */
+        null, null, null,
+        /* ~30 */
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 31 */ "\u044A",
+        /* 32 */ null,
+        /* 33 */ null,
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 34 */ "\u044A",
+    };
+
+    /* Language ca: Catalan */
+    private static final String[] LANGUAGE_ca = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E0,\u00E1,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E8,\u00E9,\u00EB,\u00EA,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+        /* 5 */ null,
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u00E7,\u0107,\u010D",
+        /* 8~ */
+        null, null, null, null, null, null,
+        /* ~13 */
+        // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        /* 14 */ "\u0140,\u0142",
+    };
+
+    /* Language cs: Czech */
+    private static final String[] LANGUAGE_cs = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u011B,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        /* 5 */ "\u0161,\u00DF,\u015B",
+        // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u0148,\u00F1,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u00E7,\u0107",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        /* 9 */ "\u010F",
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        /* 10 */ "\u0159",
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        /* 11 */ "\u0165",
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        /* 12 */ "\u017E,\u017A,\u017C",
+    };
+
+    /* Language da: Danish */
+    private static final String[] LANGUAGE_da = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E1,\u00E4,\u00E0,\u00E2,\u00E3,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        /* 1 */ "\u00E9,\u00EB",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        /* 2 */ "\u00ED,\u00EF",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F4,\u00F2,\u00F5,\u0153,\u014D",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u00DF,\u015B,\u0161",
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+        /* 7 */ null,
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+00F0: "ð" LATIN SMALL LETTER ETH
+        /* 9 */ "\u00F0",
+        /* 10~ */
+        null, null, null, null,
+        /* ~13 */
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        /* 14 */ "\u0142",
+        /* 15~ */
+        null, null, null, null, null,
+        /* ~19 */
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        /* 20 */ "\u00E5",
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 21 */ "\u00E6",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 22 */ "\u00F8",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 23 */ "\u00E4",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 24 */ "\u00F6",
+    };
+
+    /* Language de: German */
+    private static final String[] LANGUAGE_de = {
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E4,\u00E2,\u00E0,\u00E1,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        /* 1 */ "\u0117",
+        /* 2 */ null,
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F6,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u00F8,\u014D",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u00DF,\u015B,\u0161",
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+    };
+
+    /* Language en: English */
+    private static final String[] LANGUAGE_en = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0103",
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        /* 2 */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        /* 3 */ "\u00F4,\u00F6,\u00F2,\u00F3,\u0153,\u00F8\u014D,\u00F5",
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B",
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        /* 5 */ "\u00DF",
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        /* 6 */ "\u00F1",
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        /* 7 */ "\u00E7",
+    };
+
+    /* Language es: Spanish */
+    private static final String[] LANGUAGE_es = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E1,\u00E0,\u00E4,\u00E2,\u00E3,\u00E5,\u0105,\u00E6,\u0101,\u00AA",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00E8,\u00EB,\u00EA,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F3,\u00F2,\u00F6,\u00F4,\u00F5,\u00F8,\u0153,\u014D,\u00BA",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+        /* 5 */ null,
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u00E7,\u0107,\u010D",
+        /* 8~ */
+        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,
+        /* ~48 */
+        // U+00A1: "¡" INVERTED EXCLAMATION MARK
+        // U+00BF: "¿" INVERTED QUESTION MARK
+        /* 49 */ "!fixedColumnOrder!7,#,-,\u00A1,!,\u00BF,\\,,?,\\%,+,;,:,/,(,),@,&,\",\'",
+    };
+
+    /* Language et: Estonian */
+    private static final String[] LANGUAGE_et = {
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        /* 0 */ "\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6,\u0105",
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        /* 1 */ "\u0113,\u00E8,\u0117,\u00E9,\u00EA,\u00EB,\u0119,\u011B",
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        /* 2 */ "\u012B,\u00EC,\u012F,\u00ED,\u00EE,\u00EF,\u0131",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 3 */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        /* 4 */ "\u00FC,\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u016F,\u0171",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        /* 5 */ "\u0161,\u00DF,\u015B,\u015F",
+        // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u0146,\u00F1,\u0144,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u00E7,\u0107",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        /* 9 */ "\u010F",
+        // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+        /* 10 */ "\u0157,\u0159,\u0155",
+        // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        /* 11 */ "\u0163,\u0165",
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        /* 12 */ "\u017E,\u017C,\u017A",
+        // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+        /* 13 */ "\u0137",
+        // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+        // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+        /* 14 */ "\u013C,\u0142,\u013A,\u013E",
+        // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        /* 15 */ "\u0123,\u011F",
+        /* 16~ */
+        null, null, null, null,
+        /* ~19 */
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        /* 20 */ "\u00FC",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 21 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 22 */ "\u00E4",
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        /* 23 */ "\u00F5",
+    };
+
+    /* Language fa: Persian */
+    private static final String[] LANGUAGE_fa = {
+        /* 0~ */
+        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,
+        /* ~41 */
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
+        /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+        /* 44~ */
+        null, null, null, null, null,
+        /* ~48 */
+        // U+061F: "؟" ARABIC QUESTION MARK
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON  U+0650: "ِ" ARABIC KASRA
+        // U+064E: "َ" ARABIC FATHA
+        // U+064D: "ٍ" ARABIC KASRATAN
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0655: "ٕ" ARABIC HAMZA BELOW
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE  U+064F: "ُ" ARABIC DAMMA
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+0640: "ـ" ARABIC TATWEEL  In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 49 */ "!fixedColumnOrder!8,\",\',-,:,!,\u061F,\u060C,\u061B,\u0650,\u064E,\u064D,\u064B,\u0656,\u0670,\u0655,\u0654,\u064F,\u064C,\u0651,\u0652,\u0653,\u0640\u0640\u0640|\u0640,/",
+        /* 50 */ "\u064B",
+        /* 51 */ null,
+        /* 52 */ null,
+        // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
+        /* 53 */ "\u06F1",
+        // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
+        /* 54 */ "\u06F2",
+        // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
+        /* 55 */ "\u06F3",
+        // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
+        /* 56 */ "\u06F4",
+        // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
+        /* 57 */ "\u06F5",
+        // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
+        /* 58 */ "\u06F6",
+        // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
+        /* 59 */ "\u06F7",
+        // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
+        /* 60 */ "\u06F8",
+        // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
+        /* 61 */ "\u06F9",
+        // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
+        /* 62 */ "\u06F0",
+        /* 63 */ "1",
+        /* 64 */ "2",
+        /* 65 */ "3",
+        /* 66 */ "4",
+        /* 67 */ "5",
+        /* 68 */ "6",
+        /* 69 */ "7",
+        /* 70 */ "8",
+        /* 71 */ "9",
+        // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+        // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+        /* 72 */ "0,\u066B,\u066C",
+        /* 73~ */
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~84 */
+        // U+060C: "،" ARABIC COMMA
+        /* 85 */ "\u060C",
+        /* 86 */ "\\,",
+        /* 87 */ null,
+        /* 88 */ null,
+        /* 89 */ "\u061F",
+        /* 90 */ "\u061B",
+        // U+066A: "٪" ARABIC PERCENT SIGN
+        /* 91 */ "\u066A",
+        /* 92 */ "?",
+        /* 93 */ ";",
+        // U+2030: "‰" PER MILLE SIGN
+        /* 94 */ "%,\u2030",
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON
+        // U+061F: "؟" ARABIC QUESTION MARK
+        /* 95 */ "\u060C",
+        /* 96 */ "!",
+        /* 97 */ "!,\\,",
+        /* 98 */ "\u061F",
+        /* 99 */ "\u061F,?",
+        /* 100~ */
+        null, null, null,
+        /* ~102 */
+        /* 103 */ "\u064B",
+        /* 104 */ "\u061F,\u061B,!,:,-,/,\',\"",
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+064F: "ُ" ARABIC DAMMA  U+0650: "ِ" ARABIC KASRA
+        // U+064E: "َ" ARABIC FATHA
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0640: "ـ" ARABIC TATWEEL
+        // U+064D: "ٍ" ARABIC KASRATAN  U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE
+        // U+0655: "ٕ" ARABIC HAMZA BELOW  In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 105 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,_,\u0670",
+        // U+266A: "♪" EIGHTH NOTE
+        /* 106 */ "\u266A",
+        // U+2605: "★" BLACK STAR
+        // U+066D: "٭" ARABIC FIVE POINTED STAR
+        /* 107 */ "\u2605,\u066D",
+        /* 108 */ null,
+        // The all letters need to be mirrored are found at
+        // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt  U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
+        // U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS  TODO: DroidSansArabic lacks the glyph of U+FD3E ORNATE LEFT PARENTHESIS  TODO: DroidSansArabic lacks the glyph of U+FD3F ORNATE RIGHT PARENTHESIS
+        /* 109 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 110 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+        // U+2264: "≤" LESS-THAN OR EQUAL TO
+        // U+2265: "≥" GREATER-THAN EQUAL TO
+        // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        // The following characters don't need BIDI mirroring.
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+        /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+    };
+
+    /* Language fi: Finnish */
+    private static final String[] LANGUAGE_fi = {
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E6,\u00E0,\u00E1,\u00E2,\u00E3,\u0101",
+        /* 1 */ null,
+        /* 2 */ null,
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        /* 4 */ "\u00FC",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        /* 5 */ "\u0161,\u00DF,\u015B",
+        /* 6~ */
+        null, null, null, null, null, null,
+        /* ~11 */
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        /* 12 */ "\u017E,\u017A,\u017C",
+        /* 13~ */
+        null, null, null, null, null, null, null,
+        /* ~19 */
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        /* 20 */ "\u00E5",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 21 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 22 */ "\u00E4",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 23 */ "\u00F8",
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 24 */ "\u00E6",
+    };
+
+    /* Language fr: French */
+    private static final String[] LANGUAGE_fr = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E0,\u00E2,%,\u00E6,\u00E1,\u00E4,\u00E3,\u00E5,\u0101,\u00AA",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,%,\u0119,\u0117,\u0113",
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00EE,%,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F4,\u0153,%,\u00F6,\u00F2,\u00F3,\u00F5,\u00F8,\u014D,\u00BA",
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00F9,\u00FB,%,\u00FC,\u00FA,\u016B",
+        /* 5 */ null,
+        /* 6 */ null,
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u00E7,\u0107,\u010D",
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "%,\u00FF",
+    };
+
+    /* Language hi: Hindi */
+    private static final String[] LANGUAGE_hi = {
+        /* 0~ */
+        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,
+        /* ~52 */
+        // U+0967: "१" DEVANAGARI DIGIT ONE
+        /* 53 */ "\u0967",
+        // U+0968: "२" DEVANAGARI DIGIT TWO
+        /* 54 */ "\u0968",
+        // U+0969: "३" DEVANAGARI DIGIT THREE
+        /* 55 */ "\u0969",
+        // U+096A: "४" DEVANAGARI DIGIT FOUR
+        /* 56 */ "\u096A",
+        // U+096B: "५" DEVANAGARI DIGIT FIVE
+        /* 57 */ "\u096B",
+        // U+096C: "६" DEVANAGARI DIGIT SIX
+        /* 58 */ "\u096C",
+        // U+096D: "७" DEVANAGARI DIGIT SEVEN
+        /* 59 */ "\u096D",
+        // U+096E: "८" DEVANAGARI DIGIT EIGHT
+        /* 60 */ "\u096E",
+        // U+096F: "९" DEVANAGARI DIGIT NINE
+        /* 61 */ "\u096F",
+        // U+0966: "०" DEVANAGARI DIGIT ZERO
+        /* 62 */ "\u0966",
+        /* 63 */ "1",
+        /* 64 */ "2",
+        /* 65 */ "3",
+        /* 66 */ "4",
+        /* 67 */ "5",
+        /* 68 */ "6",
+        /* 69 */ "7",
+        /* 70 */ "8",
+        /* 71 */ "9",
+        /* 72 */ "0",
+    };
+
+    /* Language hr: Croatian */
+    private static final String[] LANGUAGE_hr = {
+        /* 0~ */
+        null, null, null, null, null,
+        /* ~4 */
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        /* 5 */ "\u0161,\u015B,\u00DF",
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        /* 7 */ "\u010D,\u0107,\u00E7",
+        /* 8 */ null,
+        // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+        /* 9 */ "\u0111",
+        /* 10 */ null,
+        /* 11 */ null,
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        /* 12 */ "\u017E,\u017A,\u017C",
+    };
+
+    /* Language hu: Hungarian */
+    private static final String[] LANGUAGE_hu = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F6,\u0151,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u0171,\u00FB,\u00F9,\u016B",
+    };
+
+    /* Language is: Icelandic */
+    private static final String[] LANGUAGE_is = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E1,\u00E4,\u00E6,\u00E5,\u00E0,\u00E2,\u00E3,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00EB,\u00E8,\u00EA,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+        /* 5~ */
+        null, null, null,
+        /* ~7 */
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+00F0: "ð" LATIN SMALL LETTER ETH
+        /* 9 */ "\u00F0",
+        /* 10 */ null,
+        // U+00FE: "þ" LATIN SMALL LETTER THORN
+        /* 11 */ "\u00FE",
+        /* 12~ */
+        null, null, null, null, null, null, null, null,
+        /* ~19 */
+        // U+00F0: "ð" LATIN SMALL LETTER ETH
+        /* 20 */ "\u00F0",
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 21 */ "\u00E6",
+        // U+00FE: "þ" LATIN SMALL LETTER THORN
+        /* 22 */ "\u00FE",
+    };
+
+    /* Language it: Italian */
+    private static final String[] LANGUAGE_it = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101,\u00AA",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u0117,\u0113",
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00EC,\u00ED,\u00EE,\u00EF,\u012F,\u012B",
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F6,\u00F5,\u0153,\u00F8,\u014D,\u00BA",
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00F9,\u00FA,\u00FB,\u00FC,\u016B",
+    };
+
+    /* Language iw: Hebrew */
+    private static final String[] LANGUAGE_iw = {
+        /* 0~ */
+        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,
+        /* ~41 */
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
+        /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
+        /* 44~ */
+        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,
+        /* ~106 */
+        // U+2605: "★" BLACK STAR
+        /* 107 */ "\u2605",
+        // U+00B1: "±" PLUS-MINUS SIGN
+        // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
+        /* 108 */ "\u00B1,\uFB29",
+        // The all letters need to be mirrored are found at
+        // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
+        /* 109 */ "!fixedColumnOrder!3,<|>,{|},[|]",
+        /* 110 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
+        // U+2264: "≤" LESS-THAN OR EQUAL TO
+        // U+2265: "≥" GREATER-THAN EQUAL TO
+        // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+        // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+        // The following characters don't need BIDI mirroring.
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+        /* 111 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 112 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+    };
+
+    /* Language ky: Kirghiz */
+    private static final String[] LANGUAGE_ky = {
+        /* 0~ */
+        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,
+        /* ~24 */
+        // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+        /* 25 */ "\u0449",
+        // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+        /* 26 */ "\u044B",
+        // U+0438: "и" CYRILLIC SMALL LETTER I
+        /* 27 */ "\u0438",
+        // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
+        /* 28 */ "\u04AF",
+        /* 29 */ null,
+        // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER
+        /* 30 */ "\u04A3",
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 31 */ "\u044A",
+        /* 32 */ null,
+        // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O
+        /* 33 */ "\u04E9",
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 34 */ "\u044A",
+    };
+
+    /* Language lt: Lithuanian */
+    private static final String[] LANGUAGE_lt = {
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 0 */ "\u0105,\u00E4,\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E5,\u00E6",
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        /* 1 */ "\u0117,\u0119,\u0113,\u00E8,\u00E9,\u00EA,\u00EB,\u011B",
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        /* 2 */ "\u012F,\u012B,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 3 */ "\u00F6,\u00F5,\u00F2,\u00F3,\u00F4,\u0153,\u0151,\u00F8",
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        /* 4 */ "\u016B,\u0173,\u00FC,\u016B,\u00F9,\u00FA,\u00FB,\u016F,\u0171",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        /* 5 */ "\u0161,\u00DF,\u015B,\u015F",
+        // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u0146,\u00F1,\u0144,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u00E7,\u0107",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        /* 9 */ "\u010F",
+        // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+        /* 10 */ "\u0157,\u0159,\u0155",
+        // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        /* 11 */ "\u0163,\u0165",
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        /* 12 */ "\u017E,\u017C,\u017A",
+        // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+        /* 13 */ "\u0137",
+        // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+        // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+        /* 14 */ "\u013C,\u0142,\u013A,\u013E",
+        // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        /* 15 */ "\u0123,\u011F",
+    };
+
+    /* Language lv: Latvian */
+    private static final String[] LANGUAGE_lv = {
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        /* 0 */ "\u0101,\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u0105",
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        /* 1 */ "\u0113,\u0117,\u00E8,\u00E9,\u00EA,\u00EB,\u0119,\u011B",
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        /* 2 */ "\u012B,\u012F,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u0153,\u0151,\u00F8",
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        /* 4 */ "\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u00FC,\u016F,\u0171",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        /* 5 */ "\u0161,\u00DF,\u015B,\u015F",
+        // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u0146,\u00F1,\u0144,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u00E7,\u0107",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        /* 9 */ "\u010F",
+        // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+        /* 10 */ "\u0157,\u0159,\u0155",
+        // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        /* 11 */ "\u0163,\u0165",
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        /* 12 */ "\u017E,\u017C,\u017A",
+        // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+        /* 13 */ "\u0137",
+        // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+        // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+        /* 14 */ "\u013C,\u0142,\u013A,\u013E",
+        // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        /* 15 */ "\u0123,\u011F",
+    };
+
+    /* Language mk: Macedonian */
+    private static final String[] LANGUAGE_mk = {
+        /* 0~ */
+        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,
+        /* ~34 */
+        // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
+        /* 35 */ "\u0455",
+        // U+045C: "ќ" CYRILLIC SMALL LETTER KJE
+        /* 36 */ "\u045C",
+        // U+0437: "з" CYRILLIC SMALL LETTER ZE
+        /* 37 */ "\u0437",
+        // U+0453: "ѓ" CYRILLIC SMALL LETTER GJE
+        /* 38 */ "\u0453",
+        // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
+        /* 39 */ "\u0450",
+        // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
+        /* 40 */ "\u045D",
+        /* 41 */ null,
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK  TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
+        /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+    };
+
+    /* Language nb: Norwegian Bokmål */
+    private static final String[] LANGUAGE_nb = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E0,\u00E4,\u00E1,\u00E2,\u00E3,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
+        /* 2 */ null,
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F4,\u00F2,\u00F3,\u00F6,\u00F5,\u0153,\u014D",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+        /* 5~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~19 */
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        /* 20 */ "\u00E5",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 21 */ "\u00F8",
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 22 */ "\u00E6",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 23 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 24 */ "\u00E4",
+    };
+
+    /* Language nl: Dutch */
+    private static final String[] LANGUAGE_nl = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E1,\u00E4,\u00E2,\u00E0,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u00E9,\u00EB,\u00EA,\u00E8,\u0119,\u0117,\u0113",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+0133: "ij" LATIN SMALL LIGATURE IJ
+        /* 2 */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+        /* 5 */ null,
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u00F1,\u0144",
+        /* 7 */ null,
+        // U+0133: "ij" LATIN SMALL LIGATURE IJ
+        /* 8 */ "\u0133",
+    };
+
+    /* Language pl: Polish */
+    private static final String[] LANGUAGE_pl = {
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u0105,\u00E1,\u00E0,\u00E2,\u00E4,\u00E6,\u00E3,\u00E5,\u0101",
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        /* 1 */ "\u0119,\u00E8,\u00E9,\u00EA,\u00EB,\u0117,\u0113",
+        /* 2 */ null,
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
+        /* 4 */ null,
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u015B,\u00DF,\u0161",
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        /* 6 */ "\u0144,\u00F1",
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u0107,\u00E7,\u010D",
+        /* 8~ */
+        null, null, null, null,
+        /* ~11 */
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        /* 12 */ "\u017C,\u017A,\u017E",
+        /* 13 */ null,
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        /* 14 */ "\u0142",
+    };
+
+    /* Language pt: Portuguese */
+    private static final String[] LANGUAGE_pt = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E1,\u00E3,\u00E0,\u00E2,\u00E4,\u00E5,\u00E6,\u00AA",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        /* 1 */ "\u00E9,\u00EA,\u00E8,\u0119,\u0117,\u0113,\u00EB",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00ED,\u00EE,\u00EC,\u00EF,\u012F,\u012B",
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F3,\u00F5,\u00F4,\u00F2,\u00F6,\u0153,\u00F8,\u014D,\u00BA",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+        /* 5 */ null,
+        /* 6 */ null,
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u00E7,\u010D,\u0107",
+    };
+
+    /* Language rm: Raeto-Romance */
+    private static final String[] LANGUAGE_rm = {
+        /* 0~ */
+        null, null, null,
+        /* ~2 */
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 3 */ "\u00F2,\u00F3,\u00F6,\u00F4,\u00F5,\u0153,\u00F8",
+    };
+
+    /* Language ro: Romanian */
+    private static final String[] LANGUAGE_ro = {
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        /* 0 */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101",
+        /* 1 */ null,
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+        /* 3 */ null,
+        /* 4 */ null,
+        // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u0219,\u00DF,\u015B,\u0161",
+        /* 6~ */
+        null, null, null, null, null,
+        /* ~10 */
+        // U+021B: "ț" LATIN SMALL LETTER T WITH COMMA BELOW
+        /* 11 */ "\u021B",
+    };
+
+    /* Language ru: Russian */
+    private static final String[] LANGUAGE_ru = {
+        /* 0~ */
+        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,
+        /* ~24 */
+        // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+        /* 25 */ "\u0449",
+        // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+        /* 26 */ "\u044B",
+        // U+0438: "и" CYRILLIC SMALL LETTER I
+        /* 27 */ "\u0438",
+        /* 28 */ null,
+        // U+0451: "ё" CYRILLIC SMALL LETTER IO
+        /* 29 */ "\u0451",
+        /* 30 */ null,
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 31 */ "\u044A",
+        /* 32 */ null,
+        /* 33 */ null,
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 34 */ "\u044A",
+    };
+
+    /* Language sk: Slovak */
+    private static final String[] LANGUAGE_sk = {
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        /* 0 */ "\u00E1,\u00E4,\u0101,\u00E0,\u00E2,\u00E3,\u00E5,\u00E6,\u0105",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        /* 1 */ "\u00E9,\u011B,\u0113,\u0117,\u00E8,\u00EA,\u00EB,\u0119",
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        /* 2 */ "\u00ED,\u012B,\u012F,\u00EC,\u00EE,\u00EF,\u0131",
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 3 */ "\u00F4,\u00F3,\u00F6,\u00F2,\u00F5,\u0153,\u0151,\u00F8",
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        /* 4 */ "\u00FA,\u016F,\u00FC,\u016B,\u0173,\u00F9,\u00FB,\u0171",
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        /* 5 */ "\u0161,\u00DF,\u015B,\u015F",
+        // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
+        // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        /* 6 */ "\u0148,\u0146,\u00F1,\u0144,\u0144",
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u00E7,\u0107",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        /* 8 */ "\u00FD,\u00FF",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        /* 9 */ "\u010F",
+        // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+        /* 10 */ "\u0155,\u0159,\u0157",
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+        /* 11 */ "\u0165,\u0163",
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        /* 12 */ "\u017E,\u017C,\u017A",
+        // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+        /* 13 */ "\u0137",
+        // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+        // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+        // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        /* 14 */ "\u013E,\u013A,\u013C,\u0142",
+        // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        /* 15 */ "\u0123,\u011F",
+    };
+
+    /* Language sl: Slovenian */
+    private static final String[] LANGUAGE_sl = {
+        /* 0~ */
+        null, null, null, null, null,
+        /* ~4 */
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u0161",
+        /* 6 */ null,
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        /* 7 */ "\u010D,\u0107",
+        /* 8 */ null,
+        // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+        /* 9 */ "\u0111",
+        /* 10 */ null,
+        /* 11 */ null,
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        /* 12 */ "\u017E",
+    };
+
+    /* Language sr: Serbian */
+    private static final String[] LANGUAGE_sr = {
+        /* 0~ */
+        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,
+        /* ~34 */
+        // U+0437: "з" CYRILLIC SMALL LETTER ZE
+        /* 35 */ "\u0437",
+        // U+045B: "ћ" CYRILLIC SMALL LETTER TSHE
+        /* 36 */ "\u045B",
+        // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
+        /* 37 */ "\u0455",
+        // U+0452: "ђ" CYRILLIC SMALL LETTER DJE
+        /* 38 */ "\u0452",
+        // U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
+        /* 39 */ "\u0450",
+        // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
+        /* 40 */ "\u045D",
+        /* 41 */ null,
+        // U+2018: "‘" LEFT SINGLE QUOTATION MARK
+        // U+2019: "’" RIGHT SINGLE QUOTATION MARK
+        // U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+        // U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+        // U+201C: "“" LEFT DOUBLE QUOTATION MARK
+        // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+        // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+        // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK  TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string>
+        /* 42 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB",
+        // TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK.  <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+        /* 43 */ "!fixedColumnOrder!5,\u201E,\u201C,\u201D,\u00AB,\u00BB,\u2018,\u2019,\u201A,\u201B",
+    };
+
+    /* Language sv: Swedish */
+    private static final String[] LANGUAGE_sv = {
+        /* 0 */ null,
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        /* 1 */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119",
+        /* 2 */ null,
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u0153,\u00F4,\u00F2,\u00F3,\u00F5,\u014D",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u00DF,\u015B,\u0161",
+        /* 6~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~19 */
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        /* 20 */ "\u00E5",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 21 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 22 */ "\u00E4",
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        /* 23 */ "\u00F8",
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        /* 24 */ "\u00E6",
+    };
+
+    /* Language tr: Turkish */
+    private static final String[] LANGUAGE_tr = {
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        /* 0 */ "\u00E2",
+        /* 1 */ null,
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        /* 2 */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        /* 3 */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        /* 5 */ "\u015F,\u00DF,\u015B,\u0161",
+        /* 6 */ null,
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u00E7,\u0107,\u010D",
+        /* 8~ */
+        null, null, null, null, null, null, null,
+        /* ~14 */
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        /* 15 */ "\u011F",
+    };
+
+    /* Language uk: Ukrainian */
+    private static final String[] LANGUAGE_uk = {
+        /* 0~ */
+        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,
+        /* ~24 */
+        // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+        /* 25 */ "\u0449",
+        // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+        /* 26 */ "\u0456",
+        // U+0438: "и" CYRILLIC SMALL LETTER I
+        /* 27 */ "\u0438",
+        /* 28~ */
+        null, null, null,
+        /* ~30 */
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 31 */ "\u044A",
+        // U+0457: "ї" CYRILLIC SMALL LETTER YI
+        /* 32 */ "\u0457",
+        /* 33 */ null,
+        // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+        /* 34 */ "\u044A",
+    };
+
+    /* Language vi: Vietnamese */
+    private static final String[] LANGUAGE_vi = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+1EA3: "ả" LATIN SMALL LETTER A WITH HOOK ABOVE
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+1EA1: "ạ" LATIN SMALL LETTER A WITH DOT BELOW
+        // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
+        // U+1EB1: "ằ" LATIN SMALL LETTER A WITH BREVE AND GRAVE
+        // U+1EAF: "ắ" LATIN SMALL LETTER A WITH BREVE AND ACUTE
+        // U+1EB3: "ẳ" LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+        // U+1EB5: "ẵ" LATIN SMALL LETTER A WITH BREVE AND TILDE
+        // U+1EB7: "ặ" LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+1EA7: "ầ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+        // U+1EA5: "ấ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+        // U+1EA9: "ẩ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+        // U+1EAB: "ẫ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+        // U+1EAD: "ậ" LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+        /* 0 */ "\u00E0,\u00E1,\u1EA3,\u00E3,\u1EA1,\u0103,\u1EB1,\u1EAF,\u1EB3,\u1EB5,\u1EB7,\u00E2,\u1EA7,\u1EA5,\u1EA9,\u1EAB,\u1EAD",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE
+        // U+1EBD: "ẽ" LATIN SMALL LETTER E WITH TILDE
+        // U+1EB9: "ẹ" LATIN SMALL LETTER E WITH DOT BELOW
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+1EC1: "ề" LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+        // U+1EBF: "ế" LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+        // U+1EC3: "ể" LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+        // U+1EC5: "ễ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+        // U+1EC7: "ệ" LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+        /* 1 */ "\u00E8,\u00E9,\u1EBB,\u1EBD,\u1EB9,\u00EA,\u1EC1,\u1EBF,\u1EC3,\u1EC5,\u1EC7",
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+1EC9: "ỉ" LATIN SMALL LETTER I WITH HOOK ABOVE
+        // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE
+        // U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW
+        /* 2 */ "\u00EC,\u00ED,\u1EC9,\u0129,\u1ECB",
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+1ECF: "ỏ" LATIN SMALL LETTER O WITH HOOK ABOVE
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+1ECD: "ọ" LATIN SMALL LETTER O WITH DOT BELOW
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+1ED3: "ồ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+        // U+1ED1: "ố" LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+        // U+1ED5: "ổ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+        // U+1ED7: "ỗ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+        // U+1ED9: "ộ" LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+        // U+01A1: "ơ" LATIN SMALL LETTER O WITH HORN
+        // U+1EDD: "ờ" LATIN SMALL LETTER O WITH HORN AND GRAVE
+        // U+1EDB: "ớ" LATIN SMALL LETTER O WITH HORN AND ACUTE
+        // U+1EDF: "ở" LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+        // U+1EE1: "ỡ" LATIN SMALL LETTER O WITH HORN AND TILDE
+        // U+1EE3: "ợ" LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+        /* 3 */ "\u00F2,\u00F3,\u1ECF,\u00F5,\u1ECD,\u00F4,\u1ED3,\u1ED1,\u1ED5,\u1ED7,\u1ED9,\u01A1,\u1EDD,\u1EDB,\u1EDF,\u1EE1,\u1EE3",
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+1EE7: "ủ" LATIN SMALL LETTER U WITH HOOK ABOVE
+        // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE
+        // U+1EE5: "ụ" LATIN SMALL LETTER U WITH DOT BELOW
+        // U+01B0: "ư" LATIN SMALL LETTER U WITH HORN
+        // U+1EEB: "ừ" LATIN SMALL LETTER U WITH HORN AND GRAVE
+        // U+1EE9: "ứ" LATIN SMALL LETTER U WITH HORN AND ACUTE
+        // U+1EED: "ử" LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+        // U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE
+        // U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+        /* 4 */ "\u00F9,\u00FA,\u1EE7,\u0169,\u1EE5,\u01B0,\u1EEB,\u1EE9,\u1EED,\u1EEF,\u1EF1",
+        /* 5~ */
+        null, null, null,
+        /* ~7 */
+        // U+1EF3: "ỳ" LATIN SMALL LETTER Y WITH GRAVE
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+1EF7: "ỷ" LATIN SMALL LETTER Y WITH HOOK ABOVE
+        // U+1EF9: "ỹ" LATIN SMALL LETTER Y WITH TILDE
+        // U+1EF5: "ỵ" LATIN SMALL LETTER Y WITH DOT BELOW
+        /* 8 */ "\u1EF3,\u00FD,\u1EF7,\u1EF9,\u1EF5",
+        // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+        /* 9 */ "\u0111",
+    };
+
+    /* Language zz: No language */
+    private static final String[] LANGUAGE_zz = {
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
+        // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX
+        // U+00E3: "ã" LATIN SMALL LETTER A WITH TILDE
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        // U+00E5: "å" LATIN SMALL LETTER A WITH RING ABOVE
+        // U+00E6: "æ" LATIN SMALL LETTER AE
+        // U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
+        // U+0103: "ă" LATIN SMALL LETTER A WITH BREVE
+        // U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
+        // U+00AA: "ª" FEMININE ORDINAL INDICATOR
+        /* 0 */ "\u00E0,\u00E1,\u00E2,\u00E3,\u00E4,\u00E5,\u00E6,\u00E3,\u00E5,\u0101,\u0103,\u0105,\u00AA",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        // U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
+        // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
+        // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
+        // U+0115: "ĕ" LATIN SMALL LETTER E WITH BREVE
+        // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
+        // U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
+        // U+011B: "ě" LATIN SMALL LETTER E WITH CARON
+        /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113,\u0115,\u0117,\u0119,\u011B",
+        // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+        // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+        // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+        // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+        // U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE
+        // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+        // U+012D: "ĭ" LATIN SMALL LETTER I WITH BREVE
+        // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+        // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+        // U+0133: "ij" LATIN SMALL LIGATURE IJ
+        /* 2 */ "\u00EC,\u00ED,\u00EE,\u00EF,\u0129,\u012B,\u012D,\u012F,\u0131,\u0133",
+        // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+        // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+        // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+        // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+        // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+        // U+014F: "ŏ" LATIN SMALL LETTER O WITH BREVE
+        // U+0151: "ő" LATIN SMALL LETTER O WITH DOUBLE ACUTE
+        // U+0153: "œ" LATIN SMALL LIGATURE OE
+        // U+00BA: "º" MASCULINE ORDINAL INDICATOR
+        /* 3 */ "\u00F2,\u00F3,\u00F4,\u00F5,\u00F6,\u00F8,\u014D,\u014F,\u0151,\u0153,\u00BA",
+        // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+        // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+        // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        // U+0169: "ũ" LATIN SMALL LETTER U WITH TILDE
+        // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+        // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
+        // U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
+        // U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
+        // U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
+        /* 4 */ "\u00F9,\u00FA,\u00FB,\u00FC,\u0169,\u016B,\u016D,\u016F,\u0171,\u0173",
+        // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+        // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+        // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
+        // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+        // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+        // U+017F: "ſ" LATIN SMALL LETTER LONG S
+        /* 5 */ "\u00DF,\u015B,\u015D,\u015F,\u0161,\u017F",
+        // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+        // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
+        // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
+        // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
+        // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+        // U+014B: "ŋ" LATIN SMALL LETTER ENG
+        /* 6 */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B",
+        // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+        // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+        // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
+        // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE
+        // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+        /* 7 */ "\u00E7,\u0107,\u0109,\u010B,\u010D",
+        // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
+        // U+0177: "ŷ" LATIN SMALL LETTER Y WITH CIRCUMFLEX
+        // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
+        // U+0133: "ij" LATIN SMALL LIGATURE IJ
+        /* 8 */ "\u00FD,\u0177,\u00FF,\u0133",
+        // U+010F: "ď" LATIN SMALL LETTER D WITH CARON
+        // U+0111: "đ" LATIN SMALL LETTER D WITH STROKE
+        // U+00F0: "ð" LATIN SMALL LETTER ETH
+        /* 9 */ "\u010F,\u0111,\u00F0",
+        // U+0155: "ŕ" LATIN SMALL LETTER R WITH ACUTE
+        // U+0157: "ŗ" LATIN SMALL LETTER R WITH CEDILLA
+        // U+0159: "ř" LATIN SMALL LETTER R WITH CARON
+        /* 10 */ "\u0155,\u0157,\u0159",
+        // U+00FE: "þ" LATIN SMALL LETTER THORN
+        // U+0163: "ţ" LATIN SMALL LETTER T WITH CEDILLA
+        // U+0165: "ť" LATIN SMALL LETTER T WITH CARON
+        // U+0167: "ŧ" LATIN SMALL LETTER T WITH STROKE
+        /* 11 */ "\u00FE,\u0163,\u0165,\u0167",
+        // U+017A: "ź" LATIN SMALL LETTER Z WITH ACUTE
+        // U+017C: "ż" LATIN SMALL LETTER Z WITH DOT ABOVE
+        // U+017E: "ž" LATIN SMALL LETTER Z WITH CARON
+        /* 12 */ "\u017A,\u017C,\u017E",
+        // U+0137: "ķ" LATIN SMALL LETTER K WITH CEDILLA
+        // U+0138: "ĸ" LATIN SMALL LETTER KRA
+        /* 13 */ "\u0137,\u0138",
+        // U+013A: "ĺ" LATIN SMALL LETTER L WITH ACUTE
+        // U+013C: "ļ" LATIN SMALL LETTER L WITH CEDILLA
+        // U+013E: "ľ" LATIN SMALL LETTER L WITH CARON
+        // U+0140: "ŀ" LATIN SMALL LETTER L WITH MIDDLE DOT
+        // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
+        /* 14 */ "\u013A,\u013C,\u013E,\u0140,\u0142",
+        // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
+        // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+        // U+0121: "ġ" LATIN SMALL LETTER G WITH DOT ABOVE
+        // U+0123: "ģ" LATIN SMALL LETTER G WITH CEDILLA
+        /* 15 */ "\u011D,\u011F,\u0121,\u0123",
+        /* 16 */ null,
+        // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX
+        /* 17 */ "\u0125",
+        // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
+        /* 18 */ "\u0135",
+        // U+0175: "ŵ" LATIN SMALL LETTER W WITH CIRCUMFLEX
+        /* 19 */ "\u0175",
+    };
+
+    private static final Object[] LANGUAGES_AND_LABELS = {
+        "DEFAULT", LANGUAGE_DEFAULT, /* default */
+        "ar", LANGUAGE_ar, /* Arabic */
+        "be", LANGUAGE_be, /* Belarusian */
+        "ca", LANGUAGE_ca, /* Catalan */
+        "cs", LANGUAGE_cs, /* Czech */
+        "da", LANGUAGE_da, /* Danish */
+        "de", LANGUAGE_de, /* German */
+        "en", LANGUAGE_en, /* English */
+        "es", LANGUAGE_es, /* Spanish */
+        "et", LANGUAGE_et, /* Estonian */
+        "fa", LANGUAGE_fa, /* Persian */
+        "fi", LANGUAGE_fi, /* Finnish */
+        "fr", LANGUAGE_fr, /* French */
+        "hi", LANGUAGE_hi, /* Hindi */
+        "hr", LANGUAGE_hr, /* Croatian */
+        "hu", LANGUAGE_hu, /* Hungarian */
+        "is", LANGUAGE_is, /* Icelandic */
+        "it", LANGUAGE_it, /* Italian */
+        "iw", LANGUAGE_iw, /* Hebrew */
+        "ky", LANGUAGE_ky, /* Kirghiz */
+        "lt", LANGUAGE_lt, /* Lithuanian */
+        "lv", LANGUAGE_lv, /* Latvian */
+        "mk", LANGUAGE_mk, /* Macedonian */
+        "nb", LANGUAGE_nb, /* Norwegian Bokmål */
+        "nl", LANGUAGE_nl, /* Dutch */
+        "pl", LANGUAGE_pl, /* Polish */
+        "pt", LANGUAGE_pt, /* Portuguese */
+        "rm", LANGUAGE_rm, /* Raeto-Romance */
+        "ro", LANGUAGE_ro, /* Romanian */
+        "ru", LANGUAGE_ru, /* Russian */
+        "sk", LANGUAGE_sk, /* Slovak */
+        "sl", LANGUAGE_sl, /* Slovenian */
+        "sr", LANGUAGE_sr, /* Serbian */
+        "sv", LANGUAGE_sv, /* Swedish */
+        "tr", LANGUAGE_tr, /* Turkish */
+        "uk", LANGUAGE_uk, /* Ukrainian */
+        "vi", LANGUAGE_vi, /* Vietnamese */
+        "zz", LANGUAGE_zz, /* No language */
+    };
+
+    static {
+        int id = 0;
+        for (final String name : NAMES) {
+            sNameToIdMap.put(name, id++);
+        }
+
+        for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) {
+            final String language = (String)LANGUAGES_AND_LABELS[i];
+            final String[] labels = (String[])LANGUAGES_AND_LABELS[i + 1];
+            sLocaleToLabelsMap.put(language, labels);
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index cc7540e..2d958e1 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -17,11 +17,8 @@
 package com.android.inputmethod.latin;
 
 import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
 
 import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index e4d8396..b0c2adc 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -20,11 +20,8 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
 import android.util.Log;
 
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Locale;
@@ -155,14 +152,8 @@
      * Returns a file address from a resource, or null if it cannot be opened.
      */
     private static AssetFileAddress loadFallbackResource(final Context context,
-            final int fallbackResId, final Locale locale) {
-        final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
-            @Override
-            protected AssetFileDescriptor job(Resources res) {
-                return res.openRawResourceFd(fallbackResId);
-            }
-        };
-        final AssetFileDescriptor afd = job.runInLocale(context.getResources(), locale);
+            final int fallbackResId) {
+        final AssetFileDescriptor afd = context.getResources().openRawResourceFd(fallbackResId);
         if (afd == null) {
             Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId="
                     + fallbackResId);
@@ -264,13 +255,13 @@
      * - Uses a content provider to get a public dictionary set, as per the protocol described
      *   in BinaryDictionaryFileDumper.
      * If that fails:
-     * - Gets a file name from the fallback resource passed as an argument.
+     * - Gets a file name from the built-in dictionary for this locale, if any.
      * If that fails:
      * - Returns null.
      * @return The list of addresses of valid dictionary files, or null.
      */
     public static ArrayList<AssetFileAddress> getDictionaryFiles(final Locale locale,
-            final Context context, final int fallbackResId) {
+            final Context context) {
 
         // cacheWordListsFromContentProvider returns the list of files it copied to local
         // storage, but we don't really care about what was copied NOW: what we want is the
@@ -299,8 +290,9 @@
         }
 
         if (!foundMainDict && dictPackSettings.isWordListActive(mainDictId)) {
-            final AssetFileAddress fallbackAsset = loadFallbackResource(context, fallbackResId,
-                    locale);
+            final int fallbackResId =
+                    DictionaryFactory.getMainDictionaryResourceId(context.getResources(), locale);
+            final AssetFileAddress fallbackAsset = loadFallbackResource(context, fallbackResId);
             if (null != fallbackAsset) {
                 fileList.add(fallbackAsset);
             }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index fedb454..bf05f3b 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -21,8 +21,6 @@
 import android.content.res.Resources;
 import android.util.Log;
 
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -38,24 +36,22 @@
      * Initializes a dictionary from a dictionary pack, with explicit flags.
      *
      * This searches for a content provider providing a dictionary pack for the specified
-     * locale. If none is found, it falls back to using the resource passed as fallBackResId
-     * as a dictionary.
+     * locale. If none is found, it falls back to the built-in dictionary - if any.
      * @param context application context for reading resources
      * @param locale the locale for which to create the dictionary
-     * @param fallbackResId the id of the resource to use as a fallback if no pack is found
      * @param useFullEditDistance whether to use the full edit distance in suggestions
      * @return an initialized instance of DictionaryCollection
      */
     public static DictionaryCollection createDictionaryFromManager(final Context context,
-            final Locale locale, final int fallbackResId, final boolean useFullEditDistance) {
+            final Locale locale, final boolean useFullEditDistance) {
         if (null == locale) {
             Log.e(TAG, "No locale defined for dictionary");
-            return new DictionaryCollection(createBinaryDictionary(context, fallbackResId, locale));
+            return new DictionaryCollection(createBinaryDictionary(context, locale));
         }
 
         final LinkedList<Dictionary> dictList = new LinkedList<Dictionary>();
         final ArrayList<AssetFileAddress> assetFileList =
-                BinaryDictionaryGetter.getDictionaryFiles(locale, context, fallbackResId);
+                BinaryDictionaryGetter.getDictionaryFiles(locale, context);
         if (null != assetFileList) {
             for (final AssetFileAddress f : assetFileList) {
                 final BinaryDictionary binaryDictionary =
@@ -77,17 +73,14 @@
      * Initializes a dictionary from a dictionary pack, with default flags.
      *
      * This searches for a content provider providing a dictionary pack for the specified
-     * locale. If none is found, it falls back to using the resource passed as fallBackResId
-     * as a dictionary.
+     * locale. If none is found, it falls back to the built-in dictionary, if any.
      * @param context application context for reading resources
      * @param locale the locale for which to create the dictionary
-     * @param fallbackResId the id of the resource to use as a fallback if no pack is found
      * @return an initialized instance of DictionaryCollection
      */
     public static DictionaryCollection createDictionaryFromManager(final Context context,
-            final Locale locale, final int fallbackResId) {
-        return createDictionaryFromManager(context, locale, fallbackResId,
-                false /* useFullEditDistance */);
+            final Locale locale) {
+        return createDictionaryFromManager(context, locale, false /* useFullEditDistance */);
     }
 
     /**
@@ -98,16 +91,11 @@
      * @return an initialized instance of BinaryDictionary
      */
     protected static BinaryDictionary createBinaryDictionary(final Context context,
-            final int resId, final Locale locale) {
+            final Locale locale) {
         AssetFileDescriptor afd = null;
         try {
-            final RunInLocale<AssetFileDescriptor> job = new RunInLocale<AssetFileDescriptor>() {
-                @Override
-                protected AssetFileDescriptor job(Resources res) {
-                    return res.openRawResourceFd(resId);
-                }
-            };
-            afd = job.runInLocale(context.getResources(), locale);
+            final int resId = getMainDictionaryResourceId(context.getResources(), locale);
+            afd = context.getResources().openRawResourceFd(resId);
             if (afd == null) {
                 Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);
                 return null;
@@ -123,7 +111,7 @@
             return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(),
                     false /* useFullEditDistance */, locale);
         } catch (android.content.res.Resources.NotFoundException e) {
-            Log.e(TAG, "Could not find the resource. resId=" + resId);
+            Log.e(TAG, "Could not find the resource");
             return null;
         } finally {
             if (null != afd) {
@@ -163,41 +151,31 @@
      * @return whether a (non-placeholder) dictionary is available or not.
      */
     public static boolean isDictionaryAvailable(Context context, Locale locale) {
-        final RunInLocale<Boolean> job = new RunInLocale<Boolean>() {
-            @Override
-            protected Boolean job(Resources res) {
-                final int resourceId = getMainDictionaryResourceId(res);
-                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
-                final boolean hasDictionary = isFullDictionary(afd);
-                try {
-                    if (null != afd) afd.close();
-                } catch (java.io.IOException e) {
-                    /* Um, what can we do here exactly? */
-                }
-                return hasDictionary;
-            }
-        };
-        return job.runInLocale(context.getResources(), locale);
+        final Resources res = context.getResources();
+        final int resourceId = getMainDictionaryResourceId(res, locale);
+        final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+        final boolean hasDictionary = isFullDictionary(afd);
+        try {
+            if (null != afd) afd.close();
+        } catch (java.io.IOException e) {
+            /* Um, what can we do here exactly? */
+        }
+        return hasDictionary;
     }
 
     // TODO: Do not use the size of the dictionary as an unique dictionary ID.
     public static Long getDictionaryId(final Context context, final Locale locale) {
-        final RunInLocale<Long> job = new RunInLocale<Long>() {
-            @Override
-            protected Long job(Resources res) {
-                final int resourceId = getMainDictionaryResourceId(res);
-                final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
-                final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
-                        ? afd.getLength()
-                        : null;
-                try {
-                    if (null != afd) afd.close();
-                } catch (java.io.IOException e) {
-                }
-                return size;
-            }
-        };
-        return job.runInLocale(context.getResources(), locale);
+        final Resources res = context.getResources();
+        final int resourceId = getMainDictionaryResourceId(res, locale);
+        final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+        final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
+                ? afd.getLength()
+                : null;
+        try {
+            if (null != afd) afd.close();
+        } catch (java.io.IOException e) {
+        }
+        return size;
     }
 
     // TODO: Find the Right Way to find out whether the resource is a placeholder or not.
@@ -214,13 +192,32 @@
         return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH);
     }
 
+    private static final String DEFAULT_MAIN_DICT = "main";
+    private static final String MAIN_DICT_PREFIX = "main_";
+
     /**
      * Returns a main dictionary resource id
+     * @param locale dictionary locale
      * @return main dictionary resource id
      */
-    public static int getMainDictionaryResourceId(Resources res) {
-        final String MAIN_DIC_NAME = "main";
-        String packageName = LatinIME.class.getPackage().getName();
-        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
+    public static int getMainDictionaryResourceId(Resources res, Locale locale) {
+        final String packageName = LatinIME.class.getPackage().getName();
+        int resId;
+
+        // Try to find main_language_country dictionary.
+        if (!locale.getCountry().isEmpty()) {
+            final String dictLanguageCountry = MAIN_DICT_PREFIX + locale.toString().toLowerCase();
+            if ((resId = res.getIdentifier(dictLanguageCountry, "raw", packageName)) != 0) {
+                return resId;
+            }
+        }
+
+        // Try to find main_language dictionary.
+        final String dictLanguage = MAIN_DICT_PREFIX + locale.getLanguage();
+        if ((resId = res.getIdentifier(dictLanguage, "raw", packageName)) != 0) {
+            return resId;
+        }
+
+        return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", packageName);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
new file mode 100644
index 0000000..53e8b74
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2012 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.latin;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+import com.android.inputmethod.latin.makedict.FusionDictionary;
+import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Abstract base class for an expandable dictionary that can be created and updated dynamically
+ * during runtime. When updated it automatically generates a new binary dictionary to handle future
+ * queries in native code. This binary dictionary is written to internal storage, and potentially
+ * shared across multiple ExpandableBinaryDictionary instances. Updates to each dictionary filename
+ * are controlled across multiple instances to ensure that only one instance can update the same
+ * dictionary at the same time.
+ */
+abstract public class ExpandableBinaryDictionary extends Dictionary {
+
+    /** Used for Log actions from this class */
+    private static final String TAG = ExpandableBinaryDictionary.class.getSimpleName();
+
+    /** Whether to print debug output to log */
+    private static boolean DEBUG = false;
+
+    /**
+     * The maximum length of a word in this dictionary. This is the same value as the binary
+     * dictionary.
+     */
+    protected static final int MAX_WORD_LENGTH = BinaryDictionary.MAX_WORD_LENGTH;
+
+    /**
+     * A static map of locks, each of which controls access to a single binary dictionary file. They
+     * ensure that only one instance can update the same dictionary at the same time. The key for
+     * this map is the filename and the value is the shared dictionary controller associated with
+     * that filename.
+     */
+    private static final HashMap<String, DictionaryController> sSharedDictionaryControllers =
+            new HashMap<String, DictionaryController>();
+
+    /** The application context. */
+    protected final Context mContext;
+
+    /**
+     * The binary dictionary generated dynamically from the fusion dictionary. This is used to
+     * answer unigram and bigram queries.
+     */
+    private BinaryDictionary mBinaryDictionary;
+
+    /** The expandable fusion dictionary used to generate the binary dictionary. */
+    private FusionDictionary mFusionDictionary;
+
+    /** The dictionary type id. */
+    public final int mDicTypeId;
+
+    /**
+     * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple
+     * dictionary instances with the same filename is supported, with access controlled by
+     * DictionaryController.
+     */
+    private final String mFilename;
+
+    /** Controls access to the shared binary dictionary file across multiple instances. */
+    private final DictionaryController mSharedDictionaryController;
+
+    /** Controls access to the local binary dictionary for this instance. */
+    private final DictionaryController mLocalDictionaryController = new DictionaryController();
+
+    /**
+     * Abstract method for loading the unigrams and bigrams of a given dictionary in a background
+     * thread.
+     */
+    protected abstract void loadDictionaryAsync();
+
+    /**
+     * Gets the shared dictionary controller for the given filename.
+     */
+    private static synchronized DictionaryController getSharedDictionaryController(
+            String filename) {
+        DictionaryController controller = sSharedDictionaryControllers.get(filename);
+        if (controller == null) {
+            controller = new DictionaryController();
+            sSharedDictionaryControllers.put(filename, controller);
+        }
+        return controller;
+    }
+
+    /**
+     * Creates a new expandable binary dictionary.
+     *
+     * @param context The application context of the parent.
+     * @param filename The filename for this binary dictionary. Multiple dictionaries with the same
+     *        filename is supported.
+     * @param dictType The type of this dictionary.
+     */
+    public ExpandableBinaryDictionary(
+            final Context context, final String filename, final int dictType) {
+        mDicTypeId = dictType;
+        mFilename = filename;
+        mContext = context;
+        mBinaryDictionary = null;
+        mSharedDictionaryController = getSharedDictionaryController(filename);
+        clearFusionDictionary();
+    }
+
+    /**
+     * Closes and cleans up the binary dictionary.
+     */
+    @Override
+    public void close() {
+        // Ensure that no other threads are accessing the local binary dictionary.
+        mLocalDictionaryController.lock();
+        try {
+            if (mBinaryDictionary != null) {
+                mBinaryDictionary.close();
+                mBinaryDictionary = null;
+            }
+        } finally {
+            mLocalDictionaryController.unlock();
+        }
+    }
+
+    /**
+     * Clears the fusion dictionary on the Java side. Note: Does not modify the binary dictionary on
+     * the native side.
+     */
+    public void clearFusionDictionary() {
+        mFusionDictionary = new FusionDictionary(new Node(), new FusionDictionary.DictionaryOptions(
+                new HashMap<String, String>(), false, false));
+    }
+
+    /**
+     * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes
+     * are done to update the binary dictionary.
+     */
+    // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries,
+    // considering performance regression.
+    protected void addWord(final String word, final int frequency) {
+        mFusionDictionary.add(word, frequency, null, null);
+    }
+
+    /**
+     * Sets a word bigram in the fusion dictionary. Call updateBinaryDictionary when all changes are
+     * done to update the binary dictionary.
+     */
+    // TODO: Create "cache dictionary" to cache fresh bigrams for frequently updated dictionaries,
+    // considering performance regression.
+    protected void setBigram(final String prevWord, final String word, final int frequency) {
+        mFusionDictionary.setBigram(prevWord, word, frequency);
+    }
+
+    @Override
+    public void getWords(final WordComposer codes, final WordCallback callback,
+            final ProximityInfo proximityInfo) {
+        asyncReloadDictionaryIfRequired();
+        getWordsInner(codes, callback, proximityInfo);
+    }
+
+    protected final void getWordsInner(final WordComposer codes, final WordCallback callback,
+            final ProximityInfo proximityInfo) {
+        // Ensure that there are no concurrent calls to getWords. If there are, do nothing and
+        // return.
+        if (mLocalDictionaryController.tryLock()) {
+            try {
+                if (mBinaryDictionary != null) {
+                    mBinaryDictionary.getWords(codes, callback, proximityInfo);
+                }
+            } finally {
+                mLocalDictionaryController.unlock();
+            }
+        }
+    }
+
+    @Override
+    public void getBigrams(final WordComposer codes, final CharSequence previousWord,
+            final WordCallback callback) {
+        asyncReloadDictionaryIfRequired();
+        getBigramsInner(codes, previousWord, callback);
+    }
+
+    protected void getBigramsInner(final WordComposer codes, final CharSequence previousWord,
+            final WordCallback callback) {
+        if (mLocalDictionaryController.tryLock()) {
+            try {
+                if (mBinaryDictionary != null) {
+                    mBinaryDictionary.getBigrams(codes, previousWord, callback);
+                }
+            } finally {
+                mLocalDictionaryController.unlock();
+            }
+        }
+    }
+
+    @Override
+    public boolean isValidWord(final CharSequence word) {
+        asyncReloadDictionaryIfRequired();
+        return isValidWordInner(word);
+    }
+
+    protected boolean isValidWordInner(final CharSequence word) {
+        if (mLocalDictionaryController.tryLock()) {
+            try {
+                if (mBinaryDictionary != null) {
+                    return mBinaryDictionary.isValidWord(word);
+                }
+            } finally {
+                mLocalDictionaryController.unlock();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Load the current binary dictionary from internal storage in a background thread. If no binary
+     * dictionary exists, this method will generate one.
+     */
+    protected void loadDictionary() {
+        mLocalDictionaryController.mLastUpdateRequestTime = SystemClock.uptimeMillis();
+        asyncReloadDictionaryIfRequired();
+    }
+
+    /**
+     * Loads the current binary dictionary from internal storage. Assumes the dictionary file
+     * exists.
+     */
+    protected void loadBinaryDictionary() {
+        if (DEBUG) {
+            Log.d(TAG, "Loading binary dictionary: request="
+                    + mSharedDictionaryController.mLastUpdateRequestTime + " update="
+                    + mSharedDictionaryController.mLastUpdateTime);
+        }
+
+        final File file = new File(mContext.getFilesDir(), mFilename);
+        final String filename = file.getAbsolutePath();
+        final long length = file.length();
+
+        // Build the new binary dictionary
+        final BinaryDictionary newBinaryDictionary =
+                new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */,
+                        null);
+
+        if (mBinaryDictionary != null) {
+            // Ensure all threads accessing the current dictionary have finished before swapping in
+            // the new one.
+            final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
+            mLocalDictionaryController.lock();
+            mBinaryDictionary = newBinaryDictionary;
+            mLocalDictionaryController.unlock();
+            oldBinaryDictionary.close();
+        } else {
+            mBinaryDictionary = newBinaryDictionary;
+        }
+    }
+
+    /**
+     * Generates and writes a new binary dictionary based on the contents of the fusion dictionary.
+     */
+    private void generateBinaryDictionary() {
+        if (DEBUG) {
+            Log.d(TAG, "Generating binary dictionary: request="
+                    + mSharedDictionaryController.mLastUpdateRequestTime + " update="
+                    + mSharedDictionaryController.mLastUpdateTime);
+        }
+
+        loadDictionaryAsync();
+
+        final File file = new File(mContext.getFilesDir(), mFilename);
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(file);
+            BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, 1);
+            out.flush();
+            out.close();
+            clearFusionDictionary();
+        } catch (IOException e) {
+            Log.e(TAG, "IO exception while writing file: " + e);
+        } catch (UnsupportedFormatException e) {
+            Log.e(TAG, "Unsupported format: " + e);
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets whether or not the dictionary is out of date and requires a reload.
+     */
+    protected void setRequiresReload(final boolean reload) {
+        final long time = reload ? SystemClock.uptimeMillis() : 0;
+        mSharedDictionaryController.mLastUpdateRequestTime = time;
+        mLocalDictionaryController.mLastUpdateRequestTime = time;
+        if (DEBUG) {
+            Log.d(TAG, "Reload request: request=" + time + " update="
+                    + mSharedDictionaryController.mLastUpdateTime);
+        }
+    }
+
+    /**
+     * Reloads the dictionary if required. Reload will occur asynchronously in a separate thread.
+     */
+    void asyncReloadDictionaryIfRequired() {
+        new AsyncReloadDictionaryTask().start();
+    }
+
+    /**
+     * Reloads the dictionary if required. Access is controlled on a per dictionary file basis and
+     * supports concurrent calls from multiple instances that share the same dictionary file.
+     */
+    protected final void syncReloadDictionaryIfRequired() {
+        if (mBinaryDictionary != null && !mLocalDictionaryController.isOutOfDate()) {
+            return;
+        }
+
+        // Ensure that only one thread attempts to read or write to the shared binary dictionary
+        // file at the same time.
+        mSharedDictionaryController.lock();
+        try {
+            final long time = SystemClock.uptimeMillis();
+            if (mSharedDictionaryController.isOutOfDate() || !dictionaryFileExists()) {
+                // If the shared dictionary file does not exist or is out of date, the first
+                // instance that acquires the lock will generate a new one.
+                mSharedDictionaryController.mLastUpdateTime = time;
+                mLocalDictionaryController.mLastUpdateTime = time;
+                generateBinaryDictionary();
+                loadBinaryDictionary();
+            } else if (mLocalDictionaryController.isOutOfDate()) {
+                // Otherwise, if only the local dictionary for this instance is out of date, load
+                // the shared dictionary from file.
+                mLocalDictionaryController.mLastUpdateTime = time;
+                loadBinaryDictionary();
+            }
+        } finally {
+            mSharedDictionaryController.unlock();
+        }
+    }
+
+    private boolean dictionaryFileExists() {
+        final File file = new File(mContext.getFilesDir(), mFilename);
+        return file.exists();
+    }
+
+    /**
+     * Thread class for asynchronously reloading and rewriting the binary dictionary.
+     */
+    private class AsyncReloadDictionaryTask extends Thread {
+        @Override
+        public void run() {
+            syncReloadDictionaryIfRequired();
+        }
+    }
+
+    /**
+     * Lock for controlling access to a given binary dictionary and for tracking whether the
+     * dictionary is out of date. Can be shared across multiple dictionary instances that access the
+     * same filename.
+     */
+    private static class DictionaryController extends ReentrantLock {
+        private volatile long mLastUpdateTime = 0;
+        private volatile long mLastUpdateRequestTime = 0;
+
+        private boolean isOutOfDate() {
+            return (mLastUpdateRequestTime > mLastUpdateTime);
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e0fa2f8..7cdeef8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -493,37 +493,28 @@
         final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
         final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale();
 
-        final Context context = this;
-        final RunInLocale<Void> job = new RunInLocale<Void>() {
-            @Override
-            protected Void job(Resources res) {
-                final ContactsDictionary oldContactsDictionary;
-                if (mSuggest != null) {
-                    oldContactsDictionary = mSuggest.getContactsDictionary();
-                    mSuggest.close();
-                } else {
-                    oldContactsDictionary = null;
-                }
+        final ContactsDictionary oldContactsDictionary;
+        if (mSuggest != null) {
+            oldContactsDictionary = mSuggest.getContactsDictionary();
+            mSuggest.close();
+        } else {
+            oldContactsDictionary = null;
+        }
 
-                int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res);
-                mSuggest = new Suggest(context, mainDicResId, keyboardLocale);
-                if (mSettingsValues.mAutoCorrectEnabled) {
-                    mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
-                }
+        mSuggest = new Suggest(this, keyboardLocale);
+        if (mSettingsValues.mAutoCorrectEnabled) {
+            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
+        }
 
-                mUserDictionary = new UserDictionary(context, localeStr);
-                mSuggest.setUserDictionary(mUserDictionary);
-                mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
+        mUserDictionary = new UserDictionary(this, localeStr);
+        mSuggest.setUserDictionary(mUserDictionary);
+        mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
 
-                resetContactsDictionary(oldContactsDictionary);
+        resetContactsDictionary(oldContactsDictionary);
 
-                mUserHistoryDictionary
-                    = new UserHistoryDictionary(context, localeStr, Suggest.DIC_USER_HISTORY);
-                mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
-                return null;
-            }
-        };
-        job.runInLocale(mResources, keyboardLocale);
+        mUserHistoryDictionary = new UserHistoryDictionary(
+                this, localeStr, Suggest.DIC_USER_HISTORY);
+        mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
     }
 
     /**
@@ -559,9 +550,7 @@
     }
 
     /* package private */ void resetSuggestMainDict() {
-        final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale();
-        int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(mResources);
-        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
+        mSuggest.resetMainDict(this, mSubtypeSwitcher.getInputLocale());
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 49ab7f9..526acf1 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -97,7 +97,7 @@
             }
         }
         final String[] suggestPuncsSpec = KeySpecParser.parseCsvString(
-                res.getString(R.string.suggested_punctuations), res, R.string.english_ime_name);
+                res.getString(R.string.suggested_punctuations), null);
         mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mSymbolsExcludedFromWordSeparators =
                 res.getString(R.string.symbols_excluded_from_word_separators);
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index fa6664b..c3f3bd5 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -104,8 +104,8 @@
 
     private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
 
-    public Suggest(final Context context, final int dictionaryResId, final Locale locale) {
-        initAsynchronously(context, dictionaryResId, locale);
+    public Suggest(final Context context, final Locale locale) {
+        initAsynchronously(context, locale);
     }
 
     /* package for test */ Suggest(final Context context, final File dictionary,
@@ -119,9 +119,8 @@
         addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_WHITELIST, mWhiteListDictionary);
     }
 
-    private void initAsynchronously(final Context context, final int dictionaryResId,
-            final Locale locale) {
-        resetMainDict(context, dictionaryResId, locale);
+    private void initAsynchronously(final Context context, final Locale locale) {
+        resetMainDict(context, locale);
 
         // TODO: read the whitelist and init the pool asynchronously too.
         // initPool should be done asynchronously now that the pool is thread-safe.
@@ -146,14 +145,13 @@
         }
     }
 
-    public void resetMainDict(final Context context, final int dictionaryResId,
-            final Locale locale) {
+    public void resetMainDict(final Context context, final Locale locale) {
         mMainDict = null;
         new Thread("InitializeBinaryDictionary") {
             @Override
             public void run() {
                 final Dictionary newMainDict = DictionaryFactory.createDictionaryFromManager(
-                        context, locale, dictionaryResId);
+                        context, locale);
                 mMainDict = newMainDict;
                 addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, newMainDict);
                 addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, newMainDict);
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
index 7bb3076..bb3ba86 100644
--- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
+++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
@@ -38,6 +38,7 @@
     // TODO: Conform to the async load contact of ExpandableDictionary
     public WhitelistDictionary(final Context context, final Locale locale) {
         super(context, Suggest.DIC_WHITELIST);
+        // TODO: Move whitelist dictionary into main dictionary.
         final RunInLocale<Void> job = new RunInLocale<Void>() {
             @Override
             protected Void job(Resources res) {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 9729614..576fbe6 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -386,10 +386,8 @@
         final int script = getScriptFromLocale(locale);
         final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo(
                 SpellCheckerProximityInfo.getProximityForScript(script));
-        final Resources resources = getResources();
-        final int fallbackResourceId = DictionaryFactory.getMainDictionaryResourceId(resources);
         final DictionaryCollection dictionaryCollection =
-                DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId,
+                DictionaryFactory.createDictionaryFromManager(this, locale,
                         true /* useFullEditDistance */);
         final String localeStr = locale.toString();
         Dictionary userDictionary = mUserDictionaries.get(localeStr);
diff --git a/tests/res/values/donottranslate.xml b/tests/res/values/donottranslate.xml
index 1ca4451..42181ed 100644
--- a/tests/res/values/donottranslate.xml
+++ b/tests/res/values/donottranslate.xml
@@ -50,7 +50,7 @@
     <string name="multiple_labels_with_escape_surrounded_by_spaces">" \\abc , d\\ef , gh\\i "</string>
     <string name="multiple_labels_with_comma_and_escape">"ab\\\\,d\\\\\\,,g\\,i"</string>
     <string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" ab\\\\ , d\\\\\\, , g\\,i "</string>
-    <string name="indirect_string">@string/multiple_chars</string>
-    <string name="indirect_string_with_literal">x,@string/multiple_chars,y</string>
-    <string name="infinite_indirection">infinite,@string/infinite_indirection,loop</string>
+    <string name="indirect_string">!label/multiple_chars</string>
+    <string name="indirect_string_with_literal">x,!label/multiple_chars,y</string>
+    <string name="infinite_indirection">infinite,!label/infinite_indirection,loop</string>
 </resources>
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
index e090031..000623b 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
@@ -16,22 +16,37 @@
 
 package com.android.inputmethod.keyboard.internal;
 
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
 
-import com.android.inputmethod.latin.tests.R;
-
+import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 
 public class KeySpecParserCsvTests extends AndroidTestCase {
-    private Resources mTestResources;
+    private final KeyboardLabelsSet mLabelsSet = new KeyboardLabelsSet();
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
-        mTestResources = getTestContext().getResources();
+        mLabelsSet.setLanguage(Locale.ENGLISH.getLanguage());
+        final String[] testResourceNames = getAllResourceIdNames(
+                com.android.inputmethod.latin.tests.R.string.class);
+        mLabelsSet.loadStringResourcesInternal(getTestContext(),
+                testResourceNames,
+                com.android.inputmethod.latin.tests.R.string.empty_string);
+    }
+
+    private static String[] getAllResourceIdNames(final Class<?> resourceIdClass) {
+        final ArrayList<String> names = new ArrayList<String>();
+        for (final Field field : resourceIdClass.getFields()) {
+            if (field.getType() == Integer.TYPE) {
+                names.add(field.getName());
+            }
+        }
+        return names.toArray(new String[names.size()]);
     }
 
     private static String format(String message, Object expected, Object actual) {
@@ -39,8 +54,7 @@
     }
 
     private void assertTextArray(String message, String value, String ... expected) {
-        final String actual[] = KeySpecParser.parseCsvString(value, mTestResources,
-                R.string.empty_string);
+        final String actual[] = KeySpecParser.parseCsvString(value, mLabelsSet);
         if (expected.length == 0) {
             assertNull(message + ": expected=null actual=" + Arrays.toString(actual),
                     actual);
@@ -104,10 +118,10 @@
                 "ab" + SURROGATE1 + "cd",
                 "ab" + SURROGATE1 + "cd");
 
-        assertTextArray("Incomplete resource reference 1", "string", "string");
-        assertTextArray("Incomplete resource reference 2", "@string", "@string");
-        assertTextArray("Incomplete resource reference 3", "string/", "string/");
-        assertTextArray("Incomplete resource reference 4", "@" + SURROGATE2, "@" + SURROGATE2);
+        assertTextArray("Incomplete resource reference 1", "label", "label");
+        assertTextArray("Incomplete resource reference 2", "!label", "!label");
+        assertTextArray("Incomplete resource reference 3", "label/", "label/");
+        assertTextArray("Incomplete resource reference 4", "!" + SURROGATE2, "!" + SURROGATE2);
     }
 
     public void testParseCsvTextSingleEscaped() {
@@ -138,9 +152,9 @@
         assertTextArray("Escaped surrogate with escape",
                 PAIR1 + "\\\\" + PAIR2, PAIR1 + "\\\\" + PAIR2);
 
-        assertTextArray("Escaped @string", "\\@string", "\\@string");
-        assertTextArray("Escaped @string/", "\\@string/", "\\@string/");
-        assertTextArray("Escaped @string/", "\\@string/empty_string", "\\@string/empty_string");
+        assertTextArray("Escaped !label", "\\!label", "\\!label");
+        assertTextArray("Escaped !label/", "\\!label/", "\\!label/");
+        assertTextArray("Escaped !label/", "\\!label/empty_string", "\\!label/empty_string");
     }
 
     public void testParseCsvTextMulti() {
@@ -171,133 +185,133 @@
         assertTextArray("Multiple labels with comma and escape surrounded by spaces",
                 " ab\\\\ , d\\\\\\, , g\\,i ", " ab\\\\ ", " d\\\\\\, ", " g\\,i ");
 
-        assertTextArray("Multiple escaped @string", "\\@,\\@string/empty_string",
-                "\\@", "\\@string/empty_string");
+        assertTextArray("Multiple escaped !label", "\\!,\\!label/empty_string",
+                "\\!", "\\!label/empty_string");
     }
 
     public void testParseCsvResourceError() {
-        assertError("Incomplete resource name", "@string/", "@string/");
-        assertError("Non existing resource", "@string/non_existing");
+        assertError("Incomplete resource name", "!label/", "!label/");
+        assertError("Non existing resource", "!label/non_existing");
     }
 
     public void testParseCsvResourceZero() {
         assertTextArray("Empty string",
-                "@string/empty_string");
+                "!label/empty_string");
     }
 
     public void testParseCsvResourceSingle() {
         assertTextArray("Single char",
-                "@string/single_char", "a");
+                "!label/single_char", "a");
         assertTextArray("Space",
-                "@string/space", " ");
+                "!label/space", " ");
         assertTextArray("Single label",
-                "@string/single_label", "abc");
+                "!label/single_label", "abc");
         assertTextArray("Spaces",
-                "@string/spaces", "   ");
+                "!label/spaces", "   ");
         assertTextArray("Spaces in label",
-                "@string/spaces_in_label", "a b c");
+                "!label/spaces_in_label", "a b c");
         assertTextArray("Spaces at beginning of label",
-                "@string/spaces_at_beginning_of_label", " abc");
+                "!label/spaces_at_beginning_of_label", " abc");
         assertTextArray("Spaces at end of label",
-                "@string/spaces_at_end_of_label", "abc ");
+                "!label/spaces_at_end_of_label", "abc ");
         assertTextArray("label surrounded by spaces",
-                "@string/label_surrounded_by_spaces", " abc ");
+                "!label/label_surrounded_by_spaces", " abc ");
 
         assertTextArray("Escape and single char",
-                "\\\\@string/single_char", "\\\\a");
+                "\\\\!label/single_char", "\\\\a");
     }
 
     public void testParseCsvResourceSingleEscaped() {
         assertTextArray("Escaped char",
-                "@string/escaped_char", "\\a");
+                "!label/escaped_char", "\\a");
         assertTextArray("Escaped comma",
-                "@string/escaped_comma", "\\,");
+                "!label/escaped_comma", "\\,");
         assertTextArray("Escaped comma escape",
-                "@string/escaped_comma_escape", "a\\,\\");
+                "!label/escaped_comma_escape", "a\\,\\");
         assertTextArray("Escaped escape",
-                "@string/escaped_escape", "\\\\");
+                "!label/escaped_escape", "\\\\");
         assertTextArray("Escaped label",
-                "@string/escaped_label", "a\\bc");
+                "!label/escaped_label", "a\\bc");
         assertTextArray("Escaped label at beginning",
-                "@string/escaped_label_at_beginning", "\\abc");
+                "!label/escaped_label_at_beginning", "\\abc");
         assertTextArray("Escaped label at end",
-                "@string/escaped_label_at_end", "abc\\");
+                "!label/escaped_label_at_end", "abc\\");
         assertTextArray("Escaped label with comma",
-                "@string/escaped_label_with_comma", "a\\,c");
+                "!label/escaped_label_with_comma", "a\\,c");
         assertTextArray("Escaped label with comma at beginning",
-                "@string/escaped_label_with_comma_at_beginning", "\\,bc");
+                "!label/escaped_label_with_comma_at_beginning", "\\,bc");
         assertTextArray("Escaped label with comma at end",
-                "@string/escaped_label_with_comma_at_end", "ab\\,");
+                "!label/escaped_label_with_comma_at_end", "ab\\,");
         assertTextArray("Escaped label with successive",
-                "@string/escaped_label_with_successive", "\\,\\\\bc");
+                "!label/escaped_label_with_successive", "\\,\\\\bc");
         assertTextArray("Escaped label with escape",
-                "@string/escaped_label_with_escape", "a\\\\c");
+                "!label/escaped_label_with_escape", "a\\\\c");
     }
 
     public void testParseCsvResourceMulti() {
         assertTextArray("Multiple chars",
-                "@string/multiple_chars", "a", "b", "c");
+                "!label/multiple_chars", "a", "b", "c");
         assertTextArray("Multiple chars surrounded by spaces",
-                "@string/multiple_chars_surrounded_by_spaces",
+                "!label/multiple_chars_surrounded_by_spaces",
                 " a ", " b ", " c ");
         assertTextArray("Multiple labels",
-                "@string/multiple_labels", "abc", "def", "ghi");
+                "!label/multiple_labels", "abc", "def", "ghi");
         assertTextArray("Multiple labels surrounded by spaces",
-                "@string/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi ");
+                "!label/multiple_labels_surrounded_by_spaces", " abc ", " def ", " ghi ");
     }
 
     public void testParseCsvResourcetMultiEscaped() {
         assertTextArray("Multiple chars with comma",
-                "@string/multiple_chars_with_comma",
+                "!label/multiple_chars_with_comma",
                 "a", "\\,", "c");
         assertTextArray("Multiple chars with comma surrounded by spaces",
-                "@string/multiple_chars_with_comma_surrounded_by_spaces",
+                "!label/multiple_chars_with_comma_surrounded_by_spaces",
                 " a ", " \\, ", " c ");
         assertTextArray("Multiple labels with escape",
-                "@string/multiple_labels_with_escape",
+                "!label/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",
+                "!label/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",
+                "!label/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",
+                "!label/multiple_labels_with_comma_and_escape_surrounded_by_spaces",
                 " ab\\\\ ", " d\\\\\\, ", " g\\,i ");
     }
 
     public void testParseMultipleResources() {
         assertTextArray("Literals and resources",
-                "1,@string/multiple_chars,z", "1", "a", "b", "c", "z");
+                "1,!label/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\\");
+                "\\1,!label/multiple_chars,z\\", "\\1", "a", "b", "c", "z\\");
         assertTextArray("Multiple single resource chars and labels",
-                "@string/single_char,@string/single_label,@string/escaped_comma",
+                "!label/single_char,!label/single_label,!label/escaped_comma",
                 "a", "abc", "\\,");
         assertTextArray("Multiple single resource chars and labels 2",
-                "@string/single_char,@string/single_label,@string/escaped_comma_escape",
+                "!label/single_char,!label/single_label,!label/escaped_comma_escape",
                 "a", "abc", "a\\,\\");
         assertTextArray("Multiple multiple resource chars and labels",
-                "@string/multiple_chars,@string/multiple_labels,@string/multiple_chars_with_comma",
+                "!label/multiple_chars,!label/multiple_labels,!label/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",
+                "!label/multiple_chars!label/multiple_labels!label/multiple_chars_with_comma",
                 "a", "b", "cabc", "def", "ghia", "\\,", "c");
         assertTextArray("Concatenated resource and literal",
-                "abc@string/multiple_labels",
+                "abc!label/multiple_labels",
                 "abcabc", "def", "ghi");
     }
 
     public void testParseIndirectReference() {
         assertTextArray("Indirect",
-                "@string/indirect_string", "a", "b", "c");
+                "!label/indirect_string", "a", "b", "c");
         assertTextArray("Indirect with literal",
-                "1,@string/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2");
+                "1,!label/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2");
     }
 
     public void testParseInfiniteIndirectReference() {
         assertError("Infinite indirection",
-                "1,@string/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2");
+                "1,!label/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2");
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
index 3fc2b02..e4879ad 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
@@ -16,54 +16,46 @@
 
 package com.android.inputmethod.keyboard.internal;
 
-import android.content.res.Resources;
 import android.test.AndroidTestCase;
 
 import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.latin.R;
+import com.android.inputmethod.keyboard.internal.KeySpecParser.MoreKeySpec;
 
 import java.util.Arrays;
+import java.util.Locale;
 
 public class KeySpecParserTests extends AndroidTestCase {
-    private Resources mRes;
+    private final KeyboardCodesSet mCodesSet = new KeyboardCodesSet();
 
     private static final int ICON_UNDEFINED = KeyboardIconsSet.ICON_UNDEFINED;
 
-    private static final String CODE_SETTINGS_RES = "integer/key_settings";
+    private static final String CODE_SETTINGS_NAME = "key_settings";
     private static final String ICON_SETTINGS_NAME = "settingsKey";
 
-    private static final String CODE_SETTINGS = "@" + CODE_SETTINGS_RES;
-    private static final String ICON_SETTINGS = "@icon/" + ICON_SETTINGS_NAME;
-    private static final String CODE_NON_EXISTING = "@integer/non_existing";
-    private static final String ICON_NON_EXISTING = "@icon/non_existing";
+    private static final String CODE_SETTINGS = "!code/" + CODE_SETTINGS_NAME;
+    private static final String ICON_SETTINGS = "!icon/" + ICON_SETTINGS_NAME;
+    private static final String CODE_NON_EXISTING = "!code/non_existing";
+    private static final String ICON_NON_EXISTING = "!icon/non_existing";
 
     private int mCodeSettings;
     private int mSettingsIconId;
 
     @Override
-    protected void setUp() {
-        Resources res = getContext().getResources();
-        mRes = res;
+    protected void setUp() throws Exception {
+        super.setUp();
 
-        final String packageName = res.getResourcePackageName(R.string.english_ime_name);
-        final int codeId = res.getIdentifier(CODE_SETTINGS_RES, null, packageName);
-        mCodeSettings = res.getInteger(codeId);
+        mCodesSet.setLanguage(Locale.ENGLISH.getLanguage());
+        mCodeSettings = mCodesSet.getCode(CODE_SETTINGS_NAME);
         mSettingsIconId = KeyboardIconsSet.getIconId(ICON_SETTINGS_NAME);
     }
 
     private void assertParser(String message, String moreKeySpec, String expectedLabel,
             String expectedOutputText, int expectedIcon, int expectedCode) {
-        String actualLabel = KeySpecParser.getLabel(moreKeySpec);
-        assertEquals(message + ": label:", expectedLabel, actualLabel);
-
-        String actualOutputText = KeySpecParser.getOutputText(moreKeySpec);
-        assertEquals(message + ": ouptputText:", expectedOutputText, actualOutputText);
-
-        int actualIcon = KeySpecParser.getIconId(moreKeySpec);
-        assertEquals(message + ": icon:", expectedIcon, actualIcon);
-
-        int actualCode = KeySpecParser.getCode(mRes, moreKeySpec);
-        assertEquals(message + ": codes value:", expectedCode, actualCode);
+        final MoreKeySpec spec = new MoreKeySpec(moreKeySpec, mCodesSet);
+        assertEquals(message + ": label:", expectedLabel, spec.mLabel);
+        assertEquals(message + ": ouptputText:", expectedOutputText, spec.mOutputText);
+        assertEquals(message + ": icon:", expectedIcon, spec.mIconId);
+        assertEquals(message + ": codes value:", expectedCode, spec.mCode);
     }
 
     private void assertParserError(String message, String moreKeySpec, String expectedLabel,
@@ -105,10 +97,10 @@
                 "a", null, ICON_UNDEFINED, 'a');
         assertParser("Single escaped surrogate", "\\" + PAIR2,
                 PAIR2, null, ICON_UNDEFINED, CODE2);
-        assertParser("Single at", "@",
-                "@", null, ICON_UNDEFINED, '@');
-        assertParser("Single escaped at", "\\@",
-                "@", null, ICON_UNDEFINED, '@');
+        assertParser("Single bang", "!",
+                "!", null, ICON_UNDEFINED, '!');
+        assertParser("Single escaped bang", "\\!",
+                "!", null, ICON_UNDEFINED, '!');
         assertParser("Single output text letter", "a|a",
                 "a", null, ICON_UNDEFINED, 'a');
         assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1,
@@ -128,14 +120,14 @@
                 "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Single letter with escaped comma outputText", "a|a\\,b",
                 "a", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single letter with outputText starts with at", "a|@bc",
-                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single letter with surrogate outputText starts with at", "a|@" + SURROGATE2,
-                "a", "@" + SURROGATE2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single letter with outputText contains at", "a|a@c",
-                "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single letter with escaped at outputText", "a|\\@bc",
-                "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Single letter with outputText starts with bang", "a|!bc",
+                "a", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Single letter with surrogate outputText starts with bang", "a|!" + SURROGATE2,
+                "a", "!" + SURROGATE2, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Single letter with outputText contains bang", "a|a!c",
+                "a", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Single letter with escaped bang outputText", "a|\\!bc",
+                "a", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Single escaped escape with single outputText", "\\\\|\\\\",
                 "\\", null, ICON_UNDEFINED, '\\');
         assertParser("Single escaped bar with single outputText", "\\||\\|",
@@ -160,14 +152,14 @@
                 "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with escaped comma", "a\\,c",
                 "a,c", "a,c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label starts with at", "@bc",
-                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Surrogate label starts with at", "@" + SURROGATE1,
-                "@" + SURROGATE1, "@" + SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label contains at", "a@c",
-                "a@c", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label with escaped at", "\\@bc",
-                "@bc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label starts with bang", "!bc",
+                "!bc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Surrogate label starts with bang", "!" + SURROGATE1,
+                "!" + SURROGATE1, "!" + SURROGATE1, ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label contains bang", "a!c",
+                "a!c", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label with escaped bang", "\\!bc",
+                "!bc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with escaped letter", "\\abc",
                 "abc", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with outputText", "abc|def",
@@ -182,22 +174,22 @@
                 "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Escaped escape label with outputText", "a\\\\|def",
                 "a\\", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label starts with at and outputText", "@bc|def",
-                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label contains at label and outputText", "a@c|def",
-                "a@c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Escaped at label with outputText", "\\@bc|def",
-                "@bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label starts with bang and outputText", "!bc|def",
+                "!bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label contains bang label and outputText", "a!c|def",
+                "a!c", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Escaped bang label with outputText", "\\!bc|def",
+                "!bc", "def", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with comma outputText", "abc|a,b",
                 "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with escaped comma outputText", "abc|a\\,b",
                 "abc", "a,b", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label with outputText starts with at", "abc|@bc",
-                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label with outputText contains at", "abc|a@c",
-                "abc", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label with escaped at outputText", "abc|\\@bc",
-                "abc", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label with outputText starts with bang", "abc|!bc",
+                "abc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label with outputText contains bang", "abc|a!c",
+                "abc", "a!c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label with escaped bang outputText", "abc|\\!bc",
+                "abc", "!bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Label with escaped bar outputText", "abc|d\\|f",
                 "abc", "d|f", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Escaped bar label with escaped bar outputText", "a\\|c|d\\|f",
@@ -211,18 +203,18 @@
     public void testIconAndCode() {
         assertParser("Icon with outputText", ICON_SETTINGS + "|abc",
                 null, "abc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Icon with outputText starts with at", ICON_SETTINGS + "|@bc",
-                null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Icon with outputText contains at", ICON_SETTINGS + "|a@c",
-                null, "a@c", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Icon with escaped at outputText", ICON_SETTINGS + "|\\@bc",
-                null, "@bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Label starts with at and code", "@bc|" + CODE_SETTINGS,
-                "@bc", null, ICON_UNDEFINED, mCodeSettings);
-        assertParser("Label contains at and code", "a@c|" + CODE_SETTINGS,
-                "a@c", null, ICON_UNDEFINED, mCodeSettings);
-        assertParser("Escaped at label with code", "\\@bc|" + CODE_SETTINGS,
-                "@bc", null, ICON_UNDEFINED, mCodeSettings);
+        assertParser("Icon with outputText starts with bang", ICON_SETTINGS + "|!bc",
+                null, "!bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Icon with outputText contains bang", ICON_SETTINGS + "|a!c",
+                null, "a!c", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Icon with escaped bang outputText", ICON_SETTINGS + "|\\!bc",
+                null, "!bc", mSettingsIconId, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Label starts with bang and code", "!bc|" + CODE_SETTINGS,
+                "!bc", null, ICON_UNDEFINED, mCodeSettings);
+        assertParser("Label contains bang and code", "a!c|" + CODE_SETTINGS,
+                "a!c", null, ICON_UNDEFINED, mCodeSettings);
+        assertParser("Escaped bang label with code", "\\!bc|" + CODE_SETTINGS,
+                "!bc", null, ICON_UNDEFINED, mCodeSettings);
         assertParser("Icon with code", ICON_SETTINGS + "|" + CODE_SETTINGS,
                 null, null, mSettingsIconId, mCodeSettings);
     }
diff --git a/tools/makelabel/Android.mk b/tools/makelabel/Android.mk
new file mode 100644
index 0000000..9fa8650
--- /dev/null
+++ b/tools/makelabel/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES += $(call all-java-files-under,src)
+LOCAL_JAR_MANIFEST := etc/manifest.txt
+LOCAL_JAVA_RESOURCE_DIRS := res
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE := makelabel
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+include $(LOCAL_PATH)/etc/Android.mk
diff --git a/tools/makelabel/etc/Android.mk b/tools/makelabel/etc/Android.mk
new file mode 100644
index 0000000..2d2e9a6
--- /dev/null
+++ b/tools/makelabel/etc/Android.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_PREBUILT_EXECUTABLES := makelabel
+include $(BUILD_HOST_PREBUILT)
diff --git a/tools/makelabel/etc/makelabel b/tools/makelabel/etc/makelabel
new file mode 100755
index 0000000..44a05b6
--- /dev/null
+++ b/tools/makelabel/etc/makelabel
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Copyright 2012, 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=makelabel.jar
+frameworkdir="$progdir"
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/tools/lib
+    libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/framework
+    libdir=`dirname "$progdir"`/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    echo `basename "$prog"`": can't find $jarfile"
+    exit 1
+fi
+
+if [ "$OSTYPE" = "cygwin" ] ; then
+    jarpath=`cygpath -w  "$frameworkdir/$jarfile"`
+    progdir=`cygpath -w  "$progdir"`
+else
+    jarpath="$frameworkdir/$jarfile"
+fi
+
+# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
+# might need more memory, e.g. -Xmx128M
+exec java -ea -jar "$jarpath" "$@"
diff --git a/tools/makelabel/etc/manifest.txt b/tools/makelabel/etc/manifest.txt
new file mode 100644
index 0000000..18bf0be
--- /dev/null
+++ b/tools/makelabel/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.inputmethod.latin.makelabel.LabelMaker
diff --git a/tools/makelabel/res/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.tmpl b/tools/makelabel/res/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.tmpl
new file mode 100644
index 0000000..0e887e4
--- /dev/null
+++ b/tools/makelabel/res/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.tmpl
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 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.content.Context;
+import android.content.res.Resources;
+
+import com.android.inputmethod.latin.R;
+
+import java.util.HashMap;
+
+/**
+ * !!!!! DO NOT EDIT THIS FILE !!!!!
+ * This file is generated by tools/makelabel.
+ */
+public final class KeyboardLabelsSet {
+    // Language to labels map.
+    private static final HashMap<String, String[]> sLocaleToLabelsMap =
+            new HashMap<String, String[]>();
+    private static final HashMap<String, Integer> sNameToIdMap = new HashMap<String, Integer>();
+
+    private String[] mLabels;
+    // Resource name to label map.
+    private HashMap<String, String> mResourceNameToLabelsMap = new HashMap<String, String>();
+
+    public void setLanguage(final String language) {
+        mLabels = sLocaleToLabelsMap.get(language);
+        if (mLabels == null) {
+            mLabels = LANGUAGE_DEFAULT;
+        }
+    }
+
+    public void loadStringResources(Context context) {
+        loadStringResourcesInternal(context, RESOURCE_NAMES, R.string.english_ime_name);
+    }
+
+    /* package for test */
+    void loadStringResourcesInternal(Context context, final String[] resourceNames,
+            int referenceId) {
+        final Resources res = context.getResources();
+        final String packageName = res.getResourcePackageName(referenceId);
+        for (final String resName : resourceNames) {
+            final int resId = res.getIdentifier(resName, "string", packageName);
+            mResourceNameToLabelsMap.put(resName, res.getString(resId));
+        }
+    }
+
+    public String getLabel(final String name) {
+        if (mResourceNameToLabelsMap.containsKey(name)) {
+            return mResourceNameToLabelsMap.get(name);
+        }
+        final Integer id = sNameToIdMap.get(name);
+        if (id == null) throw new RuntimeException("Unknown label: " + name);
+        final String label = (id < mLabels.length) ? mLabels[id] : null;
+        return (label == null) ? LANGUAGE_DEFAULT[id] : label;
+    }
+
+    private static final String[] RESOURCE_NAMES = {
+        // These labels' name should be aligned with the @string/<name> in values/strings.xml.
+        // Labels for action.
+        "label_go_key",
+        // "label_search_key",
+        "label_send_key",
+        "label_next_key",
+        "label_done_key",
+        "label_previous_key",
+        // Other labels.
+        "label_to_alpha_key",
+        "label_to_symbol_key",
+        "label_to_symbol_with_microphone_key",
+        "label_pause_key",
+        "label_wait_key",
+    };
+
+    private static final String[] NAMES = {
+        /* @NAMES@ */
+    };
+
+    private static final String EMPTY = "";
+
+    /* Default labels */
+    private static final String[] LANGUAGE_DEFAULT = {
+        /* @DEFAULT_LABELS@ */
+    };
+
+    /* @LABELS@ */
+    private static final Object[] LANGUAGES_AND_LABELS = {
+        /* @LANGUAGES_AND_LABELS@ */
+    };
+
+    static {
+        int id = 0;
+        for (final String name : NAMES) {
+            sNameToIdMap.put(name, id++);
+        }
+
+        for (int i = 0; i < LANGUAGES_AND_LABELS.length; i += 2) {
+            final String language = (String)LANGUAGES_AND_LABELS[i];
+            final String[] labels = (String[])LANGUAGES_AND_LABELS[i + 1];
+            sLocaleToLabelsMap.put(language, labels);
+        }
+    }
+}
diff --git a/java/res/values-ar/donottranslate-more-keys.xml b/tools/makelabel/res/values-ar/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-ar/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-ar/donottranslate-more-keys.xml
diff --git a/java/res/values-be/donottranslate-more-keys.xml b/tools/makelabel/res/values-be/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-be/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-be/donottranslate-more-keys.xml
diff --git a/java/res/values-ca/donottranslate-more-keys.xml b/tools/makelabel/res/values-ca/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-ca/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-ca/donottranslate-more-keys.xml
diff --git a/java/res/values-cs/donottranslate-more-keys.xml b/tools/makelabel/res/values-cs/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-cs/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-cs/donottranslate-more-keys.xml
diff --git a/java/res/values-da/donottranslate-more-keys.xml b/tools/makelabel/res/values-da/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-da/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-da/donottranslate-more-keys.xml
diff --git a/java/res/values-de/donottranslate-more-keys.xml b/tools/makelabel/res/values-de/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-de/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-de/donottranslate-more-keys.xml
diff --git a/java/res/values-en/donottranslate-more-keys.xml b/tools/makelabel/res/values-en/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-en/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-en/donottranslate-more-keys.xml
diff --git a/java/res/values-es/donottranslate-more-keys.xml b/tools/makelabel/res/values-es/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-es/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-es/donottranslate-more-keys.xml
diff --git a/java/res/values-et/donottranslate-more-keys.xml b/tools/makelabel/res/values-et/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-et/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-et/donottranslate-more-keys.xml
diff --git a/java/res/values-fa/donottranslate-more-keys.xml b/tools/makelabel/res/values-fa/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-fa/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-fa/donottranslate-more-keys.xml
diff --git a/java/res/values-fi/donottranslate-more-keys.xml b/tools/makelabel/res/values-fi/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-fi/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-fi/donottranslate-more-keys.xml
diff --git a/java/res/values-fr/donottranslate-more-keys.xml b/tools/makelabel/res/values-fr/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-fr/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-fr/donottranslate-more-keys.xml
diff --git a/java/res/values-hi/donottranslate-more-keys.xml b/tools/makelabel/res/values-hi/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-hi/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-hi/donottranslate-more-keys.xml
diff --git a/java/res/values-hr/donottranslate-more-keys.xml b/tools/makelabel/res/values-hr/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-hr/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-hr/donottranslate-more-keys.xml
diff --git a/java/res/values-hu/donottranslate-more-keys.xml b/tools/makelabel/res/values-hu/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-hu/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-hu/donottranslate-more-keys.xml
diff --git a/java/res/values-is/donottranslate-more-keys.xml b/tools/makelabel/res/values-is/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-is/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-is/donottranslate-more-keys.xml
diff --git a/java/res/values-it/donottranslate-more-keys.xml b/tools/makelabel/res/values-it/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-it/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-it/donottranslate-more-keys.xml
diff --git a/java/res/values-iw/donottranslate-more-keys.xml b/tools/makelabel/res/values-iw/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-iw/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-iw/donottranslate-more-keys.xml
diff --git a/java/res/values-ky/donottranslate-more-keys.xml b/tools/makelabel/res/values-ky/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-ky/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-ky/donottranslate-more-keys.xml
diff --git a/java/res/values-lt/donottranslate-more-keys.xml b/tools/makelabel/res/values-lt/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-lt/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-lt/donottranslate-more-keys.xml
diff --git a/java/res/values-lv/donottranslate-more-keys.xml b/tools/makelabel/res/values-lv/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-lv/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-lv/donottranslate-more-keys.xml
diff --git a/java/res/values-mk/donottranslate-more-keys.xml b/tools/makelabel/res/values-mk/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-mk/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-mk/donottranslate-more-keys.xml
diff --git a/java/res/values-nb/donottranslate-more-keys.xml b/tools/makelabel/res/values-nb/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-nb/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-nb/donottranslate-more-keys.xml
diff --git a/java/res/values-nl/donottranslate-more-keys.xml b/tools/makelabel/res/values-nl/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-nl/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-nl/donottranslate-more-keys.xml
diff --git a/java/res/values-pl/donottranslate-more-keys.xml b/tools/makelabel/res/values-pl/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-pl/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-pl/donottranslate-more-keys.xml
diff --git a/java/res/values-pt/donottranslate-more-keys.xml b/tools/makelabel/res/values-pt/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-pt/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-pt/donottranslate-more-keys.xml
diff --git a/java/res/values-rm/donottranslate-more-keys.xml b/tools/makelabel/res/values-rm/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-rm/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-rm/donottranslate-more-keys.xml
diff --git a/java/res/values-ro/donottranslate-more-keys.xml b/tools/makelabel/res/values-ro/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-ro/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-ro/donottranslate-more-keys.xml
diff --git a/java/res/values-ru/donottranslate-more-keys.xml b/tools/makelabel/res/values-ru/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-ru/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-ru/donottranslate-more-keys.xml
diff --git a/java/res/values-sk/donottranslate-more-keys.xml b/tools/makelabel/res/values-sk/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-sk/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-sk/donottranslate-more-keys.xml
diff --git a/java/res/values-sl/donottranslate-more-keys.xml b/tools/makelabel/res/values-sl/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-sl/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-sl/donottranslate-more-keys.xml
diff --git a/java/res/values-sr/donottranslate-more-keys.xml b/tools/makelabel/res/values-sr/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-sr/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-sr/donottranslate-more-keys.xml
diff --git a/java/res/values-sv/donottranslate-more-keys.xml b/tools/makelabel/res/values-sv/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-sv/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-sv/donottranslate-more-keys.xml
diff --git a/java/res/values-tr/donottranslate-more-keys.xml b/tools/makelabel/res/values-tr/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-tr/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-tr/donottranslate-more-keys.xml
diff --git a/java/res/values-uk/donottranslate-more-keys.xml b/tools/makelabel/res/values-uk/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-uk/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-uk/donottranslate-more-keys.xml
diff --git a/java/res/values-vi/donottranslate-more-keys.xml b/tools/makelabel/res/values-vi/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-vi/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-vi/donottranslate-more-keys.xml
diff --git a/java/res/values-zz/donottranslate-more-keys.xml b/tools/makelabel/res/values-zz/donottranslate-more-keys.xml
similarity index 100%
rename from java/res/values-zz/donottranslate-more-keys.xml
rename to tools/makelabel/res/values-zz/donottranslate-more-keys.xml
diff --git a/java/res/values/donottranslate-more-keys.xml b/tools/makelabel/res/values/donottranslate-more-keys.xml
similarity index 89%
rename from java/res/values/donottranslate-more-keys.xml
rename to tools/makelabel/res/values/donottranslate-more-keys.xml
index f50dd4f..7878757 100644
--- a/java/res/values/donottranslate-more-keys.xml
+++ b/tools/makelabel/res/values/donottranslate-more-keys.xml
@@ -59,6 +59,13 @@
     <string name="keylabel_for_south_slavic_row3_8"></string>
     <string name="more_keys_for_cyrillic_ie"></string>
     <string name="more_keys_for_cyrillic_i"></string>
+    <string name="more_keys_for_single_quote">!fixedColumnOrder!4,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
+    <!-- <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;</string> -->
+    <string name="more_keys_for_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;</string>
+    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
+    <!-- <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string> -->
+    <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
     <!-- U+00A2: "¢" CENT SIGN
          U+00A3: "£" POUND SIGN
          U+20AC: "€" EURO SIGN
@@ -120,11 +127,11 @@
          U+2205: "∅" EMPTY SET -->
     <string name="more_keys_for_symbols_0">&#x207F;,&#x2205;</string>
     <string name="more_keys_for_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string>
-    <string name="settings_as_more_key">\@icon/settingsKey|\@integer/key_settings</string>
+    <string name="settings_as_more_key">!icon/settingsKey|!code/key_settings</string>
     <string name="keylabel_for_comma">,</string>
     <string name="more_keys_for_comma"></string>
-    <string name="action_next_as_more_key">!hasLabels!,\@string/label_next_key|\@integer/key_action_next</string>
-    <string name="action_previous_as_more_key">!hasLabels!,\@string/label_previous_key|\@integer/key_action_previous</string>
+    <string name="action_next_as_more_key">!hasLabels!,\@string/label_next_key|!code/key_action_next</string>
+    <string name="action_previous_as_more_key">!hasLabels!,\@string/label_previous_key|!code/key_action_previous</string>
     <string name="keylabel_for_symbols_question">\?</string>
     <string name="keylabel_for_symbols_semicolon">;</string>
     <string name="keylabel_for_symbols_percent">%</string>
@@ -177,11 +184,20 @@
          U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <string name="more_keys_for_less_than">!fixedColumnOrder!3,&#x2039;,&#x2264;,&#x00AB;</string>
     <string name="more_keys_for_greater_than">!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;</string>
-    <string name="more_keys_for_single_quote">!fixedColumnOrder!4,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
-    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
-    <!-- <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;</string> -->
-    <string name="more_keys_for_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;</string>
-    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
-    <!-- <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string> -->
-    <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+    <!-- Label for "switch to more symbol" modifier key.  Must be short to fit on key! -->
+    <string name="label_to_more_symbol_key">= \\ &lt;</string>
+    <!-- Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key! -->
+    <string name="label_to_more_symbol_for_tablet_key">~ \\ {</string>
+    <!-- Label for "Tab" key.  Must be short to fit on key! -->
+    <string name="label_tab_key">Tab</string>
+    <!-- Label for "switch to phone numeric" key.  Must be short to fit on key! -->
+    <string name="label_to_phone_numeric_key">123</string>
+    <!-- Label for "switch to phone symbols" key.  Must be short to fit on key! -->
+    <!-- U+FF0A: "*" FULLWIDTH ASTERISK
+         U+FF03: "#" FULLWIDTH NUMBER SIGN -->
+    <string name="label_to_phone_symbols_key">&#xFF0A;&#xFF03;</string>
+    <!-- Key label for "ante meridiem" -->
+    <string name="label_time_am">"AM"</string>
+    <!-- Key label for "post meridiem" -->
+    <string name="label_time_pm">"PM"</string>
 </resources>
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/ArrayInitializerFormatter.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/ArrayInitializerFormatter.java
new file mode 100644
index 0000000..0cf2991
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/ArrayInitializerFormatter.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+import java.io.PrintStream;
+
+public class ArrayInitializerFormatter {
+    private final PrintStream mOut;
+    private final int mMaxWidth;
+    private final String mIndent;
+
+    private int mCurrentIndex = 0;
+    private String mFixedElement;
+    private final StringBuilder mBuffer = new StringBuilder();
+    private int mBufferedLen;
+    private int mBufferedIndex = Integer.MIN_VALUE;
+
+    public ArrayInitializerFormatter(PrintStream out, int width, String indent) {
+        mOut = out;
+        mMaxWidth = width - indent.length();
+        mIndent = indent;
+    }
+
+    public void flush() {
+        if (mBuffer.length() == 0) {
+            return;
+        }
+        final int lastIndex = mCurrentIndex - 1;
+        if (mBufferedIndex == lastIndex) {
+            mOut.format("%s/* %d */ %s\n", mIndent, mBufferedIndex, mBuffer);
+        } else if (mBufferedIndex == lastIndex - 1) {
+            final String[] elements = mBuffer.toString().split(" ");
+            mOut.format("%s/* %d */ %s\n"
+                    + "%s/* %d */ %s\n",
+                    mIndent, mBufferedIndex, elements[0],
+                    mIndent, lastIndex, elements[1]);
+        } else {
+            mOut.format("%s/* %d~ */\n"
+                    + "%s%s\n"
+                    + "%s/* ~%d */\n", mIndent, mBufferedIndex,
+                    mIndent, mBuffer,
+                    mIndent, lastIndex);
+        }
+        mBuffer.setLength(0);
+        mBufferedLen = 0;
+    }
+
+    public void outCommentLines(String lines) {
+        flush();
+        mOut.print(lines);
+        mFixedElement = null;
+    }
+
+    public void outElement(String element) {
+        if (!element.equals(mFixedElement)) {
+            flush();
+            mBufferedIndex = mCurrentIndex;
+        }
+        final int nextLen = mBufferedLen + " ".length() + element.length();
+        if (mBufferedLen != 0 && nextLen < mMaxWidth) {
+            mBuffer.append(' ');
+            mBuffer.append(element);
+            mBufferedLen = nextLen;
+        } else {
+            if (mBufferedLen != 0) {
+                mBuffer.append('\n');
+                mBuffer.append(mIndent);
+            }
+            mBuffer.append(element);
+            mBufferedLen = element.length();
+        }
+        mCurrentIndex++;
+        mFixedElement = element;
+    }
+}
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/JarUtils.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/JarUtils.java
new file mode 100644
index 0000000..b24b2ca
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/JarUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class JarUtils {
+    private static final String MANIFEST = "META-INF/MANIFEST.MF";
+
+    private JarUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static JarFile getJarFile(final ClassLoader loader) {
+        final URL resUrl = loader.getResource(MANIFEST);
+        if (!resUrl.getProtocol().equals("jar")) {
+            throw new RuntimeException("Should run as jar");
+        }
+        final String path = resUrl.getPath();
+        if (!path.startsWith("file:")) {
+            throw new RuntimeException("Unknown jar path: " + path);
+        }
+        final String jarPath = path.substring("file:".length(), path.indexOf('!'));
+        try {
+            return new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+        } catch (IOException e) {
+        }
+        return null;
+    }
+
+    public static InputStream openResource(final String name) {
+        return JarUtils.class.getResourceAsStream("/" + name);
+    }
+
+    public interface JarFilter {
+        public boolean accept(String dirName, String name);
+    }
+
+    public static ArrayList<String> getNameListing(final JarFile jar, final JarFilter filter) {
+        final ArrayList<String> result = new ArrayList<String>();
+        final Enumeration<JarEntry> entries = jar.entries();
+        while (entries.hasMoreElements()) {
+            final JarEntry entry = entries.nextElement();
+            final String path = entry.getName();
+            final int pos = path.lastIndexOf('/');
+            final String dirName = (pos >= 0) ? path.substring(0, pos) : "";
+            final String name = (pos >= 0) ? path.substring(pos + 1) : path;
+            if (filter.accept(dirName, name)) {
+                result.add(path);
+            }
+        }
+        return result;
+    }
+
+    public static ArrayList<String> getNameListing(final JarFile jar, final String filterName) {
+        return getNameListing(jar, new JarFilter() {
+            @Override
+            public boolean accept(final String dirName, final String name) {
+                return name.equals(filterName);
+            }
+        });
+    }
+}
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/LabelMaker.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/LabelMaker.java
new file mode 100644
index 0000000..e02f802
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/LabelMaker.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.jar.JarFile;
+
+public class LabelMaker {
+    static class Options {
+        private static final String OPTION_JAVA = "-java";
+
+        public final String mJava;
+
+        public static void usage(String message) {
+            if (message != null) {
+                System.err.println(message);
+            }
+            System.err.println("usage: makelabel " + OPTION_JAVA + " <java_output_dir>");
+            System.exit(1);
+        }
+
+        public Options(final String[] argsArray) {
+            final LinkedList<String> args = new LinkedList<String>(Arrays.asList(argsArray));
+            String arg = null;
+            String java = null;
+            try {
+                while (!args.isEmpty()) {
+                    arg = args.removeFirst();
+                    if (arg.equals(OPTION_JAVA)) {
+                        java = args.removeFirst();
+                    } else {
+                        usage("Unknown option: " + arg);
+                    }
+                }
+            } catch (NoSuchElementException e) {
+                usage("Option " + arg + " needs argument");
+            }
+
+            mJava = java;
+        }
+    }
+
+    public static void main(final String[] args) {
+        final Options options = new Options(args);
+        final JarFile jar = JarUtils.getJarFile(LabelMaker.class.getClassLoader());
+        final MoreKeysResources resources = new MoreKeysResources(jar);
+        resources.writeToJava(options.mJava);
+    }
+}
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/MoreKeysResources.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/MoreKeysResources.java
new file mode 100644
index 0000000..1dfb853
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/MoreKeysResources.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.jar.JarFile;
+
+public class MoreKeysResources {
+    private static final String LABEL_RESOURCE_NAME = "donottranslate-more-keys.xml";
+
+    private static final String JAVA_TEMPLATE = "KeyboardLabelsSet.tmpl";
+    private static final String MARK_NAMES = "@NAMES@";
+    private static final String MARK_DEFAULT_LABELS = "@DEFAULT_LABELS@";
+    private static final String MARK_LABELS = "@LABELS@";
+    private static final String MARK_LANGUAGES_AND_LABELS = "@LANGUAGES_AND_LABELS@";
+    private static final String DEFAUT_LANGUAGE_NAME = "DEFAULT";
+    private static final String ARRAY_NAME_FOR_LANGUAGE = "LANGUAGE_%s";
+    private static final String EMPTY_STRING_VAR = "EMPTY";
+
+    private static final String NO_LANGUAGE_CODE = "zz";
+    private static final String NO_LANGUAGE_DISPLAY_NAME = "No language";
+
+    private final JarFile mJar;
+    // Language to string resources map.
+    private final HashMap<String, StringResourceMap> mResourcesMap =
+            new HashMap<String, StringResourceMap>();
+    // Name to id map.
+    private final HashMap<String, Integer> mNameToIdMap = new HashMap<String,Integer>();
+
+    public MoreKeysResources(final JarFile jar) {
+        mJar = jar;
+        final ArrayList<String> resources = JarUtils.getNameListing(jar, LABEL_RESOURCE_NAME);
+        for (final String name : resources) {
+            final String dirName = name.substring(0, name.lastIndexOf('/'));
+            final int pos = dirName.lastIndexOf('/');
+            final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
+            final String language = getLanguageFromResDir(parentName);
+            final InputStream stream = JarUtils.openResource(name);
+            try {
+                mResourcesMap.put(language, new StringResourceMap(stream));
+            } finally {
+                close(stream);
+            }
+        }
+    }
+
+    private static String getLanguageFromResDir(final String dirName) {
+        final int languagePos = dirName.indexOf('-');
+        if (languagePos < 0) {
+            // Default resource.
+            return DEFAUT_LANGUAGE_NAME;
+        }
+        final String language = dirName.substring(languagePos + 1);
+        final int countryPos = language.indexOf("-r");
+        if (countryPos < 0) {
+            return language;
+        }
+        return language.replace("-r", "_");
+    }
+
+    public void writeToJava(final String outDir) {
+        final ArrayList<String> list = JarUtils.getNameListing(mJar, JAVA_TEMPLATE);
+        if (list.isEmpty())
+            throw new RuntimeException("Can't find java template " + JAVA_TEMPLATE);
+        if (list.size() > 1)
+            throw new RuntimeException("Found multiple java template " + JAVA_TEMPLATE);
+        final String template = list.get(0);
+        final String javaPackage = template.substring(0, template.lastIndexOf('/'));
+        PrintStream ps = null;
+        LineNumberReader lnr = null;
+        try {
+            if (outDir == null) {
+                ps = System.out;
+            } else {
+                final File outPackage = new File(outDir, javaPackage);
+                final File outputFile = new File(outPackage,
+                        JAVA_TEMPLATE.replace(".tmpl", ".java"));
+                outPackage.mkdirs();
+                ps = new PrintStream(outputFile);
+            }
+            lnr = new LineNumberReader(new InputStreamReader(JarUtils.openResource(template)));
+            inflateTemplate(lnr, ps);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            close(lnr);
+            close(ps);
+        }
+    }
+
+    private void inflateTemplate(final LineNumberReader in, final PrintStream out)
+            throws IOException {
+        String line;
+        while ((line = in.readLine()) != null) {
+            if (line.contains(MARK_NAMES)) {
+                dumpNames(out);
+            } else if (line.contains(MARK_DEFAULT_LABELS)) {
+                dumpDefaultLabels(out);
+            } else if (line.contains(MARK_LABELS)) {
+                dumpLabels(out);
+            } else if (line.contains(MARK_LANGUAGES_AND_LABELS)) {
+                dumpLanguageMap(out);
+            } else {
+                out.println(line);
+            }
+        }
+    }
+
+    private void dumpNames(final PrintStream out) {
+        final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+        int id = 0;
+        for (final StringResource res : defaultResMap.getResources()) {
+            out.format("        /* %2d */ \"%s\",\n", id, res.mName);
+            mNameToIdMap.put(res.mName, id);
+            id++;
+        }
+    }
+
+    private void dumpDefaultLabels(final PrintStream out) {
+        final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+        dumpLabelsInternal(out, defaultResMap, defaultResMap);
+    }
+
+    private void dumpLabels(final PrintStream out) {
+        final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+        final ArrayList<String> allLanguages = new ArrayList<String>();
+        allLanguages.addAll(mResourcesMap.keySet());
+        Collections.sort(allLanguages);
+        for (final String language : allLanguages) {
+            if (language.equals(DEFAUT_LANGUAGE_NAME)) {
+                continue;
+            }
+            out.format("    /* Language %s: %s */\n", language, getLanguageDisplayName(language));
+            out.format("    private static final String[] " + ARRAY_NAME_FOR_LANGUAGE + " = {\n",
+                    language);
+            final StringResourceMap resMap = mResourcesMap.get(language);
+            dumpLabelsInternal(out, resMap, defaultResMap);
+            out.format("    };\n\n");
+        }
+    }
+
+    private void dumpLanguageMap(final PrintStream out) {
+        final ArrayList<String> allLanguages = new ArrayList<String>();
+        allLanguages.addAll(mResourcesMap.keySet());
+        Collections.sort(allLanguages);
+        for (final String language : allLanguages) {
+            out.format("        \"%s\", " + ARRAY_NAME_FOR_LANGUAGE + ", /* %s */\n",
+                    language, language, getLanguageDisplayName(language));
+        }
+    }
+
+    private static String getLanguageDisplayName(final String language) {
+        if (language.equals(NO_LANGUAGE_CODE)) {
+            return NO_LANGUAGE_DISPLAY_NAME;
+        } else {
+            return new Locale(language).getDisplayLanguage();
+        }
+    }
+
+    private static void dumpLabelsInternal(final PrintStream out, final StringResourceMap resMap,
+            final StringResourceMap defaultResMap) {
+        final ArrayInitializerFormatter formatter =
+                new ArrayInitializerFormatter(out, 100, "        ");
+        boolean successiveNull = false;
+        for (final StringResource defaultRes : defaultResMap.getResources()) {
+            if (resMap.contains(defaultRes.mName)) {
+                final StringResource res = resMap.get(defaultRes.mName);
+                if (res.mComment != null) {
+                    formatter.outCommentLines(addPrefix("        // ", res. mComment));
+                }
+                final String escaped = escapeNonAscii(res.mValue);
+                if (escaped.length() == 0) {
+                    formatter.outElement(EMPTY_STRING_VAR + ",");
+                } else {
+                    formatter.outElement(String.format("\"%s\",", escaped));
+                }
+                successiveNull = false;
+            } else {
+                formatter.outElement("null,");
+                successiveNull = true;
+            }
+        }
+        if (!successiveNull) {
+            formatter.flush();
+        }
+    }
+
+    private static String addPrefix(final String prefix, final String lines) {
+        final StringBuilder sb = new StringBuilder();
+        for (final String line : lines.split("\n")) {
+            sb.append(prefix + line.trim() + "\n");
+        }
+        return sb.toString();
+    }
+
+    private static String escapeNonAscii(final String text) {
+        final StringBuilder sb = new StringBuilder();
+        final int length = text.length();
+        for (int i = 0; i < length; i++) {
+            final char c = text.charAt(i);
+            if (c >= ' ' && c < 0x7f) {
+                sb.append(c);
+            } else {
+                sb.append(String.format("\\u%04X", (int)c));
+            }
+        }
+        return replaceIncompatibleEscape(sb.toString());
+    }
+
+    private static String replaceIncompatibleEscape(final String text) {
+        String t = text;
+        t = replaceAll(t, "\\?", "?");
+        t = replaceAll(t, "\\@", "@");
+        t = replaceAll(t, "@string/", "!label/");
+        return t;
+    }
+
+    private static String replaceAll(final String text, final String target, final String replace) {
+        String t = text;
+        while (t.indexOf(target) >= 0) {
+            t = t.replace(target, replace);
+        }
+        return t;
+    }
+
+    private static void close(Closeable stream) {
+        try {
+            if (stream != null) {
+                stream.close();
+            }
+        } catch (IOException e) {
+        }
+    }
+}
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResource.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResource.java
new file mode 100644
index 0000000..793483c
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResource.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+public class StringResource {
+    public final String mName;
+    public final String mValue;
+    public final String mComment;
+
+    public StringResource(final String name, final String value, final String comment) {
+        mName = name;
+        mValue = value;
+        mComment = comment;
+    }
+}
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java
new file mode 100644
index 0000000..afb1aa7
--- /dev/null
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2012 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.latin.makelabel;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.DefaultHandler2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+public class StringResourceMap {
+    // String resource list.
+    private final List<StringResource> mResources;
+    // Name to string resource map.
+    private final Map<String, StringResource> mResourcesMap;
+
+    public StringResourceMap(final InputStream is) {
+        final StringResourceHandler handler = new StringResourceHandler();
+        final SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+        try {
+            final SAXParser parser = factory.newSAXParser();
+            // In order to get comment tag.
+            parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+            parser.parse(is, handler);
+        } catch (ParserConfigurationException e) {
+        } catch (SAXException e) {
+            throw new RuntimeException(e.getMessage());
+        } catch (IOException e) {
+        }
+
+        mResources = Collections.unmodifiableList(handler.mResources);
+        final HashMap<String,StringResource> map = new HashMap<String,StringResource>();
+        for (final StringResource res : mResources) {
+            map.put(res.mName, res);
+        }
+        mResourcesMap = map;
+    }
+
+    public List<StringResource> getResources() {
+        return mResources;
+    }
+
+    public boolean contains(final String name) {
+        return mResourcesMap.containsKey(name);
+    }
+
+    public StringResource get(final String name) {
+        return mResourcesMap.get(name);
+    }
+
+    static class StringResourceHandler extends DefaultHandler2 {
+        private static final String TAG_RESOURCES = "resources";
+        private static final String TAG_STRING = "string";
+        private static final String ATTR_NAME = "name";
+
+        final ArrayList<StringResource> mResources = new ArrayList<StringResource>();
+
+        private String mName;
+        private final StringBuilder mValue = new StringBuilder();
+        private final StringBuilder mComment = new StringBuilder();
+
+        private void init() {
+            mName = null;
+            mComment.setLength(0);
+        }
+
+        @Override
+        public void comment(char[] ch, int start, int length) {
+            mComment.append(ch, start, length);
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attr) {
+            if (TAG_RESOURCES.equals(localName)) {
+                init();
+            } else if (TAG_STRING.equals(localName)) {
+                mName = attr.getValue(ATTR_NAME);
+                mValue.setLength(0);
+            }
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) {
+            mValue.append(ch, start, length);
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            if (TAG_STRING.equals(localName)) {
+                if (mName == null)
+                    throw new SAXException(TAG_STRING + " doesn't have name");
+                final String comment = mComment.length() > 0 ? mComment.toString() : null;
+                String value = mValue.toString();
+                if (value.startsWith("\"") && value.endsWith("\"")) {
+                    // Trim surroundings double quote.
+                    value = value.substring(1, value.length() - 1);
+                }
+                mResources.add(new StringResource(mName, value, comment));
+                init();
+            }
+        }
+    }
+}