Merge "Change binary dictionary output buffer size to match dictionary size."
diff --git a/java/res/layout/additional_subtype_dialog.xml b/java/res/layout/additional_subtype_dialog.xml
new file mode 100644
index 0000000..f97c006
--- /dev/null
+++ b/java/res/layout/additional_subtype_dialog.xml
@@ -0,0 +1,56 @@
+<?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.
+*/
+-->
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:columnCount="2"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginLeft="8dip"
+    android:layout_marginRight="8dip"
+    android:padding="8dip">
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="left|center_vertical"
+        style="?android:attr/textAppearanceSmall"
+        android:text="@string/subtype_locale" />
+    <Spinner
+        android:id="@+id/subtype_locale_spinner"
+        android:layout_width="wrap_content"
+        android:layout_marginLeft="8dip"
+        android:layout_marginBottom="8dip"
+        android:layout_marginTop="8dip"
+        android:layout_gravity="fill_horizontal|center_vertical"
+        android:prompt="@string/subtype_locale" />
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="left|center_vertical"
+        style="?android:attr/textAppearanceSmall"
+        android:text="@string/keyboard_layout_set" />
+    <Spinner
+        android:id="@+id/keyboard_layout_set_spinner"
+        android:layout_width="wrap_content"
+        android:layout_marginLeft="8dip"
+        android:layout_marginBottom="8dip"
+        android:layout_marginTop="8dip"
+        android:layout_gravity="fill_horizontal|center_vertical"
+        android:prompt="@string/keyboard_layout_set" />
+</GridLayout>
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index a0bef12..dfb08af 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -61,9 +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>
-    <string name="bigram_suggestion" msgid="8169311444438922902">"Volgende woordvoorstelle"</string>
+    <string name="bigram_suggestion" msgid="8169311444438922902">"Volgendewoordvoorstelle"</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" msgid="3216364899483135294">"Volgendewoordvoorspelling"</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>
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Geen taal (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 2d898aa..06e55eb 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -118,8 +118,24 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"ቋንቋ አልባ (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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>
+    <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"ቁልፍ ተጫን የድምጽ መጠን ቅንብሮች"</string>
 </resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 5e76d01..ced4ea2 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"بدون لغة (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 7a2ce94..c218eda 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Мова не выбрана (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-bg/strings.xml b/java/res/values-bg/strings.xml
index 9783a8c..e2ea926 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Без език („QWERTY“)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-ca/strings.xml b/java/res/values-ca/strings.xml
index 68715fc..91f715b 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema del teclat"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Anglès (Regne Unit)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Anglès (EUA)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Cap idioma (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mode d\'estudi d\'usabilitat"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Configuració de la durada de les vibracions per pulsació de tecla"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Configuració del volum de so de pulsació de tecla"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 17073d2..ab00c4e 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Žádný jazyk (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 cd52660..953ce55 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ingen sprog (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-de/strings.xml b/java/res/values-de/strings.xml
index 399069e..522af6e 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturdesign"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Englisch (Großbritannien)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Englisch (USA)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Keine Sprache (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus der Studie zur Benutzerfreundlichkeit"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Einstellungen für Vibrationsdauer bei Tastendruck"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Einstellungen für Tonlautstärke bei Tastendruck"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 7552a28..1197600 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Καμία γλώσσα (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index ef86365..b27089e 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"No language (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 75b1fb4..e5d2430 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -62,7 +62,7 @@
     <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"Muy agresivo"</string>
     <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_suggestion_summary" msgid="6635527607242625713">"Usar 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>
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ningún idioma (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 222cd53..ce6807f 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ningún idioma (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 cb21b4c..449e76c 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Keel puudub (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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/strings.xml b/java/res/values-fa/strings.xml
index 5a6302f..554e1bf 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -63,7 +63,7 @@
     <string name="auto_correction_threshold_mode_very_aggeressive" msgid="3386782235540547678">"بسیار پرخاشگرانه"</string>
     <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" 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>
@@ -122,7 +122,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"هیچ کدام از زبانها (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-fi/strings.xml b/java/res/values-fi/strings.xml
index f37247a..e113531 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Näppäimistöteema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"englanti (Iso-Britannia)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"englanti (Yhdysvallat)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ei kieltä (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Käytettävyystutkimustila"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Näppäimenpainalluksen värinän kestoasetukset"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Näppäimenpainalluksen äänenvoimakkuusasetukset"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 96aadfb..fc26597 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Pas de langue (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-hi/strings.xml b/java/res/values-hi/strings.xml
index a502a8f..5289820 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"कोई भाषा नहीं (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-hr/strings.xml b/java/res/values-hr/strings.xml
index 093b22e..c0fbd81 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nema jezika (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 a414821..c001eb5 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nincs nyelv (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-in/strings.xml b/java/res/values-in/strings.xml
index 9b27268..b5d97ad 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema keyboard"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inggris (Inggris)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inggris (AS)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Tanpa bahasa (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modus studi daya guna"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Setelan durasi getaran saat tombol ditekan"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Setelan volume suara saat tombol ditekan"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index a8923be..6642888 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema della tastiera"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inglese (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inglese (USA)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nessuna lingua (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modalità Studio sull\'usabilità"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Impostazioni durata vibrazione alla pressione di un tasto"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Impostazioni volume audio alla pressione di un tasto"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 569f71d..f08c03f 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"אין שפה (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 8c20b46..34f2358 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"言語設定なし(QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-ko/strings.xml b/java/res/values-ko/strings.xml
index f9524cc..15744c9 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"언어가 없음(QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-lt/strings.xml b/java/res/values-lt/strings.xml
index b08d059..43a3f6c 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nėra kalbos (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 c802340..7f5ee14 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nav valodas (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-ms/strings.xml b/java/res/values-ms/strings.xml
index 95f9706..d131ba8 100644
--- a/java/res/values-ms/strings.xml
+++ b/java/res/values-ms/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema papan kekunci"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Bahasa Inggeris (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Bahasa Inggeris (AS)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Tiada bahasa (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Mod kajian kebolehgunaan"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Tetapan tempoh getaran tekan kekunci"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Tetapan kelantangan bunyi tekanan kekunci"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 28e4e97..96a9f7c 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tastaturtema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engelsk (Storbritannia)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Engelsk (USA)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ingen språk (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Nyttighetsmodus"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Innstillinger for vibrasjonsvarighet ved tastetrykk"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Innstillinger for lydstyrke ved tastetrykk"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 7ba51bc..476562c 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Geen taal (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 49f7518..dcb372d 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Brak języka (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 037ceb9..6ebf932 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -118,7 +118,23 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Inglês (RU)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Inglês (EUA)"</string>
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nenhum idioma (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Modo de estudo da capacidade de utilização"</string>
     <string name="prefs_keypress_vibration_duration_settings" msgid="1829950405285211668">"Definições de duração da vibração ao premir as teclas"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="5875933757082305040">"Definições de volume de som ao premir as teclas"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 1969888..3c31ab2 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nenhum idioma (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-rm/strings.xml b/java/res/values-rm/strings.xml
index 02de4c4..e589e8b 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -201,8 +201,24 @@
     <skip />
     <!-- no translation found for subtype_en_US (6160452336634534239) -->
     <skip />
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
     <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
     <skip />
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
     <skip />
     <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 80a6558..8dead17 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Nicio limbă (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 6345ed8..00bdabb 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Язык не указан (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 57bc3a0..eba3efa 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Žiadny jazyk (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 890877f..6d2dc07 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ni jezika (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 f21abd2..6fa75ae 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Нема језика (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 918fa42..302ded4 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Inget språk (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 39ecc02..8739edb 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Hakuna lugha (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 87838ad..13c513a 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"ไม่มีภาษา (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-tl/strings.xml b/java/res/values-tl/strings.xml
index 2bf661f..381cf1b 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Walang wika (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 abca632..cbe4622 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Dil yok (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-uk/strings.xml b/java/res/values-uk/strings.xml
index 1bc2ca7..33e1d40 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Немає мови (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-vi/strings.xml b/java/res/values-vi/strings.xml
index 362882e..fd4364f 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Không có ngôn ngữ (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 73cec6e..9a468d5 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"无语言(QWERTY 键盘)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index d91abf9..eafd43a 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"無語言 (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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 973b2e5..47ddc0c 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -118,7 +118,23 @@
     <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 (141420857808801746) -->
+    <skip />
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Akunalimi (QWERTY)"</string>
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
     <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/predefined-subtypes.xml b/java/res/values/predefined-subtypes.xml
index e67fee5..602f53e 100644
--- a/java/res/values/predefined-subtypes.xml
+++ b/java/res/values/predefined-subtypes.xml
@@ -18,6 +18,6 @@
 */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Predefined subtypes (language:layout) in CSV format -->
-    <string name="predefined_subtypes" translatable="false">de:qwerty,fr:qwertz</string>
+    <!-- Predefined subtypes (language:layout[:extraValue]) in semicolon separated format -->
+    <string name="predefined_subtypes" translatable="false">de:qwerty:AsciiCapable;fr:qwertz:AsciiCapable</string>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 28acd0f..93bd268 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -252,9 +252,26 @@
     <string name="subtype_en_GB">English (UK)</string>
     <!-- Description for English (United States) keyboard subtype [CHAR LIMIT=22] -->
     <string name="subtype_en_US">English (US)</string>
+    <!-- Description for language agnostic keyboard subtype [CHAR LIMIT=22] -->
+    <string name="subtype_no_language">No language</string>
     <!-- Description for language agnostic QWERTY keyboard subtype [CHAR LIMIT=22] -->
     <string name="subtype_no_language_qwerty">No language (QWERTY)</string>
 
+    <!-- Title of the preference settings for custom input styles (language and keyboard layout pairs) [CHAR LIMIT=22]-->
+    <string name="custom_input_styles_title">Custom input styles</string>
+    <!-- Title of the option menu to add a new style entry in the preference settings [CHAR_LIMIT=12] -->
+    <string name="add_style">Add style</string>
+    <!-- Title of the button to add custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <string name="add">Add</string>
+    <!-- Title of the button to remove a custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <string name="remove">Remove</string>
+    <!-- Title of the button to save a custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <string name="save">Save</string>
+    <!-- Title of the spinner for choosing a language of custom style in the settings dialog [CHAR_LIMIT=12]  -->
+    <string name="subtype_locale">Language</string>
+    <!-- Title of the spinner for choosing a keyboard layout of custom style in the settings dialog [CHAR_LIMIT=12]  -->
+    <string name="keyboard_layout_set">Layout</string>
+
     <!-- Title of an option for usability study mode -->
     <string name="prefs_usability_study_mode">Usability study mode</string>
     <!-- Title of the settings for keypress vibration duration -->
diff --git a/java/res/xml/additional_subtype_settings.xml b/java/res/xml/additional_subtype_settings.xml
new file mode 100644
index 0000000..ad280c1
--- /dev/null
+++ b/java/res/xml/additional_subtype_settings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Items will be added at runtime -->
+</PreferenceScreen>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index ab5d44b..3598a68 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -100,6 +100,10 @@
                 android:summary="@string/include_other_imes_in_language_switch_list_summary"
                 android:persistent="true"
                 android:defaultValue="false" />
+            <PreferenceScreen
+                android:fragment="com.android.inputmethod.latin.AdditionalSubtypeSettings"
+                android:key="custom_input_styles"
+                android:title="@string/custom_input_styles_title" />
             <!-- Values for popup dismiss delay are added programatically -->
             <ListPreference
                 android:key="pref_key_preview_popup_dismiss_delay"
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index b7eb8f6..233716a 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.keyboard;
 
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
+
 import android.text.InputType;
 import android.text.TextUtils;
 import android.view.inputmethod.EditorInfo;
@@ -23,7 +25,6 @@
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.latin.InputTypeUtils;
-import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.SubtypeLocale;
 
 import java.util.Arrays;
@@ -184,7 +185,7 @@
         return String.format("[%s %s:%s %s%d %s %s %s%s%s%s%s%s%s%s]",
                 elementIdToName(mElementId),
                 mLocale,
-                mSubtype.getExtraValueOf(LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET),
+                mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
                 (mOrientation == 1 ? "port" : "land"), mWidth,
                 modeName(mMode),
                 imeAction(),
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 35209e0..8c72468 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -16,6 +16,12 @@
 
 package com.android.inputmethod.keyboard;
 
+import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_SETTINGS_KEY;
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -29,11 +35,10 @@
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet.Params.ElementParams;
+import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.InputTypeUtils;
-import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.XmlParseUtils;
@@ -229,8 +234,8 @@
 
             params.mMode = getKeyboardMode(editorInfo);
             params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO;
-            params.mNoSettingsKey = StringUtils.inPrivateImeOptions(
-                    mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo);
+            params.mNoSettingsKey = InputAttributes.inPrivateImeOptions(
+                    mPackageName, NO_SETTINGS_KEY, mEditorInfo);
         }
 
         public Builder setScreenGeometry(int orientation, int widthPixels) {
@@ -240,10 +245,10 @@
         }
 
         public Builder setSubtype(InputMethodSubtype subtype) {
-            final boolean asciiCapable = subtype.containsExtraValueKey(
-                    LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE);
-            final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions(
-                    mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo);
+            final boolean asciiCapable = subtype.containsExtraValueKey(ASCII_CAPABLE);
+            @SuppressWarnings("deprecation")
+            final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions(
+                    mPackageName, FORCE_ASCII, mEditorInfo);
             final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
                     mParams.mEditorInfo.imeOptions)
                     || deprecatedForceAscii;
@@ -259,10 +264,10 @@
         public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain,
                 boolean languageSwitchKeyEnabled) {
             @SuppressWarnings("deprecation")
-            final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions(
-                    null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo);
-            final boolean noMicrophone = StringUtils.inPrivateImeOptions(
-                    mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo)
+            final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions(
+                    null, NO_MICROPHONE_COMPAT, mEditorInfo);
+            final boolean noMicrophone = InputAttributes.inPrivateImeOptions(
+                    mPackageName, NO_MICROPHONE, mEditorInfo)
                     || deprecatedNoMicrophone;
             mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone;
             mParams.mVoiceKeyOnMain = voiceKeyOnMain;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index 9bbd3a2..8261400 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -159,7 +159,7 @@
         return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1));
     }
 
-    private static String getOutputText(String moreKeySpec) {
+    static String getOutputText(String moreKeySpec) {
         if (hasCode(moreKeySpec)) {
             return null;
         }
@@ -183,7 +183,7 @@
         return (StringUtils.codePointCount(label) == 1) ? null : label;
     }
 
-    private static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) {
+    static int getCode(String moreKeySpec, KeyboardCodesSet codesSet) {
         if (hasCode(moreKeySpec)) {
             final int end = indexOfLabelEnd(moreKeySpec, 0);
             if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
@@ -219,7 +219,7 @@
         }
     }
 
-    private static int getIconId(String moreKeySpec) {
+    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);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java
index a46f3bf..0518b07 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardLabelsSet.java
@@ -138,75 +138,76 @@
         /* 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",
+        /* 51 */ "more_keys_for_star",
+        /* 52 */ "more_keys_for_plus",
+        /* 53 */ "more_keys_for_left_parenthesis",
+        /* 54 */ "more_keys_for_right_parenthesis",
+        /* 55 */ "more_keys_for_less_than",
+        /* 56 */ "more_keys_for_greater_than",
+        /* 57 */ "keylabel_for_popular_domain",
+        /* 58 */ "more_keys_for_popular_domain",
+        /* 59 */ "keylabel_for_symbols_1",
+        /* 60 */ "keylabel_for_symbols_2",
+        /* 61 */ "keylabel_for_symbols_3",
+        /* 62 */ "keylabel_for_symbols_4",
+        /* 63 */ "keylabel_for_symbols_5",
+        /* 64 */ "keylabel_for_symbols_6",
+        /* 65 */ "keylabel_for_symbols_7",
+        /* 66 */ "keylabel_for_symbols_8",
+        /* 67 */ "keylabel_for_symbols_9",
+        /* 68 */ "keylabel_for_symbols_0",
+        /* 69 */ "additional_more_keys_for_symbols_1",
+        /* 70 */ "additional_more_keys_for_symbols_2",
+        /* 71 */ "additional_more_keys_for_symbols_3",
+        /* 72 */ "additional_more_keys_for_symbols_4",
+        /* 73 */ "additional_more_keys_for_symbols_5",
+        /* 74 */ "additional_more_keys_for_symbols_6",
+        /* 75 */ "additional_more_keys_for_symbols_7",
+        /* 76 */ "additional_more_keys_for_symbols_8",
+        /* 77 */ "additional_more_keys_for_symbols_9",
+        /* 78 */ "additional_more_keys_for_symbols_0",
+        /* 79 */ "more_keys_for_symbols_1",
+        /* 80 */ "more_keys_for_symbols_2",
+        /* 81 */ "more_keys_for_symbols_3",
+        /* 82 */ "more_keys_for_symbols_4",
+        /* 83 */ "more_keys_for_symbols_5",
+        /* 84 */ "more_keys_for_symbols_6",
+        /* 85 */ "more_keys_for_symbols_7",
+        /* 86 */ "more_keys_for_symbols_8",
+        /* 87 */ "more_keys_for_symbols_9",
+        /* 88 */ "more_keys_for_symbols_0",
+        /* 89 */ "keylabel_for_comma",
+        /* 90 */ "more_keys_for_comma",
+        /* 91 */ "keylabel_for_symbols_question",
+        /* 92 */ "keylabel_for_symbols_semicolon",
+        /* 93 */ "keylabel_for_symbols_percent",
+        /* 94 */ "more_keys_for_symbols_question",
+        /* 95 */ "more_keys_for_symbols_semicolon",
+        /* 96 */ "more_keys_for_symbols_percent",
+        /* 97 */ "keylabel_for_tablet_comma",
+        /* 98 */ "keyhintlabel_for_tablet_comma",
+        /* 99 */ "more_keys_for_tablet_comma",
+        /* 100 */ "keyhintlabel_for_tablet_period",
+        /* 101 */ "more_keys_for_tablet_period",
+        /* 102 */ "keylabel_for_apostrophe",
+        /* 103 */ "keylabel_for_dash",
+        /* 104 */ "keyhintlabel_for_apostrophe",
+        /* 105 */ "keyhintlabel_for_dash",
+        /* 106 */ "more_keys_for_apostrophe",
+        /* 107 */ "more_keys_for_dash",
+        /* 108 */ "more_keys_for_bullet",
+        /* 109 */ "more_keys_for_am_pm",
+        /* 110 */ "settings_as_more_key",
+        /* 111 */ "shortcut_as_more_key",
+        /* 112 */ "action_next_as_more_key",
+        /* 113 */ "action_previous_as_more_key",
+        /* 114 */ "label_to_more_symbol_key",
+        /* 115 */ "label_to_more_symbol_for_tablet_key",
+        /* 116 */ "label_tab_key",
+        /* 117 */ "label_to_phone_numeric_key",
+        /* 118 */ "label_to_phone_symbols_key",
+        /* 119 */ "label_time_am",
+        /* 120 */ "label_time_pm",
     };
 
     private static final String EMPTY = "";
@@ -220,9 +221,11 @@
         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>
+        // 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>
+        // 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
@@ -236,88 +239,16 @@
         /* 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",
+        /* 51 */ "\u2020,\u2021,\u2605",
         // U+00B1: "±" PLUS-MINUS SIGN
-        /* 108 */ "\u00B1",
+        /* 52 */ "\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,>,},]",
+        /* 53 */ "!fixedColumnOrder!3,<,{,[",
+        /* 54 */ "!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
@@ -333,23 +264,97 @@
         // 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",
+        /* 55 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
+        /* 56 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
+        /* 57 */ ".com",
+        // popular web domains for the locale - most popular, displayed on the keyboard
+        /* 58 */ "!hasLabels!,.net,.org,.gov,.edu",
+        /* 59 */ "1",
+        /* 60 */ "2",
+        /* 61 */ "3",
+        /* 62 */ "4",
+        /* 63 */ "5",
+        /* 64 */ "6",
+        /* 65 */ "7",
+        /* 66 */ "8",
+        /* 67 */ "9",
+        /* 68 */ "0",
+        /* 69~ */
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        /* ~78 */
+        // 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
+        /* 79 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+        // U+00B2: "²" SUPERSCRIPT TWO
+        // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
+        /* 80 */ "\u00B2,\u2154",
+        // U+00B3: "³" SUPERSCRIPT THREE
+        // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
+        // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
+        /* 81 */ "\u00B3,\u00BE,\u215C",
+        // U+2074: "⁴" SUPERSCRIPT FOUR
+        /* 82 */ "\u2074",
+        // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
+        /* 83 */ "\u215D",
+        /* 84 */ EMPTY,
+        // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+        /* 85 */ "\u215E",
+        /* 86 */ EMPTY,
+        /* 87 */ EMPTY,
+        // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
+        // U+2205: "∅" EMPTY SET
+        /* 88 */ "\u207F,\u2205",
+        /* 89 */ ",",
+        /* 90 */ EMPTY,
+        /* 91 */ "?",
+        /* 92 */ ";",
+        /* 93 */ "%",
+        // U+00BF: "¿" INVERTED QUESTION MARK
+        /* 94 */ "\u00BF",
+        /* 95 */ EMPTY,
+        // U+2030: "‰" PER MILLE SIGN
+        /* 96 */ "\u2030",
+        /* 97 */ ",",
+        /* 98 */ "!",
+        /* 99 */ "!",
+        /* 100 */ "?",
+        /* 101 */ "?",
+        /* 102 */ "\'",
+        /* 103 */ "-",
+        /* 104 */ "\"",
+        /* 105 */ "_",
+        /* 106 */ "\"",
+        /* 107 */ "_",
+        // U+266A: "♪" EIGHTH NOTE
+        // U+2665: "♥" BLACK HEART SUIT
+        // U+2660: "♠" BLACK SPADE SUIT
+        // U+2666: "♦" BLACK DIAMOND SUIT
+        // U+2663: "♣" BLACK CLUB SUIT
+        /* 108 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+        /* 109 */ "!fixedColumnOrder!2,!hasLabels!,!label/label_time_am,!label/label_time_pm",
+        /* 110 */ "!icon/settingsKey|!code/key_settings",
+        /* 111 */ "!icon/shortcutKey|!code/key_shortcut",
+        /* 112 */ "!hasLabels!,!label/label_next_key|!code/key_action_next",
+        /* 113 */ "!hasLabels!,!label/label_previous_key|!code/key_action_previous",
         // Label for "switch to more symbol" modifier key.  Must be short to fit on key!
-        /* 113 */ "= \\ <",
+        /* 114 */ "= \\ <",
         // Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key!
-        /* 114 */ "~ \\ {",
+        /* 115 */ "~ \\ {",
         // Label for "Tab" key.  Must be short to fit on key!
-        /* 115 */ "Tab",
+        /* 116 */ "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
+        /* 117 */ "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",
+        /* 118 */ "\uFF0A\uFF03",
         // Key label for "ante meridiem"
-        /* 118 */ "AM",
+        /* 119 */ "AM",
         // Key label for "post meridiem"
-        /* 119 */ "PM",
+        /* 120 */ "PM",
     };
 
     /* Language ar: Arabic */
@@ -359,115 +364,47 @@
         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>
+        // 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>
+        // 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+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+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.
+        // 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,
+        /* 51 */ "\u2605,\u066D",
+        /* 52 */ 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,>|<,}|{,]|[",
+        // 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
+        /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 54 */ "!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
@@ -483,8 +420,85 @@
         // 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",
+        /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        /* 57 */ null,
+        /* 58 */ null,
+        // U+0661: "١" ARABIC-INDIC DIGIT ONE
+        /* 59 */ "\u0661",
+        // U+0662: "٢" ARABIC-INDIC DIGIT TWO
+        /* 60 */ "\u0662",
+        // U+0663: "٣" ARABIC-INDIC DIGIT THREE
+        /* 61 */ "\u0663",
+        // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
+        /* 62 */ "\u0664",
+        // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
+        /* 63 */ "\u0665",
+        // U+0666: "٦" ARABIC-INDIC DIGIT SIX
+        /* 64 */ "\u0666",
+        // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
+        /* 65 */ "\u0667",
+        // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
+        /* 66 */ "\u0668",
+        // U+0669: "٩" ARABIC-INDIC DIGIT NINE
+        /* 67 */ "\u0669",
+        // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
+        /* 68 */ "\u0660",
+        /* 69 */ "1",
+        /* 70 */ "2",
+        /* 71 */ "3",
+        /* 72 */ "4",
+        /* 73 */ "5",
+        /* 74 */ "6",
+        /* 75 */ "7",
+        /* 76 */ "8",
+        /* 77 */ "9",
+        // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+        // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+        /* 78 */ "0,\u066B,\u066C",
+        /* 79~ */
+        null, null, null, null, null, null, null, null, null, null,
+        /* ~88 */
+        // U+060C: "،" ARABIC COMMA
+        /* 89 */ "\u060C",
+        /* 90 */ "\\,",
+        /* 91 */ "\u061F",
+        /* 92 */ "\u061B",
+        // U+066A: "٪" ARABIC PERCENT SIGN
+        /* 93 */ "\u066A",
+        /* 94 */ "?",
+        /* 95 */ ";",
+        // U+2030: "‰" PER MILLE SIGN
+        /* 96 */ "%,\u2030",
+        /* 97~ */
+        null, null, null, null, null,
+        /* ~101 */
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON
+        // U+061F: "؟" ARABIC QUESTION MARK
+        /* 102 */ "\u060C",
+        /* 103 */ ".",
+        /* 104 */ "\u061F",
+        /* 105 */ "\u064B",
+        /* 106 */ "\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.
+        /* 107 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,\u0670",
+        // U+266A: "♪" EIGHTH NOTE
+        /* 108 */ "\u266A",
     };
 
     /* Language be: Belarusian */
@@ -755,7 +769,7 @@
         // 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",
+        /* 1 */ "\u00E8,\u00E9,\u00EA,\u00EB,\u0113",
         // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
         // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
         // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
@@ -770,7 +784,7 @@
         // 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",
+        /* 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
@@ -954,117 +968,47 @@
         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>
+        // 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>
+        // 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+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+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.
+        // 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,
+        /* 51 */ "\u2605,\u066D",
+        /* 52 */ 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,>|<,}|{,]|[",
+        // 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
+        /* 53 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 54 */ "!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
@@ -1080,8 +1024,87 @@
         // 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",
+        /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        /* 57 */ null,
+        /* 58 */ null,
+        // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
+        /* 59 */ "\u06F1",
+        // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
+        /* 60 */ "\u06F2",
+        // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
+        /* 61 */ "\u06F3",
+        // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
+        /* 62 */ "\u06F4",
+        // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
+        /* 63 */ "\u06F5",
+        // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
+        /* 64 */ "\u06F6",
+        // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
+        /* 65 */ "\u06F7",
+        // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
+        /* 66 */ "\u06F8",
+        // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
+        /* 67 */ "\u06F9",
+        // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
+        /* 68 */ "\u06F0",
+        /* 69 */ "1",
+        /* 70 */ "2",
+        /* 71 */ "3",
+        /* 72 */ "4",
+        /* 73 */ "5",
+        /* 74 */ "6",
+        /* 75 */ "7",
+        /* 76 */ "8",
+        /* 77 */ "9",
+        // U+066B: "٫" ARABIC DECIMAL SEPARATOR
+        // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
+        /* 78 */ "0,\u066B,\u066C",
+        /* 79~ */
+        null, null, null, null, null, null, null, null, null, null,
+        /* ~88 */
+        // U+060C: "،" ARABIC COMMA
+        /* 89 */ "\u060C",
+        /* 90 */ "\\,",
+        /* 91 */ "\u061F",
+        /* 92 */ "\u061B",
+        // U+066A: "٪" ARABIC PERCENT SIGN
+        /* 93 */ "\u066A",
+        /* 94 */ "?",
+        /* 95 */ ";",
+        // U+2030: "‰" PER MILLE SIGN
+        /* 96 */ "%,\u2030",
+        // U+060C: "،" ARABIC COMMA
+        // U+061B: "؛" ARABIC SEMICOLON
+        // U+061F: "؟" ARABIC QUESTION MARK
+        /* 97 */ "\u060C",
+        /* 98 */ "!",
+        /* 99 */ "!,\\,",
+        /* 100 */ "\u061F",
+        /* 101 */ "\u061F,?",
+        /* 102~ */
+        null, null, null,
+        /* ~104 */
+        /* 105 */ "\u064B",
+        /* 106 */ "\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.
+        /* 107 */ "\u0651,\u0652,\u064C,\u0653,\u064F,\u0650,\u064E,\u064B,\u0640\u0640\u0640|\u0640,\u064D,\u0654,\u0656,\u0655,_,\u0670",
+        // U+266A: "♪" EIGHTH NOTE
+        /* 108 */ "\u266A",
     };
 
     /* Language fi: Finnish */
@@ -1190,38 +1213,38 @@
         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 */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~58 */
         // U+0967: "१" DEVANAGARI DIGIT ONE
-        /* 53 */ "\u0967",
+        /* 59 */ "\u0967",
         // U+0968: "२" DEVANAGARI DIGIT TWO
-        /* 54 */ "\u0968",
+        /* 60 */ "\u0968",
         // U+0969: "३" DEVANAGARI DIGIT THREE
-        /* 55 */ "\u0969",
+        /* 61 */ "\u0969",
         // U+096A: "४" DEVANAGARI DIGIT FOUR
-        /* 56 */ "\u096A",
+        /* 62 */ "\u096A",
         // U+096B: "५" DEVANAGARI DIGIT FIVE
-        /* 57 */ "\u096B",
+        /* 63 */ "\u096B",
         // U+096C: "६" DEVANAGARI DIGIT SIX
-        /* 58 */ "\u096C",
+        /* 64 */ "\u096C",
         // U+096D: "७" DEVANAGARI DIGIT SEVEN
-        /* 59 */ "\u096D",
+        /* 65 */ "\u096D",
         // U+096E: "८" DEVANAGARI DIGIT EIGHT
-        /* 60 */ "\u096E",
+        /* 66 */ "\u096E",
         // U+096F: "९" DEVANAGARI DIGIT NINE
-        /* 61 */ "\u096F",
+        /* 67 */ "\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",
+        /* 68 */ "\u0966",
+        /* 69 */ "1",
+        /* 70 */ "2",
+        /* 71 */ "3",
+        /* 72 */ "4",
+        /* 73 */ "5",
+        /* 74 */ "6",
+        /* 75 */ "7",
+        /* 76 */ "8",
+        /* 77 */ "9",
+        /* 78 */ "0",
     };
 
     /* Language hr: Croatian */
@@ -1411,26 +1434,24 @@
         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>
+        // 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>
+        // 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 */
+        null, null, null, null, null, null, null,
+        /* ~50 */
         // U+2605: "★" BLACK STAR
-        /* 107 */ "\u2605",
+        /* 51 */ "\u2605",
         // U+00B1: "±" PLUS-MINUS SIGN
         // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
-        /* 108 */ "\u00B1,\uFB29",
+        /* 52 */ "\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,>|<,}|{,]|[",
+        /* 53 */ "!fixedColumnOrder!3,<|>,{|},[|]",
+        /* 54 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
         // U+2264: "≤" LESS-THAN OR EQUAL TO
         // U+2265: "≥" GREATER-THAN EQUAL TO
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -1446,8 +1467,8 @@
         // 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",
+        /* 55 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 56 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
     };
 
     /* Language ky: Kirghiz */
@@ -1682,9 +1703,12 @@
         // 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>
+        // 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>
+        // 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",
     };
 
@@ -2100,9 +2124,12 @@
         // 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>
+        // 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>
+        // 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",
     };
 
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
index b24f064..28cec56 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
@@ -16,6 +16,10 @@
 
 package com.android.inputmethod.latin;
 
+import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.IS_ADDITIONAL_SUBTYPE;
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
+
 import android.view.inputmethod.InputMethodSubtype;
 
 import java.util.HashMap;
@@ -24,9 +28,11 @@
     public static final String QWERTY = "qwerty";
     public static final String QWERTZ = "qwertz";
     public static final String AZERTY = "azerty";
-
-    private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
-    private static final String SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype";
+    public static final String[] PREDEFINED_KEYBOARD_LAYOUT_SET = {
+        QWERTY,
+        QWERTZ,
+        AZERTY
+    };
 
     // Keyboard layout to subtype name resource id map.
     private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap =
@@ -38,33 +44,57 @@
         sKeyboardLayoutToNameIdsMap.put(AZERTY, R.string.subtype_generic_azerty);
     }
 
-    public static boolean isAdditionalSubtype(InputMethodSubtype subtype) {
-        return subtype.containsExtraValueKey(SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE);
+    private AdditionalSubtype() {
+        // This utility class is not publicly instantiable.
     }
 
-    public static InputMethodSubtype createAdditionalSubtype(
-            String localeString, String keyboardLayoutSet) {
-        final String extraValue = String.format(
-                "%s=%s,%s", LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET, keyboardLayoutSet,
-                SUBTYPE_EXTRA_VALUE_IS_ADDITIONAL_SUBTYPE);
-        Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSet);
-        if (nameId == null) nameId = R.string.subtype_generic;
-        return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard,
-                localeString, SUBTYPE_MODE_KEYBOARD, extraValue, false, false);
+    public static boolean isAdditionalSubtype(InputMethodSubtype subtype) {
+        return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE);
     }
 
     private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":";
-    private static final String SUBTYPE_SEPARATOR = ",";
+    public static final String PREF_SUBTYPE_SEPARATOR = ";";
 
-    public static InputMethodSubtype[] createAdditionalSubtypesArray(String csvSubtypes) {
-        final String[] subtypeSpecs = csvSubtypes.split(SUBTYPE_SEPARATOR);
-        final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[subtypeSpecs.length];
-        for (int i = 0; i < subtypeSpecs.length; i++) {
-            final String elems[] = subtypeSpecs[i].split(LOCALE_AND_LAYOUT_SEPARATOR);
-            final String localeString = elems[0];
-            final String keyboardLayoutSetName = elems[1];
-            subtypesArray[i] = AdditionalSubtype.createAdditionalSubtype(
-                    localeString, keyboardLayoutSetName);
+    public static InputMethodSubtype createAdditionalSubtype(
+            String localeString, String keyboardLayoutSetName, String extraValue) {
+        final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName;
+        final String filteredExtraValue = StringUtils.appendToCsvIfNotExists(
+                IS_ADDITIONAL_SUBTYPE, extraValue);
+        Integer nameId = sKeyboardLayoutToNameIdsMap.get(keyboardLayoutSetName);
+        if (nameId == null) nameId = R.string.subtype_generic;
+        return new InputMethodSubtype(nameId, R.drawable.ic_subtype_keyboard,
+                localeString, KEYBOARD_MODE,
+                layoutExtraValue + "," + filteredExtraValue, false, false);
+    }
+
+    public static String getPrefSubtype(InputMethodSubtype subtype) {
+        final String localeString = subtype.getLocale();
+        final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
+        final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName;
+        final String extraValue = StringUtils.removeFromCsvIfExists(layoutExtraValue,
+                StringUtils.removeFromCsvIfExists(IS_ADDITIONAL_SUBTYPE, subtype.getExtraValue()));
+        final String basePrefSubtype = localeString + LOCALE_AND_LAYOUT_SEPARATOR
+                + keyboardLayoutSetName;
+        return extraValue.isEmpty() ? basePrefSubtype
+                : basePrefSubtype + LOCALE_AND_LAYOUT_SEPARATOR + extraValue;
+    }
+
+    public static InputMethodSubtype createAdditionalSubtype(String prefSubtype) {
+        final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR);
+        if (elems.length < 2 || elems.length > 3) {
+            throw new RuntimeException("Unknown additional subtype specified: " + prefSubtype);
+        }
+        final String localeString = elems[0];
+        final String keyboardLayoutSetName = elems[1];
+        final String extraValue = (elems.length == 3) ? elems[2] : null;
+        return createAdditionalSubtype(localeString, keyboardLayoutSetName, extraValue);
+    }
+
+    public static InputMethodSubtype[] createAdditionalSubtypesArray(String prefSubtypes) {
+        final String[] prefSubtypeArray = prefSubtypes.split(PREF_SUBTYPE_SEPARATOR);
+        final InputMethodSubtype[] subtypesArray = new InputMethodSubtype[prefSubtypeArray.length];
+        for (int i = 0; i < prefSubtypeArray.length; i++) {
+            subtypesArray[i] = createAdditionalSubtype(prefSubtypeArray[i]);
         }
         return subtypesArray;
     }
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
new file mode 100644
index 0000000..7a22c97
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
@@ -0,0 +1,440 @@
+/**
+ * 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 static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.DialogPreference;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+
+import java.util.Locale;
+import java.util.TreeSet;
+
+public class AdditionalSubtypeSettings extends PreferenceFragment {
+    private SharedPreferences mPrefs;
+    private SubtypeLocaleAdapter mSubtypeLocaleAdapter;
+    private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
+
+    private PreferenceGroup mSubtypePrefGroup;
+
+    private static final int MENU_ADD_SUBTYPE = Menu.FIRST;
+
+    static class SubtypeLocaleItem extends Pair<String, String>
+            implements Comparable<SubtypeLocaleItem> {
+        public SubtypeLocaleItem(String localeString, String displayName) {
+            super(localeString, displayName);
+        }
+
+        public SubtypeLocaleItem(String localeString) {
+            this(localeString, getDisplayName(localeString));
+        }
+
+        @Override
+        public String toString() {
+            return second;
+        }
+
+        @Override
+        public int compareTo(SubtypeLocaleItem o) {
+            return first.compareTo(o.first);
+        }
+
+        private static String getDisplayName(String localeString) {
+            final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
+            return StringUtils.toTitleCase(locale.getDisplayName(locale), locale);
+        }
+    }
+
+    static class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> {
+        public SubtypeLocaleAdapter(Context context) {
+            super(context, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+            final TreeSet<SubtypeLocaleItem> items = new TreeSet<SubtypeLocaleItem>();
+            final InputMethodInfo imi = ImfUtils.getInputMethodInfoOfThisIme(context);
+            final int count = imi.getSubtypeCount();
+            for (int i = 0; i < count; i++) {
+                final InputMethodSubtype subtype = imi.getSubtypeAt(i);
+                if (subtype.containsExtraValueKey(ASCII_CAPABLE)) {
+                    items.add(createItem(context, subtype.getLocale()));
+                }
+            }
+            // TODO: Should filter out already existing combinations of locale and layout.
+            addAll(items);
+        }
+
+        public static SubtypeLocaleItem createItem(Context context, String localeString) {
+            if (localeString.equals(SubtypeLocale.NO_LANGUAGE)) {
+                final String displayName = context.getString(R.string.subtype_no_language);
+                return new SubtypeLocaleItem(localeString, displayName);
+            } else {
+                return new SubtypeLocaleItem(localeString);
+            }
+        }
+    }
+
+    static class KeyboardLayoutSetItem extends Pair<String, String> {
+        public KeyboardLayoutSetItem(String keyboardLayoutSetName) {
+            super(keyboardLayoutSetName, getDisplayName(keyboardLayoutSetName));
+        }
+
+        @Override
+        public String toString() {
+            return second;
+        }
+
+        private static String getDisplayName(String keyboardLayoutSetName) {
+            return keyboardLayoutSetName.toUpperCase();
+        }
+    }
+
+    static class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> {
+        public KeyboardLayoutSetAdapter(Context context) {
+            super(context, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+            // TODO: Should filter out already existing combinations of locale and layout.
+            for (final String layout : AdditionalSubtype.PREDEFINED_KEYBOARD_LAYOUT_SET) {
+                add(new KeyboardLayoutSetItem(layout));
+            }
+        }
+    }
+
+    private interface SubtypeDialogProxy {
+        public void onRemovePressed(SubtypePreference subtypePref);
+        public SubtypeLocaleAdapter getSubtypeLocaleAdapter();
+        public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter();
+    }
+
+    static class SubtypePreference extends DialogPreference {
+        private InputMethodSubtype mSubtype;
+
+        private final SubtypeDialogProxy mProxy;
+        private Spinner mSubtypeLocaleSpinner;
+        private Spinner mKeyboardLayoutSetSpinner;
+
+        public SubtypePreference(Context context, InputMethodSubtype subtype,
+                    SubtypeDialogProxy proxy) {
+            super(context, null);
+            setPersistent(false);
+            mProxy = proxy;
+            setSubtype(subtype);
+        }
+
+        public void show() {
+            showDialog(null);
+        }
+
+        public InputMethodSubtype getSubtype() {
+            return mSubtype;
+        }
+
+        public void setSubtype(InputMethodSubtype subtype) {
+            mSubtype = subtype;
+            if (subtype == null) {
+                setTitle(null);
+                setDialogTitle(R.string.add_style);
+            } else {
+                final String displayName = SubtypeLocale.getFullDisplayName(subtype);
+                setTitle(displayName);
+                setDialogTitle(displayName);
+            }
+        }
+
+        @Override
+        protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+            final Context context = builder.getContext();
+            final View v = LayoutInflater.from(context).inflate(
+                    R.layout.additional_subtype_dialog, null);
+            builder.setView(v);
+            mSubtypeLocaleSpinner = (Spinner) v.findViewById(R.id.subtype_locale_spinner);
+            mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
+            mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
+            mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
+
+            if (mSubtype == null) {
+                builder.setPositiveButton(R.string.add, this)
+                        .setNegativeButton(android.R.string.cancel, this);
+            } else {
+                builder.setPositiveButton(R.string.save, this)
+                        .setNeutralButton(android.R.string.cancel, this)
+                        .setNegativeButton(R.string.remove, this);
+                final SubtypeLocaleItem localeItem = SubtypeLocaleAdapter.createItem(
+                        context, mSubtype.getLocale());
+                final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem(
+                        SubtypeLocale.getKeyboardLayoutSetName(mSubtype));
+                setSpinnerPosition(mSubtypeLocaleSpinner, localeItem);
+                setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem);
+            }
+        }
+
+        private static void setSpinnerPosition(Spinner spinner, Object itemToSelect) {
+            final SpinnerAdapter adapter = spinner.getAdapter();
+            final int count = adapter.getCount();
+            for (int i = 0; i < count; i++) {
+                final Object item = spinner.getItemAtPosition(i);
+                if (item.equals(itemToSelect)) {
+                    spinner.setSelection(i);
+                    return;
+                }
+            }
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            super.onClick(dialog, which);
+            switch (which) {
+            case DialogInterface.BUTTON_POSITIVE:
+                final SubtypeLocaleItem locale =
+                        (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem();
+                final KeyboardLayoutSetItem layout =
+                        (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem();
+                final InputMethodSubtype subtype = AdditionalSubtype.createAdditionalSubtype(
+                        locale.first, layout.first, ASCII_CAPABLE);
+                setSubtype(subtype);
+                notifyChanged();
+                break;
+            case DialogInterface.BUTTON_NEUTRAL:
+                // Nothing to do
+                break;
+            case DialogInterface.BUTTON_NEGATIVE:
+                mProxy.onRemovePressed(this);
+                break;
+            }
+        }
+
+        @Override
+        protected Parcelable onSaveInstanceState() {
+            final SavedState myState = new SavedState(super.onSaveInstanceState());
+            myState.mSubtype = mSubtype;
+            return myState;
+        }
+
+        @Override
+        protected void onRestoreInstanceState(Parcelable state) {
+            if (state instanceof SavedState) {
+                final SavedState myState = (SavedState) state;
+                super.onRestoreInstanceState(state);
+                setSubtype(myState.mSubtype);
+            } else {
+                super.onRestoreInstanceState(state);
+            }
+        }
+
+        static class SavedState extends Preference.BaseSavedState {
+            InputMethodSubtype mSubtype;
+            private static final byte VALID = 1;
+            private static final byte INVALID = 0;
+
+            public SavedState(Parcelable superState) {
+                super(superState);
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                super.writeToParcel(dest, flags);
+                if (mSubtype != null) {
+                    dest.writeByte(VALID);
+                    mSubtype.writeToParcel(dest, 0);
+                } else {
+                    dest.writeByte(INVALID);
+                }
+            }
+
+            public SavedState(Parcel source) {
+                super(source);
+                if (source.readByte() == VALID) {
+                    mSubtype = source.readParcelable(null);
+                } else {
+                    mSubtype = null;
+                }
+            }
+
+            public static final Parcelable.Creator<SavedState> CREATOR =
+                    new Parcelable.Creator<SavedState>() {
+                        @Override
+                        public SavedState createFromParcel(Parcel source) {
+                            return new SavedState(source);
+                        }
+
+                        @Override
+                        public SavedState[] newArray(int size) {
+                            return new SavedState[size];
+                        }
+                    };
+        }
+    }
+
+    public AdditionalSubtypeSettings() {
+        // Empty constructor for fragment generation.
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        addPreferencesFromResource(R.xml.additional_subtype_settings);
+        setHasOptionsMenu(true);
+        mSubtypePrefGroup = getPreferenceScreen();
+
+        mPrefs = getPreferenceManager().getSharedPreferences();
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        final Context context = getActivity();
+        mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context);
+        mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context);
+
+        // TODO: Restore editing dialog if any.
+    }
+
+    private final SubtypeDialogProxy mSubtypeProxy = new SubtypeDialogProxy() {
+        @Override
+        public void onRemovePressed(SubtypePreference subtypePref) {
+            final PreferenceGroup group = mSubtypePrefGroup;
+            if (group != null) {
+                group.removePreference(subtypePref);
+            }
+        }
+
+        @Override
+        public SubtypeLocaleAdapter getSubtypeLocaleAdapter() {
+            return mSubtypeLocaleAdapter;
+        }
+
+        @Override
+        public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter() {
+            return mKeyboardLayoutSetAdapter;
+        }
+    };
+
+    private void setPrefSubtypes(String prefSubtypes, Context context) {
+        final PreferenceGroup group = mSubtypePrefGroup;
+        group.removeAll();
+        final String[] prefSubtypeArray = prefSubtypes.split(
+                AdditionalSubtype.PREF_SUBTYPE_SEPARATOR);
+        for (final String prefSubtype : prefSubtypeArray) {
+            final InputMethodSubtype subtype =
+                    AdditionalSubtype.createAdditionalSubtype(prefSubtype);
+            final SubtypePreference pref = new SubtypePreference(
+                    context, subtype, mSubtypeProxy);
+            group.addPreference(pref);
+        }
+    }
+
+    private String getPrefSubtypes() {
+        final StringBuilder sb = new StringBuilder();
+        final int count = mSubtypePrefGroup.getPreferenceCount();
+        for (int i = 0; i < count; i++) {
+            final Preference pref = mSubtypePrefGroup.getPreference(i);
+            if (pref instanceof SubtypePreference) {
+                final InputMethodSubtype subtype = ((SubtypePreference)pref).getSubtype();
+                if (sb.length() > 0) {
+                    sb.append(AdditionalSubtype.PREF_SUBTYPE_SEPARATOR);
+                }
+                sb.append(AdditionalSubtype.getPrefSubtype(subtype));
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        final String prefSubtypes =
+                SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources());
+        setPrefSubtypes(prefSubtypes, getActivity());
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources());
+        final String prefSubtypes = getPrefSubtypes();
+        if (prefSubtypes.equals(oldSubtypes)) {
+            return;
+        }
+
+        final SharedPreferences.Editor editor = mPrefs.edit();
+        try {
+            editor.putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes);
+        } finally {
+            editor.apply();
+        }
+        final InputMethodSubtype[] subtypes =
+                AdditionalSubtype.createAdditionalSubtypesArray(prefSubtypes);
+        ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), subtypes);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        // TODO: save editing dialog state.
+    }
+
+    @Override
+    public boolean onPreferenceTreeClick(PreferenceScreen prefScreen, Preference pref) {
+        if (pref instanceof SubtypePreference) {
+            return true;
+        }
+        return super.onPreferenceTreeClick(prefScreen, pref);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style);
+        addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        final int itemId = item.getItemId();
+        if (itemId == MENU_ADD_SUBTYPE) {
+            final SubtypePreference subtypePref = new SubtypePreference(
+                    getActivity(), null, mSubtypeProxy);
+            mSubtypePrefGroup.addPreference(subtypePref);
+            subtypePref.show();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
new file mode 100644
index 0000000..b205cc0
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -0,0 +1,103 @@
+/*
+ * 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.view.inputmethod.EditorInfo;
+
+public final class Constants {
+    public static final class ImeOption {
+        /**
+         * The private IME option used to indicate that no microphone should be shown for a given
+         * text field. For instance, this is specified by the search dialog when the dialog is
+         * already showing a voice search button.
+         *
+         * @deprecated Use {@link ImeOption#NO_MICROPHONE} with package name prefixed.
+         */
+        @SuppressWarnings("dep-ann")
+        public static final String NO_MICROPHONE_COMPAT = "nm";
+
+        /**
+         * The private IME option used to indicate that no microphone should be shown for a given
+         * text field. For instance, this is specified by the search dialog when the dialog is
+         * already showing a voice search button.
+         */
+        public static final String NO_MICROPHONE = "noMicrophoneKey";
+
+        /**
+         * The private IME option used to indicate that no settings key should be shown for a given
+         * text field.
+         */
+        public static final String NO_SETTINGS_KEY = "noSettingsKey";
+
+        /**
+         * The private IME option used to indicate that the given text field needs ASCII code points
+         * input.
+         *
+         * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}.
+         */
+        @SuppressWarnings("dep-ann")
+        public static final String FORCE_ASCII = "forceAscii";
+
+        private ImeOption() {
+            // This utility class is not publicly instantiable.
+        }
+    }
+
+    public static final class Subtype {
+        /**
+         * The subtype mode used to indicate that the subtype is a keyboard.
+         */
+        public static final String KEYBOARD_MODE = "keyboard";
+
+        public static final class ExtraValue {
+            /**
+             * The subtype extra value used to indicate that the subtype keyboard layout set name.
+             */
+            public static final String KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet";
+
+            /**
+             * The subtype extra value used to indicate that the subtype keyboard layout is capable
+             * for typing ASCII characters.
+             */
+            public static final String ASCII_CAPABLE = "AsciiCapable";
+
+            /**
+             * The subtype extra value used to indicate that the subtype require network connection
+             * to work.
+             */
+            public static final String REQ_NETWORK_CONNECTIVITY = "requireNetworkConnectivity";
+
+            /**
+             * The subtype extra value used to indicate that the subtype is additional subtype
+             * that the user defined. This extra value is private to LatinIME.
+             */
+            public static final String IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype";
+
+            private ExtraValue() {
+                // This utility class is not publicly instantiable.
+            }
+        }
+
+        private Subtype() {
+            // This utility class is not publicly instantiable.
+        }
+    }
+
+    private Constants() {
+        // This utility class is not publicly instantiable.
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 17d7536..f5dc7b3 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -30,7 +30,10 @@
  * Factory for dictionary instances.
  */
 public class DictionaryFactory {
-    private static String TAG = DictionaryFactory.class.getSimpleName();
+    private static final String TAG = DictionaryFactory.class.getSimpleName();
+    // This class must be located in the same package as LatinIME.java.
+    private static final String RESOURCE_PACKAGE_NAME =
+            DictionaryFactory.class.getPackage().getName();
 
     /**
      * Initializes a dictionary from a dictionary pack, with explicit flags.
@@ -166,20 +169,19 @@
      */
     private static int getMainDictionaryResourceIdIfAvailableForLocale(final Resources res,
             final 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) {
+            if ((resId = res.getIdentifier(
+                    dictLanguageCountry, "raw", RESOURCE_PACKAGE_NAME)) != 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) {
+        if ((resId = res.getIdentifier(dictLanguage, "raw", RESOURCE_PACKAGE_NAME)) != 0) {
             return resId;
         }
 
@@ -195,7 +197,6 @@
     public static int getMainDictionaryResourceId(final Resources res, final Locale locale) {
         int resourceId = getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
         if (0 != resourceId) return resourceId;
-        final String packageName = LatinIME.class.getPackage().getName();
-        return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", packageName);
+        return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", RESOURCE_PACKAGE_NAME);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/ImfUtils.java b/java/src/com/android/inputmethod/latin/ImfUtils.java
index bd7d89f..4633b82 100644
--- a/java/src/com/android/inputmethod/latin/ImfUtils.java
+++ b/java/src/com/android/inputmethod/latin/ImfUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
+
 import android.content.Context;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -131,7 +133,7 @@
         // both explicitly and implicitly enabled input method subtype.
         // (The current IME should be LatinIME.)
         for (InputMethodSubtype subtype : subtypes) {
-            if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) {
+            if (KEYBOARD_MODE.equals(subtype.getMode())) {
                 ++keyboardCount;
             }
         }
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index a6ce040..9c32f94 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -162,4 +162,12 @@
                 + "\n mIsSettingsSuggestionStripOn = " + mIsSettingsSuggestionStripOn
                 + "\n mApplicationSpecifiedCompletionOn = " + mApplicationSpecifiedCompletionOn;
     }
+
+    public static boolean inPrivateImeOptions(String packageName, String key,
+            EditorInfo editorInfo) {
+        if (editorInfo == null) return false;
+        final String findingKey = (packageName != null) ? packageName + "." + key
+                : key;
+        return StringUtils.containsInCsv(findingKey, editorInfo.privateImeOptions);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 682901c..41884d3 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -16,6 +16,10 @@
 
 package com.android.inputmethod.latin;
 
+import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE;
+import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT;
+
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -81,49 +85,6 @@
     private static final boolean TRACE = false;
     private static boolean DEBUG;
 
-    /**
-     * The private IME option used to indicate that no microphone should be
-     * shown for a given text field. For instance, this is specified by the
-     * search dialog when the dialog is already showing a voice search button.
-     *
-     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
-     */
-    @SuppressWarnings("dep-ann")
-    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
-
-    /**
-     * The private IME option used to indicate that no microphone should be
-     * shown for a given text field. For instance, this is specified by the
-     * search dialog when the dialog is already showing a voice search button.
-     */
-    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
-
-    /**
-     * The private IME option used to indicate that no settings key should be
-     * shown for a given text field.
-     */
-    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
-
-    /**
-     * The private IME option used to indicate that the given text field needs
-     * ASCII code points input.
-     *
-     * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}.
-     */
-    @SuppressWarnings("dep-ann")
-    public static final String IME_OPTION_FORCE_ASCII = "forceAscii";
-
-    /**
-     * The subtype extra value used to indicate that the subtype keyboard layout set name.
-     */
-    public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet";
-
-    /**
-     * The subtype extra value used to indicate that the subtype keyboard layout is capable for
-     * typing ASCII characters.
-     */
-    public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
-
     private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
 
     // How many continuous deletes at which to start deleting at a higher speed.
@@ -193,6 +154,7 @@
     private final SubtypeSwitcher mSubtypeSwitcher;
     private boolean mShouldSwitchToLastSubtype = true;
 
+    private boolean mIsMainDictionaryAvailable;
     private UserDictionary mUserDictionary;
     private UserHistoryDictionary mUserHistoryDictionary;
     private boolean mIsUserDictionaryAvailable;
@@ -488,14 +450,14 @@
                 return new SettingsValues(mPrefs, LatinIME.this);
             }
         };
-        mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getInputLocale());
+        mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
         mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues);
         resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
     }
 
     private void initSuggest() {
-        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
-        final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale();
+        final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+        final String localeStr = subtypeLocale.toString();
 
         final Dictionary oldContactsDictionary;
         if (mSuggest != null) {
@@ -504,11 +466,13 @@
         } else {
             oldContactsDictionary = null;
         }
-        mSuggest = new Suggest(this, keyboardLocale);
+        mSuggest = new Suggest(this, subtypeLocale);
         if (mSettingsValues.mAutoCorrectEnabled) {
             mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
         }
 
+        mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
+
         mUserDictionary = new UserDictionary(this, localeStr);
         mSuggest.setUserDictionary(mUserDictionary);
         mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
@@ -550,7 +514,7 @@
         } else {
             if (USE_BINARY_CONTACTS_DICTIONARY) {
                 dictionaryToUse = new ContactsBinaryDictionary(this, Suggest.DIC_CONTACTS,
-                        mSubtypeSwitcher.getInputLocale());
+                        mSubtypeSwitcher.getCurrentSubtypeLocale());
             } else {
                 dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
             }
@@ -562,7 +526,9 @@
     }
 
     /* package private */ void resetSuggestMainDict() {
-        mSuggest.resetMainDict(this, mSubtypeSwitcher.getInputLocale());
+        final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+        mSuggest.resetMainDict(this, subtypeLocale);
+        mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
     }
 
     @Override
@@ -642,13 +608,14 @@
 
     @Override
     public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
-        SubtypeSwitcher.getInstance().updateSubtype(subtype);
+        mSubtypeSwitcher.updateSubtype(subtype);
     }
 
     private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) {
         super.onStartInput(editorInfo, restarting);
     }
 
+    @SuppressWarnings("deprecation")
     private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) {
         super.onStartInputView(editorInfo, restarting);
         final KeyboardSwitcher switcher = mKeyboardSwitcher;
@@ -669,12 +636,12 @@
         if (ProductionFlag.IS_EXPERIMENTAL) {
             ResearchLogger.latinIME_onStartInputViewInternal(editorInfo);
         }
-        if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) {
+        if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
             Log.w(TAG, "Deprecated private IME option specified: "
                     + editorInfo.privateImeOptions);
-            Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead");
+            Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead");
         }
-        if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) {
+        if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) {
             Log.w(TAG, "Deprecated private IME option specified: "
                     + editorInfo.privateImeOptions);
             Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
@@ -1077,7 +1044,7 @@
         if (ic == null) return false;
         final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
         if (lastThree != null && lastThree.length() == 3
-                && StringUtils.canBeFollowedByPeriod(lastThree.charAt(0))
+                && canBeFollowedByPeriod(lastThree.charAt(0))
                 && lastThree.charAt(1) == Keyboard.CODE_SPACE
                 && lastThree.charAt(2) == Keyboard.CODE_SPACE
                 && mHandler.isAcceptingDoubleSpaces()) {
@@ -1093,6 +1060,18 @@
         return false;
     }
 
+    private static boolean canBeFollowedByPeriod(final int codePoint) {
+        // TODO: Check again whether there really ain't a better way to check this.
+        // TODO: This should probably be language-dependant...
+        return Character.isLetterOrDigit(codePoint)
+                || codePoint == Keyboard.CODE_SINGLE_QUOTE
+                || codePoint == Keyboard.CODE_DOUBLE_QUOTE
+                || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS
+                || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET
+                || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET
+                || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
+    }
+
     // "ic" may be null
     private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) {
         if (ic == null) return;
@@ -1920,7 +1899,7 @@
             if (mSettingsValues.mEnableSuggestionSpanInsertion) {
                 final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
                 ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
-                        this, bestWord, suggestedWords, mSubtypeSwitcher.isDictionaryAvailable()),
+                        this, bestWord, suggestedWords, mIsMainDictionaryAvailable),
                         1);
                 if (ProductionFlag.IS_EXPERIMENTAL) {
                     ResearchLogger.latinIME_commitText(bestWord);
@@ -1998,7 +1977,8 @@
             }
             final String secondWord;
             if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
-                secondWord = suggestion.toString().toLowerCase(mSubtypeSwitcher.getInputLocale());
+                secondWord = suggestion.toString().toLowerCase(
+                        mSubtypeSwitcher.getCurrentSubtypeLocale());
             } else {
                 secondWord = suggestion.toString();
             }
@@ -2326,8 +2306,7 @@
     }
 
     private void showOptionDialogInternal(AlertDialog dialog) {
-        final IBinder windowToken = KeyboardSwitcher.getInstance().getKeyboardView()
-                .getWindowToken();
+        final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
         if (windowToken == null) return;
 
         dialog.setCancelable(true);
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 29825df..13264f7 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -33,6 +33,7 @@
 import android.preference.PreferenceScreen;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.inputmethod.InputMethodSubtype;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -255,6 +256,7 @@
         }
         updateShowCorrectionSuggestionsSummary();
         updateKeyPreviewPopupDelaySummary();
+        updateCustomInputStylesSummary();
     }
 
     @Override
@@ -294,6 +296,21 @@
                         mShowCorrectionSuggestionsPreference.getValue())]);
     }
 
+    private void updateCustomInputStylesSummary() {
+        final PreferenceScreen customInputStyles =
+                (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES);
+        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+        final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, getResources());
+        final InputMethodSubtype[] subtypes =
+                AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype);
+        final StringBuilder styles = new StringBuilder();
+        for (final InputMethodSubtype subtype : subtypes) {
+            if (styles.length() > 0) styles.append(", ");
+            styles.append(SubtypeLocale.getFullDisplayName(subtype));
+        }
+        customInputStyles.setSummary(styles);
+    }
+
     private void updateKeyPreviewPopupDelaySummary() {
         final ListPreference lp = mKeyPreviewPopupDismissDelay;
         lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]);
diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java
index 5567013..68f8582 100644
--- a/java/src/com/android/inputmethod/latin/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/SettingsActivity.java
@@ -20,11 +20,15 @@
 import android.preference.PreferenceActivity;
 
 public class SettingsActivity extends PreferenceActivity {
+    private static final String DEFAULT_FRAGMENT = Settings.class.getName();
+
     @Override
     public Intent getIntent() {
-        final Intent modIntent = new Intent(super.getIntent());
-        modIntent.putExtra(EXTRA_SHOW_FRAGMENT, Settings.class.getName());
-        modIntent.putExtra(EXTRA_NO_HEADERS, true);
-        return modIntent;
+        final Intent intent = super.getIntent();
+        if (!intent.hasExtra(EXTRA_SHOW_FRAGMENT)) {
+            intent.putExtra(EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT);
+        }
+        intent.putExtra(EXTRA_NO_HEADERS, true);
+        return intent;
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index c160555..5f9e1bc 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -28,7 +28,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Locale;
 
 /**
  * When you call the constructor of this class, you may want to change the current system locale by
@@ -148,9 +147,8 @@
                 mAutoCorrectionThresholdRawValue);
         mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
         mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
-
         mAdditionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray(
-                getCsvAdditionalSubtypes(prefs, res));
+                getPrefAdditionalSubtypes(prefs, res));
     }
 
     // Helper functions to create member values.
@@ -315,10 +313,10 @@
         return mAdditionalSubtypes;
     }
 
-    public static String getCsvAdditionalSubtypes(final SharedPreferences prefs,
+    public static String getPrefAdditionalSubtypes(final SharedPreferences prefs,
             final Resources res) {
-        final String csvPredefinedSubtypes = res.getString(R.string.predefined_subtypes, "");
-        return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, csvPredefinedSubtypes);
+        final String prefSubtypes = res.getString(R.string.predefined_subtypes, "");
+        return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes);
     }
 
     // Accessed from the settings interface, hence public
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java
index a599933..160581c 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/StringUtils.java
@@ -17,9 +17,6 @@
 package com.android.inputmethod.latin;
 
 import android.text.TextUtils;
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.keyboard.Keyboard;
 
 import java.util.ArrayList;
 import java.util.Locale;
@@ -29,39 +26,38 @@
         // This utility class is not publicly instantiable.
     }
 
-    public static boolean canBeFollowedByPeriod(final int codePoint) {
-        // TODO: Check again whether there really ain't a better way to check this.
-        // TODO: This should probably be language-dependant...
-        return Character.isLetterOrDigit(codePoint)
-                || codePoint == Keyboard.CODE_SINGLE_QUOTE
-                || codePoint == Keyboard.CODE_DOUBLE_QUOTE
-                || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS
-                || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET
-                || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET
-                || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
-    }
-
     public static int codePointCount(String text) {
         if (TextUtils.isEmpty(text)) return 0;
         return text.codePointCount(0, text.length());
     }
 
-    private static boolean containsInCsv(String key, String csv) {
-        if (csv == null)
-            return false;
-        for (String option : csv.split(",")) {
-            if (option.equals(key))
-                return true;
+    public static boolean containsInArray(String key, String[] array) {
+        for (final String element : array) {
+            if (key.equals(element)) return true;
         }
         return false;
     }
 
-    public static boolean inPrivateImeOptions(String packageName, String key,
-            EditorInfo editorInfo) {
-        if (editorInfo == null)
-            return false;
-        return containsInCsv(packageName != null ? packageName + "." + key : key,
-                editorInfo.privateImeOptions);
+    public static boolean containsInCsv(String key, String csv) {
+        if (TextUtils.isEmpty(csv)) return false;
+        return containsInArray(key, csv.split(","));
+    }
+
+    public static String appendToCsvIfNotExists(String key, String csv) {
+        if (TextUtils.isEmpty(csv)) return key;
+        if (containsInCsv(key, csv)) return csv;
+        return csv + "," + key;
+    }
+
+    public static String removeFromCsvIfExists(String key, String csv) {
+        if (TextUtils.isEmpty(csv)) return "";
+        final String[] elements = csv.split(",");
+        if (!containsInArray(key, elements)) return csv;
+        final ArrayList<String> result = new ArrayList<String>(elements.length - 1);
+        for (final String element : elements) {
+            if (!key.equals(element)) result.add(element);
+        }
+        return TextUtils.join(",", result);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
index 37f46fc..fc61932 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.view.inputmethod.InputMethodSubtype;
@@ -24,6 +26,8 @@
 import java.util.Locale;
 
 public class SubtypeLocale {
+    private static final String TAG = SubtypeLocale.class.getSimpleName();
+
     // Special language code to represent "no language".
     public static final String NO_LANGUAGE = "zz";
 
@@ -56,26 +60,29 @@
     //  zz    qwerty F      QWERTY    QWERTY
     //  fr    qwertz T  Fr  Français  Français (QWERTZ)
     //  de    qwerty T  De  Deutsch   Deutsch (QWERTY)
-    //  en    azerty T  En  English   English (AZERTY)
+    //  en_US azerty T  En  English   English (US) (AZERTY)
     //  zz    azerty T      AZERTY    AZERTY
 
     // Get InputMethodSubtype's full display name in its locale.
     public static String getFullDisplayName(InputMethodSubtype subtype) {
-        final String value = sExceptionalDisplayNamesMap.get(subtype.getLocale());
-        if (value != null) {
-            return value;
-        }
-
         if (isNoLanguage(subtype)) {
             return getKeyboardLayoutSetDisplayName(subtype);
         }
 
+        final String exceptionalValue = sExceptionalDisplayNamesMap.get(subtype.getLocale());
+
         final Locale locale = getSubtypeLocale(subtype);
-        final String language = StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale);
         if (AdditionalSubtype.isAdditionalSubtype(subtype)) {
-            return String.format("%s (%s)",
-                    language, getKeyboardLayoutSetDisplayName(subtype));
+            final String language = (exceptionalValue != null) ? exceptionalValue
+                    : StringUtils.toTitleCase(locale.getDisplayLanguage(locale), locale);
+            final String layout = getKeyboardLayoutSetDisplayName(subtype);
+            return String.format("%s (%s)", language, layout);
         }
+
+        if (exceptionalValue != null) {
+            return exceptionalValue;
+        }
+
         return StringUtils.toTitleCase(locale.getDisplayName(locale), locale);
     }
 
@@ -112,11 +119,14 @@
     }
 
     public static String getKeyboardLayoutSetName(InputMethodSubtype subtype) {
-        final String keyboardLayoutSet = subtype.getExtraValueOf(
-                LatinIME.SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET);
+        final String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET);
         // TODO: Remove this null check when InputMethodManager.getCurrentInputMethodSubtype is
         // fixed.
-        if (keyboardLayoutSet == null) return AdditionalSubtype.QWERTY;
+        if (keyboardLayoutSet == null) {
+            android.util.Log.w(TAG, "KeyboardLayoutSet not found, use QWERTY: " +
+                    "locale=" + subtype.getLocale() + " extraValue=" + subtype.getExtraValue());
+            return AdditionalSubtype.QWERTY;
+        }
         return keyboardLayoutSet;
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index cf95a7e..3b9a406 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -16,16 +16,16 @@
 
 package com.android.inputmethod.latin;
 
+import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY;
+
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.os.AsyncTask;
 import android.os.IBinder;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -33,7 +33,6 @@
 
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -42,41 +41,42 @@
     private static boolean DBG = LatinImeLogger.sDBG;
     private static final String TAG = SubtypeSwitcher.class.getSimpleName();
 
-    public static final String KEYBOARD_MODE = "keyboard";
-    private static final char LOCALE_SEPARATOR = '_';
-    private static final String SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY =
-            "requireNetworkConnectivity";
-
-    private final TextUtils.SimpleStringSplitter mLocaleSplitter =
-            new TextUtils.SimpleStringSplitter(LOCALE_SEPARATOR);
-
     private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
     private /* final */ LatinIME mService;
     private /* final */ InputMethodManager mImm;
     private /* final */ Resources mResources;
     private /* final */ ConnectivityManager mConnectivityManager;
-    private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod =
-            new ArrayList<InputMethodSubtype>();
-    private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
 
     /*-----------------------------------------------------------*/
     // Variants which should be changed only by reload functions.
-    private boolean mNeedsToDisplayLanguage;
-    private boolean mIsDictionaryAvailable;
-    private boolean mIsSystemLanguageSameAsInputLanguage;
+    private NeedsToDisplayLanguage mNeedsToDisplayLanguage = new NeedsToDisplayLanguage();
     private InputMethodInfo mShortcutInputMethodInfo;
     private InputMethodSubtype mShortcutSubtype;
-    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
     private InputMethodSubtype mNoLanguageSubtype;
     // Note: This variable is always non-null after {@link #initialize(LatinIME)}.
     private InputMethodSubtype mCurrentSubtype;
-    private Locale mSystemLocale;
-    private Locale mInputLocale;
-    private String mInputLocaleStr;
+    private Locale mCurrentSystemLocale;
     /*-----------------------------------------------------------*/
 
     private boolean mIsNetworkConnected;
 
+    static class NeedsToDisplayLanguage {
+        private int mEnabledSubtypeCount;
+        private boolean mIsSystemLanguageSameAsInputLanguage;
+
+        public boolean getValue() {
+            return mEnabledSubtypeCount >= 2 || !mIsSystemLanguageSameAsInputLanguage;
+        }
+
+        public void updateEnabledSubtypeCount(int count) {
+            mEnabledSubtypeCount = count;
+        }
+
+        public void updateIsSystemLanguageSameAsInputLanguage(boolean isSame) {
+            mIsSystemLanguageSameAsInputLanguage = isSame;
+        }
+    }
+
     public static SubtypeSwitcher getInstance() {
         return sInstance;
     }
@@ -97,13 +97,8 @@
         mImm = ImfUtils.getInputMethodManager(service);
         mConnectivityManager = (ConnectivityManager) service.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
-        mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
-        mEnabledLanguagesOfCurrentInputMethod.clear();
-        mSystemLocale = null;
-        mInputLocale = null;
-        mInputLocaleStr = null;
+        mCurrentSystemLocale = mResources.getConfiguration().locale;
         mCurrentSubtype = mImm.getCurrentInputMethodSubtype();
-        mAllEnabledSubtypesOfCurrentInputMethod = null;
         mNoLanguageSubtype = ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
                 service, SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.QWERTY);
 
@@ -114,7 +109,7 @@
     // Update all parameters stored in SubtypeSwitcher.
     // Only configuration changed event is allowed to call this because this is heavy.
     private void updateAllParameters() {
-        mSystemLocale = mResources.getConfiguration().locale;
+        mCurrentSystemLocale = mResources.getConfiguration().locale;
         updateSubtype(mImm.getCurrentInputMethodSubtype());
         updateParametersOnStartInputView();
     }
@@ -128,31 +123,20 @@
 
     // Reload enabledSubtypes from the framework.
     private void updateEnabledSubtypes() {
-        final String currentMode = mCurrentSubtype.getMode();
+        final InputMethodSubtype currentSubtype = mCurrentSubtype;
         boolean foundCurrentSubtypeBecameDisabled = true;
-        mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
-                null, true);
-        mEnabledLanguagesOfCurrentInputMethod.clear();
-        mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
-        for (InputMethodSubtype ims : mAllEnabledSubtypesOfCurrentInputMethod) {
-            final String locale = ims.getLocale();
-            final String mode = ims.getMode();
-            mLocaleSplitter.setString(locale);
-            if (mLocaleSplitter.hasNext()) {
-                mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next());
-            }
-            if (locale.equals(mInputLocaleStr) && mode.equals(currentMode)) {
+        final List<InputMethodSubtype> enabledSubtypesOfThisIme =
+                mImm.getEnabledInputMethodSubtypeList(null, true);
+        for (InputMethodSubtype ims : enabledSubtypesOfThisIme) {
+            if (ims.equals(currentSubtype)) {
                 foundCurrentSubtypeBecameDisabled = false;
             }
-            if (KEYBOARD_MODE.equals(ims.getMode())) {
-                mEnabledKeyboardSubtypesOfCurrentInputMethod.add(ims);
-            }
         }
-        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
-                && mIsSystemLanguageSameAsInputLanguage);
+        mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size());
         if (foundCurrentSubtypeBecameDisabled) {
             if (DBG) {
-                Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + currentMode);
+                Log.w(TAG, "Last subtype: "
+                        + currentSubtype.getLocale() + "/" + currentSubtype.getExtraValue());
                 Log.w(TAG, "Last subtype was disabled. Update to the current one.");
             }
             updateSubtype(mImm.getCurrentInputMethodSubtype());
@@ -193,70 +177,20 @@
 
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
     public void updateSubtype(InputMethodSubtype newSubtype) {
-        final String newLocale = newSubtype.getLocale();
-        final String newMode = newSubtype.getMode();
-        final String oldMode = mCurrentSubtype.getMode();
         if (DBG) {
-            Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode
-                    + ", from: " + mInputLocaleStr + ", " + oldMode);
+            Log.w(TAG, "onCurrentInputMethodSubtypeChanged: to: "
+                    + newSubtype.getLocale() + "/" + newSubtype.getExtraValue() + ", from: "
+                    + mCurrentSubtype.getLocale() + "/" + mCurrentSubtype.getExtraValue());
         }
-        boolean languageChanged = false;
-        if (!newLocale.equals(mInputLocaleStr)) {
-            if (mInputLocaleStr != null) {
-                languageChanged = true;
-            }
-            updateInputLocale(newLocale);
-        }
-        boolean modeChanged = false;
-        if (!newMode.equals(oldMode)) {
-            if (oldMode != null) {
-                modeChanged = true;
-            }
-        }
+        if (newSubtype.equals(mCurrentSubtype)) return;
+
+        final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype);
+        mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage(
+                mCurrentSystemLocale.equals(newLocale));
+
         mCurrentSubtype = newSubtype;
-
-        if (KEYBOARD_MODE.equals(mCurrentSubtype.getMode())) {
-            if (modeChanged || languageChanged) {
-                updateShortcutIME();
-                mService.onRefreshKeyboard();
-            }
-        } else {
-            final String packageName = mService.getPackageName();
-            int version = -1;
-            try {
-                version = mService.getPackageManager().getPackageInfo(
-                        packageName, 0).versionCode;
-            } catch (NameNotFoundException e) {
-            }
-            Log.w(TAG, "Unknown subtype mode: " + newMode + "," + version + ", " + packageName
-                    + ". IME is already changed to other IME.");
-            Log.w(TAG, "Subtype mode:" + newSubtype.getMode());
-            Log.w(TAG, "Subtype locale:" + newSubtype.getLocale());
-            Log.w(TAG, "Subtype extra value:" + newSubtype.getExtraValue());
-            Log.w(TAG, "Subtype is auxiliary:" + newSubtype.isAuxiliary());
-        }
-    }
-
-    // Update the current input locale from Locale string.
-    private void updateInputLocale(String inputLocaleStr) {
-        // example: inputLocaleStr = "en_US" "en" ""
-        // "en_US" --> language: en  & country: US
-        // "en" --> language: en
-        // "" --> the system locale
-        if (!TextUtils.isEmpty(inputLocaleStr)) {
-            mInputLocale = LocaleUtils.constructLocaleFromString(inputLocaleStr);
-            mInputLocaleStr = inputLocaleStr;
-        } else {
-            mInputLocale = mSystemLocale;
-            String country = mSystemLocale.getCountry();
-            mInputLocaleStr = mSystemLocale.getLanguage()
-                    + (TextUtils.isEmpty(country) ? "" : "_" + mSystemLocale.getLanguage());
-        }
-        mIsSystemLanguageSameAsInputLanguage = getSystemLocale().getLanguage().equalsIgnoreCase(
-                getInputLocale().getLanguage());
-        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
-                && mIsSystemLanguageSameAsInputLanguage);
-        mIsDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(mService, mInputLocale);
+        updateShortcutIME();
+        mService.onRefreshKeyboard();
     }
 
     ////////////////////////////
@@ -309,8 +243,7 @@
             return false;
         if (mShortcutSubtype == null)
             return true;
-        if (mShortcutSubtype.containsExtraValueKey(
-                SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) {
+        if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) {
             return mIsNetworkConnected;
         }
         return true;
@@ -325,62 +258,31 @@
     }
 
     //////////////////////////////////
-    // Language Switching functions //
+    // Subtype Switching functions //
     //////////////////////////////////
 
-    public int getEnabledKeyboardLocaleCount() {
-        return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
-    }
-
     public boolean needsToDisplayLanguage(Locale keyboardLocale) {
         if (keyboardLocale.toString().equals(SubtypeLocale.NO_LANGUAGE)) {
             return true;
         }
-        if (!keyboardLocale.equals(mInputLocale)) {
+        if (!keyboardLocale.equals(getCurrentSubtypeLocale())) {
             return false;
         }
-        return mNeedsToDisplayLanguage;
+        return mNeedsToDisplayLanguage.getValue();
     }
 
-    public Locale getInputLocale() {
-        return mInputLocale;
-    }
-
-    public String getInputLocaleStr() {
-        return mInputLocaleStr;
-    }
-
-    public String[] getEnabledLanguages() {
-        int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size();
-        // Workaround for explicitly specifying the voice language
-        if (enabledLanguageCount == 1) {
-            mEnabledLanguagesOfCurrentInputMethod.add(mEnabledLanguagesOfCurrentInputMethod
-                    .get(0));
-            ++enabledLanguageCount;
-        }
-        return mEnabledLanguagesOfCurrentInputMethod.toArray(new String[enabledLanguageCount]);
-    }
-
-    public Locale getSystemLocale() {
-        return mSystemLocale;
-    }
-
-    public boolean isSystemLanguageSameAsInputLanguage() {
-        return mIsSystemLanguageSameAsInputLanguage;
+    public Locale getCurrentSubtypeLocale() {
+        return SubtypeLocale.getSubtypeLocale(mCurrentSubtype);
     }
 
     public void onConfigurationChanged(Configuration conf) {
         final Locale systemLocale = conf.locale;
         // If system configuration was changed, update all parameters.
-        if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) {
+        if (!systemLocale.equals(mCurrentSystemLocale)) {
             updateAllParameters();
         }
     }
 
-    public boolean isDictionaryAvailable() {
-        return mIsDictionaryAvailable;
-    }
-
     public InputMethodSubtype getCurrentSubtype() {
         return mCurrentSubtype;
     }
diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
new file mode 100644
index 0000000..8a5a822
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
@@ -0,0 +1,91 @@
+/*
+ * 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.test.AndroidTestCase;
+
+public class StringUtilsTests extends AndroidTestCase {
+    public void testContainsInArray() {
+        assertFalse("empty array", StringUtils.containsInArray("key", new String[0]));
+        assertFalse("not in 1 element", StringUtils.containsInArray("key", new String[] {
+                "key1"
+        }));
+        assertFalse("not in 2 elements", StringUtils.containsInArray("key", new String[] {
+                "key1", "key2"
+        }));
+
+        assertTrue("in 1 element", StringUtils.containsInArray("key", new String[] {
+                "key"
+        }));
+        assertTrue("in 2 elements", StringUtils.containsInArray("key", new String[] {
+                "key1", "key"
+        }));
+    }
+
+    public void testContainsInCsv() {
+        assertFalse("null", StringUtils.containsInCsv("key", null));
+        assertFalse("empty", StringUtils.containsInCsv("key", ""));
+        assertFalse("not in 1 element", StringUtils.containsInCsv("key", "key1"));
+        assertFalse("not in 2 elements", StringUtils.containsInCsv("key", "key1,key2"));
+
+        assertTrue("in 1 element", StringUtils.containsInCsv("key", "key"));
+        assertTrue("in 2 elements", StringUtils.containsInCsv("key", "key1,key"));
+    }
+
+    public void testAppendToCsvIfNotExists() {
+        assertEquals("null", "key", StringUtils.appendToCsvIfNotExists("key", null));
+        assertEquals("empty", "key", StringUtils.appendToCsvIfNotExists("key", ""));
+
+        assertEquals("not in 1 element", "key1,key",
+                StringUtils.appendToCsvIfNotExists("key", "key1"));
+        assertEquals("not in 2 elements", "key1,key2,key",
+                StringUtils.appendToCsvIfNotExists("key", "key1,key2"));
+
+        assertEquals("in 1 element", "key",
+                StringUtils.appendToCsvIfNotExists("key", "key"));
+        assertEquals("in 2 elements at position 1", "key,key2",
+                StringUtils.appendToCsvIfNotExists("key", "key,key2"));
+        assertEquals("in 2 elements at position 2", "key1,key",
+                StringUtils.appendToCsvIfNotExists("key", "key1,key"));
+        assertEquals("in 3 elements at position 2", "key1,key,key3",
+                StringUtils.appendToCsvIfNotExists("key", "key1,key,key3"));
+    }
+
+    public void testRemoveFromCsvIfExists() {
+        assertEquals("null", "", StringUtils.removeFromCsvIfExists("key", null));
+        assertEquals("empty", "", StringUtils.removeFromCsvIfExists("key", ""));
+
+        assertEquals("not in 1 element", "key1",
+                StringUtils.removeFromCsvIfExists("key", "key1"));
+        assertEquals("not in 2 elements", "key1,key2",
+                StringUtils.removeFromCsvIfExists("key", "key1,key2"));
+
+        assertEquals("in 1 element", "",
+                StringUtils.removeFromCsvIfExists("key", "key"));
+        assertEquals("in 2 elements at position 1", "key2",
+                StringUtils.removeFromCsvIfExists("key", "key,key2"));
+        assertEquals("in 2 elements at position 2", "key1",
+                StringUtils.removeFromCsvIfExists("key", "key1,key"));
+        assertEquals("in 3 elements at position 2", "key1,key3",
+                StringUtils.removeFromCsvIfExists("key", "key1,key,key3"));
+
+        assertEquals("in 3 elements at position 1,2,3", "",
+                StringUtils.removeFromCsvIfExists("key", "key,key,key"));
+        assertEquals("in 5 elements at position 2,4", "key1,key3,key5",
+                StringUtils.removeFromCsvIfExists("key", "key1,key,key3,key,key5"));
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
index 12711c1..b294770 100644
--- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
+++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
@@ -110,6 +110,7 @@
     //  zz    qwerty F      QWERTY    QWERTY
     //  fr    qwertz T  Fr  Français  Français (QWERTZ)
     //  de    qwerty T  De  Deutsch   Deutsch (QWERTY)
+    //  en_US azerty T  En  English   English (US) (AZERTY)
     //  zz    azerty T      AZERTY    AZERTY
 
     public void testSampleSubtypes() {
@@ -165,32 +166,36 @@
 
     public void testAdditionalSubtype() {
         final InputMethodSubtype DE_QWERTY = AdditionalSubtype.createAdditionalSubtype(
-                Locale.GERMAN.toString(), AdditionalSubtype.QWERTY);
+                Locale.GERMAN.toString(), AdditionalSubtype.QWERTY, null);
         final InputMethodSubtype FR_QWERTZ = AdditionalSubtype.createAdditionalSubtype(
-                Locale.FRENCH.toString(), AdditionalSubtype.QWERTZ);
-        final InputMethodSubtype EN_AZERTY = AdditionalSubtype.createAdditionalSubtype(
-                Locale.ENGLISH.toString(), AdditionalSubtype.AZERTY);
+                Locale.FRENCH.toString(), AdditionalSubtype.QWERTZ, null);
+        final InputMethodSubtype US_AZERTY = AdditionalSubtype.createAdditionalSubtype(
+                Locale.US.toString(), AdditionalSubtype.AZERTY, null);
         final InputMethodSubtype ZZ_AZERTY = AdditionalSubtype.createAdditionalSubtype(
-                SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.AZERTY);
+                SubtypeLocale.NO_LANGUAGE, AdditionalSubtype.AZERTY, null);
 
         assertTrue(AdditionalSubtype.isAdditionalSubtype(FR_QWERTZ));
         assertTrue(AdditionalSubtype.isAdditionalSubtype(DE_QWERTY));
-        assertTrue(AdditionalSubtype.isAdditionalSubtype(EN_AZERTY));
+        assertTrue(AdditionalSubtype.isAdditionalSubtype(US_AZERTY));
         assertTrue(AdditionalSubtype.isAdditionalSubtype(ZZ_AZERTY));
 
-        assertEquals("fr qwertz", "Français (QWERTZ)", SubtypeLocale.getFullDisplayName(FR_QWERTZ));
-        assertEquals("de qwerty", "Deutsch (QWERTY)",  SubtypeLocale.getFullDisplayName(DE_QWERTY));
-        assertEquals("en azerty", "English (AZERTY)",  SubtypeLocale.getFullDisplayName(EN_AZERTY));
-        assertEquals("zz azerty", "AZERTY",            SubtypeLocale.getFullDisplayName(ZZ_AZERTY));
+        assertEquals("fr qwertz",    "Français (QWERTZ)",
+                SubtypeLocale.getFullDisplayName(FR_QWERTZ));
+        assertEquals("de qwerty",    "Deutsch (QWERTY)",
+                SubtypeLocale.getFullDisplayName(DE_QWERTY));
+        assertEquals("en_US azerty", "English (US) (AZERTY)",
+                SubtypeLocale.getFullDisplayName(US_AZERTY));
+        assertEquals("zz azerty",    "AZERTY",
+                SubtypeLocale.getFullDisplayName(ZZ_AZERTY));
 
-        assertEquals("fr qwertz", "Français", SubtypeLocale.getMiddleDisplayName(FR_QWERTZ));
-        assertEquals("de qwerty", "Deutsch",  SubtypeLocale.getMiddleDisplayName(DE_QWERTY));
-        assertEquals("en azerty", "English",  SubtypeLocale.getMiddleDisplayName(EN_AZERTY));
-        assertEquals("zz azerty", "AZERTY",   SubtypeLocale.getMiddleDisplayName(ZZ_AZERTY));
+        assertEquals("fr qwertz",    "Français", SubtypeLocale.getMiddleDisplayName(FR_QWERTZ));
+        assertEquals("de qwerty",    "Deutsch",  SubtypeLocale.getMiddleDisplayName(DE_QWERTY));
+        assertEquals("en_US azerty", "English",  SubtypeLocale.getMiddleDisplayName(US_AZERTY));
+        assertEquals("zz azerty",    "AZERTY",   SubtypeLocale.getMiddleDisplayName(ZZ_AZERTY));
 
-        assertEquals("fr qwertz", "Fr", SubtypeLocale.getShortDisplayName(FR_QWERTZ));
-        assertEquals("de qwerty", "De", SubtypeLocale.getShortDisplayName(DE_QWERTY));
-        assertEquals("en azerty", "En", SubtypeLocale.getShortDisplayName(EN_AZERTY));
-        assertEquals("zz azerty", "", SubtypeLocale.getShortDisplayName(ZZ_AZERTY));
+        assertEquals("fr qwertz",    "Fr", SubtypeLocale.getShortDisplayName(FR_QWERTZ));
+        assertEquals("de qwerty",    "De", SubtypeLocale.getShortDisplayName(DE_QWERTY));
+        assertEquals("en_US azerty", "En", SubtypeLocale.getShortDisplayName(US_AZERTY));
+        assertEquals("zz azerty",    "", SubtypeLocale.getShortDisplayName(ZZ_AZERTY));
     }
 }
diff --git a/tools/makelabel/res/values-en/donottranslate-more-keys.xml b/tools/makelabel/res/values-en/donottranslate-more-keys.xml
index 6e43e86..969a504 100644
--- a/tools/makelabel/res/values-en/donottranslate-more-keys.xml
+++ b/tools/makelabel/res/values-en/donottranslate-more-keys.xml
@@ -32,7 +32,7 @@
          U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
          U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
          U+0113: "ē" LATIN SMALL LETTER E WITH MACRON -->
-    <string name="more_keys_for_e">&#x00E8;,&#x00E9;,&#x00EA;,&#x00EB;,&#x0103;</string>
+    <string name="more_keys_for_e">&#x00E8;,&#x00E9;,&#x00EA;,&#x00EB;,&#x0113;</string>
     <!-- U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
          U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
          U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
@@ -47,7 +47,7 @@
          U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
          U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
          U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE -->
-    <string name="more_keys_for_o">&#x00F4;,&#x00F6;,&#x00F2;,&#x00F3;,&#x0153;,&#x00F8;&#x014D;,&#x00F5;</string>
+    <string name="more_keys_for_o">&#x00F4;,&#x00F6;,&#x00F2;,&#x00F3;,&#x0153;,&#x00F8;,&#x014D;,&#x00F5;</string>
     <!-- U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
          U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
          U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
diff --git a/tools/makelabel/res/values/donottranslate-more-keys.xml b/tools/makelabel/res/values/donottranslate-more-keys.xml
index 7878757..b594f36 100644
--- a/tools/makelabel/res/values/donottranslate-more-keys.xml
+++ b/tools/makelabel/res/values/donottranslate-more-keys.xml
@@ -78,6 +78,33 @@
     <string name="more_keys_for_smiley">"!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ "</string>
     <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,\\,,\?,\@,&amp;,\\%,+,;,/,(,)"</string>
     <string name="keyhintlabel_for_punctuation"></string>
+    <!-- U+2020: "†" DAGGER
+         U+2021: "‡" DOUBLE DAGGER
+         U+2605: "★" BLACK STAR -->
+    <string name="more_keys_for_star">&#x2020;,&#x2021;,&#x2605;</string>
+    <!-- U+00B1: "±" PLUS-MINUS SIGN -->
+    <string name="more_keys_for_plus">&#x00B1;</string>
+    <!-- The all letters need to be mirrored are found at
+         http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
+    <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!3,&lt;,{,[</string>
+    <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!3,&gt;,},]</string>
+    <!-- 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 -->
+    <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="keylabel_for_popular_domain">".com"</string>
     <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
     <string name="more_keys_for_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string>
@@ -126,12 +153,8 @@
     <!-- U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
          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|!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|!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>
@@ -157,33 +180,11 @@
          U+2666: "♦" BLACK DIAMOND SUIT
          U+2663: "♣" BLACK CLUB SUIT -->
     <string name="more_keys_for_bullet">&#x266A;,&#x2665;,&#x2660;,&#x2666;,&#x2663;</string>
-    <!-- U+2020: "†" DAGGER
-         U+2021: "‡" DOUBLE DAGGER
-         U+2605: "★" BLACK STAR -->
-    <string name="more_keys_for_star">&#x2020;,&#x2021;,&#x2605;</string>
-    <!-- U+00B1: "±" PLUS-MINUS SIGN -->
-    <string name="more_keys_for_plus">&#x00B1;</string>
-    <!-- The all letters need to be mirrored are found at
-         http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
-    <string name="more_keys_for_left_parenthesis">!fixedColumnOrder!3,&lt;,{,[</string>
-    <string name="more_keys_for_right_parenthesis">!fixedColumnOrder!3,&gt;,},]</string>
-    <!-- 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 -->
-    <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_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string>
+    <string name="settings_as_more_key">!icon/settingsKey|!code/key_settings</string>
+    <string name="shortcut_as_more_key">!icon/shortcutKey|!code/key_shortcut</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>
     <!-- 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! -->
diff --git a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java
index afb1aa7..764421f 100644
--- a/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java
+++ b/tools/makelabel/src/com/android/inputmethod/latin/makelabel/StringResourceMap.java
@@ -92,6 +92,9 @@
         @Override
         public void comment(char[] ch, int start, int length) {
             mComment.append(ch, start, length);
+            if (ch[start + length - 1] != '\n') {
+                mComment.append('\n');
+            }
         }
 
         @Override