Merge "Initial step to support version 4 format in native code."
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 9fa68f3..42f60a4 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -161,7 +161,7 @@
     <string name="save" msgid="7646738597196767214">"አስቀምጥ"</string>
     <string name="subtype_locale" msgid="8576443440738143764">"ቋንቋ"</string>
     <string name="keyboard_layout_set" msgid="4309233698194565609">"አቀማመጥ"</string>
-    <string name="custom_input_style_note_message" msgid="8826731320846363423">"የተበጀው የግብዓት ቅጥህን ከመጠቀምህ በፊት መንቃት አለበት። አሁን ማንቃት ትፈልጋለህ?"</string>
+    <string name="custom_input_style_note_message" msgid="8826731320846363423">"የተበጀው የእርስዎን ግብዓት ቅጥ ከመጠቀምዎ በፊት መንቃት አለበት። አሁን ማንቃት ይፈልጋሉ?"</string>
     <string name="enable" msgid="5031294444630523247">"አንቃ"</string>
     <string name="not_now" msgid="6172462888202790482">"አሁን አልፈልግም"</string>
     <string name="custom_input_style_already_exists" msgid="8008728952215449707">"ተመሳሳዩ የግብዓት ቅጥ አስቀድሞ አለ፦ <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 28d82ae..ac51926 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -84,7 +84,7 @@
     <string name="spoken_use_headphones" msgid="896961781287283493">"Schließen Sie ein Headset an, um das Passwort gesprochen zu hören."</string>
     <string name="spoken_current_text_is" msgid="2485723011272583845">"Aktueller Text lautet %s"</string>
     <string name="spoken_no_text_entered" msgid="7479685225597344496">"Kein Text eingegeben"</string>
-    <string name="spoken_auto_correct" msgid="8005997889020109763">"Mit <xliff:g id="KEY">%1$s</xliff:g> wird <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> in <xliff:g id="CORRECTED">%3$s</xliff:g> korrigiert."</string>
+    <string name="spoken_auto_correct" msgid="8005997889020109763">"Mit <xliff:g id="KEY">%1$s</xliff:g> wird <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> zu <xliff:g id="CORRECTED">%3$s</xliff:g> korrigiert."</string>
     <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"Mit <xliff:g id="KEY">%1$s</xliff:g> erfolgt eine Autokorrektur."</string>
     <string name="spoken_description_unknown" msgid="3197434010402179157">"Tastencode %d"</string>
     <string name="spoken_description_shift" msgid="244197883292549308">"Umschalttaste"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index 1a07772..71fce94 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -85,7 +85,7 @@
     <string name="spoken_current_text_is" msgid="2485723011272583845">"A jelenlegi szöveg: %s"</string>
     <string name="spoken_no_text_entered" msgid="7479685225597344496">"Szöveg nincs megadva"</string>
     <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> billentyű: <xliff:g id="CORRECTED">%3$s</xliff:g> szóra javítja a következőt: <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>"</string>
-    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> billentyű: automatikus javítás"</string>
+    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> billentyű automatikus javítást végez"</string>
     <string name="spoken_description_unknown" msgid="3197434010402179157">"Billentyűkód: %d"</string>
     <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
     <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift be van kapcsolva (érintse meg a kikapcsoláshoz)"</string>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index c2cdeac..79a0b2c 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -85,7 +85,7 @@
     <string name="spoken_current_text_is" msgid="2485723011272583845">"អត្ថបទ​បច្ចុប្បន្ន​គឺ %s"</string>
     <string name="spoken_no_text_entered" msgid="7479685225597344496">"គ្មាន​អត្ថបទ​​​បាន​បញ្ចូល"</string>
     <string name="spoken_auto_correct" msgid="8005997889020109763">"<xliff:g id="KEY">%1$s</xliff:g> កែ <xliff:g id="ORIGINAL_WORD">%2$s</xliff:g> ទៅ <xliff:g id="CORRECTED">%3$s</xliff:g>"</string>
-    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> អនុវត្តការ​កែ​ដោយស្វ័យប្រវត្តិ"</string>
+    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"<xliff:g id="KEY">%1$s</xliff:g> អនុវត្ត​ការ​កែ​ដោយស្វ័យប្រវត្តិ"</string>
     <string name="spoken_description_unknown" msgid="3197434010402179157">"កូដ​គ្រាប់​ចុច %d"</string>
     <string name="spoken_description_shift" msgid="244197883292549308">"Shift"</string>
     <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"បើក Shift (​ប៉ះ​ដើម្បី​បិទ)"</string>
diff --git a/java/res/values-sw600dp-land/config.xml b/java/res/values-sw540dp-land/config.xml
similarity index 100%
rename from java/res/values-sw600dp-land/config.xml
rename to java/res/values-sw540dp-land/config.xml
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw540dp-land/dimens.xml
similarity index 100%
rename from java/res/values-sw600dp-land/dimens.xml
rename to java/res/values-sw540dp-land/dimens.xml
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw540dp/config.xml
similarity index 100%
rename from java/res/values-sw600dp/config.xml
rename to java/res/values-sw540dp/config.xml
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw540dp/dimens.xml
similarity index 100%
rename from java/res/values-sw600dp/dimens.xml
rename to java/res/values-sw540dp/dimens.xml
diff --git a/java/res/values-sw600dp/touch-position-correction.xml b/java/res/values-sw540dp/touch-position-correction.xml
similarity index 100%
rename from java/res/values-sw600dp/touch-position-correction.xml
rename to java/res/values-sw540dp/touch-position-correction.xml
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index 17aef4b..1d4f36a 100644
--- a/java/res/values-zh-rHK/strings.xml
+++ b/java/res/values-zh-rHK/strings.xml
@@ -84,8 +84,8 @@
     <string name="spoken_use_headphones" msgid="896961781287283493">"插上耳機即可聽到系統朗讀密碼鍵。"</string>
     <string name="spoken_current_text_is" msgid="2485723011272583845">"目前文字為 %s"</string>
     <string name="spoken_no_text_entered" msgid="7479685225597344496">"未輸入文字"</string>
-    <string name="spoken_auto_correct" msgid="8005997889020109763">"按下「<xliff:g id="KEY">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED">%3$s</xliff:g>」"</string>
-    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"按下「<xliff:g id="KEY">%1$s</xliff:g>」可自動修正"</string>
+    <string name="spoken_auto_correct" msgid="8005997889020109763">"按「<xliff:g id="KEY">%1$s</xliff:g>」可將「<xliff:g id="ORIGINAL_WORD">%2$s</xliff:g>」修正為「<xliff:g id="CORRECTED">%3$s</xliff:g>」"</string>
+    <string name="spoken_auto_correct_obscured" msgid="6276420476908833791">"按「<xliff:g id="KEY">%1$s</xliff:g>」可自動修正"</string>
     <string name="spoken_description_unknown" msgid="3197434010402179157">"按鍵代碼 %d"</string>
     <string name="spoken_description_shift" msgid="244197883292549308">"Shift 鍵"</string>
     <string name="spoken_description_shift_shifted" msgid="1681877323344195035">"Shift 鍵已開啟 (輕按即可停用)"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 7df5fc5..2774949 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -44,7 +44,7 @@
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"預設"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> 毫秒"</string>
     <string name="settings_system_default" msgid="6268225104743331821">"系統預設"</string>
-    <string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人姓名"</string>
+    <string name="use_contacts_dict" msgid="4435317977804180815">"聯絡人姓名建議"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string>
     <string name="use_double_space_period_summary" msgid="6532892187247952799">"輕按兩下空格鍵可插入句號另加一個空格"</string>
diff --git a/java/res/xml-sw600dp/rows_swiss.xml b/java/res/xml-sw600dp/rows_swiss.xml
new file mode 100644
index 0000000..4f4ca85
--- /dev/null
+++ b/java/res/xml-sw600dp/rows_swiss.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_swiss1" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_swiss2" />
+        <Key
+            latin:keyStyle="enterKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="10.0%p" />
+        <Spacer
+            latin:keyWidth="3.181%p" />
+        <include
+            latin:keyboardLayout="@xml/rowkeys_qwertz3" />
+        <include
+            latin:keyboardLayout="@xml/keys_exclamation_question" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyXPos="-10.0%p"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/kbd_swiss.xml b/java/res/xml/kbd_swiss.xml
new file mode 100644
index 0000000..c64ad11
--- /dev/null
+++ b/java/res/xml/kbd_swiss.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/rows_swiss" />
+</Keyboard>
diff --git a/java/res/xml/keyboard_layout_set_swiss.xml b/java/res/xml/keyboard_layout_set_swiss.xml
new file mode 100644
index 0000000..e17a5ab
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_swiss.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<KeyboardLayoutSet
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+    <Element
+        latin:elementName="alphabet"
+        latin:elementKeyboard="@xml/kbd_swiss"
+        latin:enableProximityCharsCorrection="true" />
+    <Element
+        latin:elementName="symbols"
+        latin:elementKeyboard="@xml/kbd_symbols" />
+    <Element
+        latin:elementName="symbolsShifted"
+        latin:elementKeyboard="@xml/kbd_symbols_shift" />
+    <Element
+        latin:elementName="phone"
+        latin:elementKeyboard="@xml/kbd_phone" />
+    <Element
+        latin:elementName="phoneSymbols"
+        latin:elementKeyboard="@xml/kbd_phone_symbols" />
+    <Element
+        latin:elementName="number"
+        latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index f0e04c2..f11b636 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -32,6 +32,7 @@
     cs: Czech/qwertz
     da: Danish/nordic
     de: German/qwertz
+    de_CH: German Switzerland/swiss
     el: Greek/greek
     en_US: English United States/qwerty
     en_GB: English Great Britain/qwerty
@@ -44,6 +45,7 @@
     fi: Finnish/nordic
     fr: French/azerty
     fr_CA: French Canada/qwerty
+    fr_CH: French Switzerland/swiss
     hi: Hindi/hindi
     hr: Croatian/qwertz
     hu: Hungarian/qwertz
@@ -181,6 +183,13 @@
     />
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
+            android:subtypeId="0x7acfd0aa"
+            android:imeSubtypeLocale="de_CH"
+            android:imeSubtypeMode="keyboard"
+            android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
+    />
+    <subtype android:icon="@drawable/ic_ime_switcher_dark"
+            android:label="@string/subtype_generic"
             android:subtypeId="0x0e7802d3"
             android:imeSubtypeLocale="el"
             android:imeSubtypeMode="keyboard"
@@ -253,6 +262,13 @@
     />
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
+            android:subtypeId="0xeadc55f5"
+            android:imeSubtypeLocale="fr_CH"
+            android:imeSubtypeMode="keyboard"
+            android:imeSubtypeExtraValue="KeyboardLayoutSet=swiss,AsciiCapable,SupportTouchPositionCorrection,EmojiCapable"
+    />
+    <subtype android:icon="@drawable/ic_ime_switcher_dark"
+            android:label="@string/subtype_generic"
             android:subtypeId="0x39753b7f"
             android:imeSubtypeLocale="hi"
             android:imeSubtypeMode="keyboard"
diff --git a/java/res/xml/rowkeys_swiss1.xml b/java/res/xml/rowkeys_swiss1.xml
new file mode 100644
index 0000000..e3b8426
--- /dev/null
+++ b/java/res/xml/rowkeys_swiss1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/rowkeys_qwertz1" />
+    <Key
+        latin:keyLabel="!text/keylabel_for_swiss_row1_11"
+        latin:moreKeys="!text/more_keys_for_swiss_row1_11" />
+</merge>
diff --git a/java/res/xml/rowkeys_swiss2.xml b/java/res/xml/rowkeys_swiss2.xml
new file mode 100644
index 0000000..5364a44
--- /dev/null
+++ b/java/res/xml/rowkeys_swiss2.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/rowkeys_qwerty2" />
+    <Key
+        latin:keyLabel="!text/keylabel_for_swiss_row2_10"
+        latin:moreKeys="!text/more_keys_for_swiss_row2_10" />
+    <Key
+        latin:keyLabel="!text/keylabel_for_swiss_row2_11"
+        latin:moreKeys="!text/more_keys_for_swiss_row2_11" />
+</merge>
diff --git a/java/res/xml/rows_swiss.xml b/java/res/xml/rows_swiss.xml
new file mode 100644
index 0000000..03e4129
--- /dev/null
+++ b/java/res/xml/rows_swiss.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="9.091%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_swiss1" />
+    </Row>
+    <Row
+        latin:keyWidth="9.091%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_swiss2" />
+    </Row>
+    <Row
+        latin:keyWidth="9.2%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:visualInsetsRight="1%p" />
+        <Spacer
+            latin:keyWidth="2.8%p" />
+        <include
+            latin:keyboardLayout="@xml/rowkeys_qwertz3" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyXPos="-15%p"
+            latin:keyWidth="fillRight"
+            latin:visualInsetsLeft="1%p" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
new file mode 100644
index 0000000..b119d6c
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 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.compat;
+
+import android.os.Build;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.lang.reflect.Constructor;
+
+public final class InputMethodSubtypeCompatUtils {
+    private static final String TAG = InputMethodSubtypeCompatUtils.class.getSimpleName();
+    // Note that InputMethodSubtype(int nameId, int iconId, String locale, String mode,
+    // String extraValue, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, int id)
+    // has been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
+    private static final Constructor<?> CONSTRUCTOR_INPUT_METHOD_SUBTYPE =
+            CompatUtils.getConstructor(InputMethodSubtype.class,
+                    Integer.TYPE, Integer.TYPE, String.class, String.class, String.class,
+                    Boolean.TYPE, Boolean.TYPE, Integer.TYPE);
+    static {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
+                android.util.Log.w(TAG, "Warning!!! Constructor is not defined.");
+            }
+        }
+    }
+    private InputMethodSubtypeCompatUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static InputMethodSubtype newInputMethodSubtype(int nameId, int iconId, String locale,
+            String mode, String extraValue, boolean isAuxiliary,
+            boolean overridesImplicitlyEnabledSubtype, int id) {
+        if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null
+                || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return new InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
+                    overridesImplicitlyEnabledSubtype);
+        }
+        return (InputMethodSubtype) CompatUtils.newInstance(CONSTRUCTOR_INPUT_METHOD_SUBTYPE,
+                nameId, iconId, locale, mode, extraValue, isAuxiliary,
+                overridesImplicitlyEnabledSubtype, id);
+    }
+}
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsActivity.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsActivity.java
index c28d729..4366348 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsActivity.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.dictionarypack;
 
+import com.android.inputmethod.latin.utils.FragmentUtils;
+
 import android.content.Intent;
 import android.os.Bundle;
 import android.preference.PreferenceActivity;
@@ -45,6 +47,6 @@
     // TODO: Uncomment the override annotation once we start using SDK version 19.
     // @Override
     public boolean isValidFragment(String fragmentName) {
-        return fragmentName.equals(DEFAULT_FRAGMENT);
+        return FragmentUtils.isValidFragment(fragmentName);
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 9779c68..f123735 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -162,9 +162,11 @@
                 addShownCategoryId(CATEGORY_ID_OBJECTS);
                 addShownCategoryId(CATEGORY_ID_NATURE);
                 addShownCategoryId(CATEGORY_ID_PLACES);
-                mCurrentCategoryId = CATEGORY_ID_PEOPLE;
+                mCurrentCategoryId =
+                        Settings.readLastShownEmojiCategoryId(mPrefs, CATEGORY_ID_PEOPLE);
             } else {
-                mCurrentCategoryId = CATEGORY_ID_SYMBOLS;
+                mCurrentCategoryId =
+                        Settings.readLastShownEmojiCategoryId(mPrefs, CATEGORY_ID_SYMBOLS);
             }
             addShownCategoryId(CATEGORY_ID_SYMBOLS);
             addShownCategoryId(CATEGORY_ID_EMOTICONS);
@@ -222,6 +224,7 @@
 
         public void setCurrentCategoryId(int categoryId) {
             mCurrentCategoryId = categoryId;
+            Settings.writeLastShownEmojiCategoryId(mPrefs, categoryId);
         }
 
         public void setCurrentCategoryPageId(int id) {
@@ -233,7 +236,7 @@
         }
 
         public void saveLastTypedCategoryPage() {
-            Settings.writeEmojiCategoryLastTypedId(
+            Settings.writeLastTypedEmojiCategoryPageId(
                     mPrefs, mCurrentCategoryId, mCurrentCategoryPageId);
         }
 
@@ -254,7 +257,7 @@
         // Returns the view pager's page position for the categoryId
         public int getPageIdFromCategoryId(int categoryId) {
             final int lastSavedCategoryPageId =
-                    Settings.readEmojiCategoryLastTypedId(mPrefs, categoryId);
+                    Settings.readLastTypedEmojiCategoryPageId(mPrefs, categoryId);
             int sum = 0;
             for (int i = 0; i < mShownCategories.size(); ++i) {
                 final CategoryProperties props = mShownCategories.get(i);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 9760983..b7521b9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -155,7 +155,7 @@
     }
 
     public void saveKeyboardState() {
-        if (getKeyboard() != null || isShowingEmojiKeyboard()) {
+        if (getKeyboard() != null || isShowingEmojiPalettes()) {
             mState.onSaveKeyboardState();
         }
     }
@@ -316,19 +316,23 @@
         mState.onCodeInput(code, mLatinIME.getCurrentAutoCapsState());
     }
 
-    public boolean isShowingEmojiKeyboard() {
-        return mEmojiPalettesView != null && mEmojiPalettesView.getVisibility() == View.VISIBLE;
+    private boolean isShowingMainKeyboard() {
+        return null != mKeyboardView && mKeyboardView.isShown();
+    }
+
+    public boolean isShowingEmojiPalettes() {
+        return mEmojiPalettesView != null && mEmojiPalettesView.isShown();
     }
 
     public boolean isShowingMoreKeysPanel() {
-        if (isShowingEmojiKeyboard()) {
+        if (isShowingEmojiPalettes()) {
             return false;
         }
         return mKeyboardView.isShowingMoreKeysPanel();
     }
 
     public View getVisibleKeyboardView() {
-        if (isShowingEmojiKeyboard()) {
+        if (isShowingEmojiPalettes()) {
             return mEmojiPalettesView;
         }
         return mKeyboardView;
@@ -348,6 +352,10 @@
         }
     }
 
+    public boolean isShowingMainKeyboardOrEmojiPalettes() {
+        return isShowingMainKeyboard() || isShowingEmojiPalettes();
+    }
+
     public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) {
         if (mKeyboardView != null) {
             mKeyboardView.closing();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index 09766ac..3133e54 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -184,12 +184,12 @@
 
     private int getKeyY0(final int index) {
         final int row = index / mColumnsNum;
-        return row * mVerticalStep;
+        return row * mVerticalStep + mVerticalGap / 2;
     }
 
     private int getKeyY1(final int index) {
         final int row = index / mColumnsNum + 1;
-        return row * mVerticalStep;
+        return row * mVerticalStep + mVerticalGap / 2;
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index bcb80b4..98515c8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -147,111 +147,117 @@
         /* 42 */ "keylabel_for_south_slavic_row3_8",
         /* 43 */ "more_keys_for_cyrillic_ie",
         /* 44 */ "more_keys_for_cyrillic_i",
-        /* 45 */ "label_to_alpha_key",
-        /* 46 */ "single_quotes",
-        /* 47 */ "double_quotes",
-        /* 48 */ "single_angle_quotes",
-        /* 49 */ "double_angle_quotes",
-        /* 50 */ "more_keys_for_currency_dollar",
-        /* 51 */ "keylabel_for_currency",
-        /* 52 */ "more_keys_for_currency",
-        /* 53 */ "more_keys_for_punctuation",
-        /* 54 */ "more_keys_for_star",
-        /* 55 */ "more_keys_for_bullet",
-        /* 56 */ "more_keys_for_plus",
-        /* 57 */ "more_keys_for_left_parenthesis",
-        /* 58 */ "more_keys_for_right_parenthesis",
-        /* 59 */ "more_keys_for_less_than",
-        /* 60 */ "more_keys_for_greater_than",
-        /* 61 */ "more_keys_for_arabic_diacritics",
-        /* 62 */ "keyhintlabel_for_arabic_diacritics",
-        /* 63 */ "keylabel_for_symbols_1",
-        /* 64 */ "keylabel_for_symbols_2",
-        /* 65 */ "keylabel_for_symbols_3",
-        /* 66 */ "keylabel_for_symbols_4",
-        /* 67 */ "keylabel_for_symbols_5",
-        /* 68 */ "keylabel_for_symbols_6",
-        /* 69 */ "keylabel_for_symbols_7",
-        /* 70 */ "keylabel_for_symbols_8",
-        /* 71 */ "keylabel_for_symbols_9",
-        /* 72 */ "keylabel_for_symbols_0",
-        /* 73 */ "label_to_symbol_key",
-        /* 74 */ "label_to_symbol_with_microphone_key",
-        /* 75 */ "additional_more_keys_for_symbols_1",
-        /* 76 */ "additional_more_keys_for_symbols_2",
-        /* 77 */ "additional_more_keys_for_symbols_3",
-        /* 78 */ "additional_more_keys_for_symbols_4",
-        /* 79 */ "additional_more_keys_for_symbols_5",
-        /* 80 */ "additional_more_keys_for_symbols_6",
-        /* 81 */ "additional_more_keys_for_symbols_7",
-        /* 82 */ "additional_more_keys_for_symbols_8",
-        /* 83 */ "additional_more_keys_for_symbols_9",
-        /* 84 */ "additional_more_keys_for_symbols_0",
-        /* 85 */ "more_keys_for_symbols_1",
-        /* 86 */ "more_keys_for_symbols_2",
-        /* 87 */ "more_keys_for_symbols_3",
-        /* 88 */ "more_keys_for_symbols_4",
-        /* 89 */ "more_keys_for_symbols_5",
-        /* 90 */ "more_keys_for_symbols_6",
-        /* 91 */ "more_keys_for_symbols_7",
-        /* 92 */ "more_keys_for_symbols_8",
-        /* 93 */ "more_keys_for_symbols_9",
-        /* 94 */ "more_keys_for_symbols_0",
-        /* 95 */ "keylabel_for_comma",
-        /* 96 */ "more_keys_for_comma",
-        /* 97 */ "keylabel_for_symbols_question",
-        /* 98 */ "keylabel_for_symbols_semicolon",
-        /* 99 */ "keylabel_for_symbols_percent",
-        /* 100 */ "more_keys_for_symbols_exclamation",
-        /* 101 */ "more_keys_for_symbols_question",
-        /* 102 */ "more_keys_for_symbols_semicolon",
-        /* 103 */ "more_keys_for_symbols_percent",
-        /* 104 */ "keylabel_for_tablet_comma",
-        /* 105 */ "keyhintlabel_for_tablet_comma",
-        /* 106 */ "more_keys_for_tablet_comma",
-        /* 107 */ "keyhintlabel_for_period",
-        /* 108 */ "more_keys_for_period",
-        /* 109 */ "keylabel_for_apostrophe",
-        /* 110 */ "keyhintlabel_for_apostrophe",
-        /* 111 */ "more_keys_for_apostrophe",
-        /* 112 */ "more_keys_for_q",
-        /* 113 */ "more_keys_for_x",
-        /* 114 */ "keylabel_for_q",
-        /* 115 */ "keylabel_for_w",
-        /* 116 */ "keylabel_for_y",
-        /* 117 */ "keylabel_for_x",
-        /* 118 */ "keylabel_for_spanish_row2_10",
-        /* 119 */ "more_keys_for_am_pm",
-        /* 120 */ "settings_as_more_key",
-        /* 121 */ "shortcut_as_more_key",
-        /* 122 */ "action_next_as_more_key",
-        /* 123 */ "action_previous_as_more_key",
-        /* 124 */ "label_to_more_symbol_key",
-        /* 125 */ "label_to_more_symbol_for_tablet_key",
-        /* 126 */ "label_tab_key",
-        /* 127 */ "label_to_phone_numeric_key",
-        /* 128 */ "label_to_phone_symbols_key",
-        /* 129 */ "label_time_am",
-        /* 130 */ "label_time_pm",
-        /* 131 */ "keylabel_for_popular_domain",
-        /* 132 */ "more_keys_for_popular_domain",
-        /* 133 */ "more_keys_for_smiley",
-        /* 134 */ "single_laqm_raqm",
-        /* 135 */ "single_laqm_raqm_rtl",
-        /* 136 */ "single_raqm_laqm",
-        /* 137 */ "double_laqm_raqm",
-        /* 138 */ "double_laqm_raqm_rtl",
-        /* 139 */ "double_raqm_laqm",
-        /* 140 */ "single_lqm_rqm",
-        /* 141 */ "single_9qm_lqm",
-        /* 142 */ "single_9qm_rqm",
-        /* 143 */ "double_lqm_rqm",
-        /* 144 */ "double_9qm_lqm",
-        /* 145 */ "double_9qm_rqm",
-        /* 146 */ "more_keys_for_single_quote",
-        /* 147 */ "more_keys_for_double_quote",
-        /* 148 */ "more_keys_for_tablet_double_quote",
-        /* 149 */ "emoji_key_as_more_key",
+        /* 45 */ "keylabel_for_swiss_row1_11",
+        /* 46 */ "keylabel_for_swiss_row2_10",
+        /* 47 */ "keylabel_for_swiss_row2_11",
+        /* 48 */ "more_keys_for_swiss_row1_11",
+        /* 49 */ "more_keys_for_swiss_row2_10",
+        /* 50 */ "more_keys_for_swiss_row2_11",
+        /* 51 */ "label_to_alpha_key",
+        /* 52 */ "single_quotes",
+        /* 53 */ "double_quotes",
+        /* 54 */ "single_angle_quotes",
+        /* 55 */ "double_angle_quotes",
+        /* 56 */ "more_keys_for_currency_dollar",
+        /* 57 */ "keylabel_for_currency",
+        /* 58 */ "more_keys_for_currency",
+        /* 59 */ "more_keys_for_punctuation",
+        /* 60 */ "more_keys_for_star",
+        /* 61 */ "more_keys_for_bullet",
+        /* 62 */ "more_keys_for_plus",
+        /* 63 */ "more_keys_for_left_parenthesis",
+        /* 64 */ "more_keys_for_right_parenthesis",
+        /* 65 */ "more_keys_for_less_than",
+        /* 66 */ "more_keys_for_greater_than",
+        /* 67 */ "more_keys_for_arabic_diacritics",
+        /* 68 */ "keyhintlabel_for_arabic_diacritics",
+        /* 69 */ "keylabel_for_symbols_1",
+        /* 70 */ "keylabel_for_symbols_2",
+        /* 71 */ "keylabel_for_symbols_3",
+        /* 72 */ "keylabel_for_symbols_4",
+        /* 73 */ "keylabel_for_symbols_5",
+        /* 74 */ "keylabel_for_symbols_6",
+        /* 75 */ "keylabel_for_symbols_7",
+        /* 76 */ "keylabel_for_symbols_8",
+        /* 77 */ "keylabel_for_symbols_9",
+        /* 78 */ "keylabel_for_symbols_0",
+        /* 79 */ "label_to_symbol_key",
+        /* 80 */ "label_to_symbol_with_microphone_key",
+        /* 81 */ "additional_more_keys_for_symbols_1",
+        /* 82 */ "additional_more_keys_for_symbols_2",
+        /* 83 */ "additional_more_keys_for_symbols_3",
+        /* 84 */ "additional_more_keys_for_symbols_4",
+        /* 85 */ "additional_more_keys_for_symbols_5",
+        /* 86 */ "additional_more_keys_for_symbols_6",
+        /* 87 */ "additional_more_keys_for_symbols_7",
+        /* 88 */ "additional_more_keys_for_symbols_8",
+        /* 89 */ "additional_more_keys_for_symbols_9",
+        /* 90 */ "additional_more_keys_for_symbols_0",
+        /* 91 */ "more_keys_for_symbols_1",
+        /* 92 */ "more_keys_for_symbols_2",
+        /* 93 */ "more_keys_for_symbols_3",
+        /* 94 */ "more_keys_for_symbols_4",
+        /* 95 */ "more_keys_for_symbols_5",
+        /* 96 */ "more_keys_for_symbols_6",
+        /* 97 */ "more_keys_for_symbols_7",
+        /* 98 */ "more_keys_for_symbols_8",
+        /* 99 */ "more_keys_for_symbols_9",
+        /* 100 */ "more_keys_for_symbols_0",
+        /* 101 */ "keylabel_for_comma",
+        /* 102 */ "more_keys_for_comma",
+        /* 103 */ "keylabel_for_symbols_question",
+        /* 104 */ "keylabel_for_symbols_semicolon",
+        /* 105 */ "keylabel_for_symbols_percent",
+        /* 106 */ "more_keys_for_symbols_exclamation",
+        /* 107 */ "more_keys_for_symbols_question",
+        /* 108 */ "more_keys_for_symbols_semicolon",
+        /* 109 */ "more_keys_for_symbols_percent",
+        /* 110 */ "keylabel_for_tablet_comma",
+        /* 111 */ "keyhintlabel_for_tablet_comma",
+        /* 112 */ "more_keys_for_tablet_comma",
+        /* 113 */ "keyhintlabel_for_period",
+        /* 114 */ "more_keys_for_period",
+        /* 115 */ "keylabel_for_apostrophe",
+        /* 116 */ "keyhintlabel_for_apostrophe",
+        /* 117 */ "more_keys_for_apostrophe",
+        /* 118 */ "more_keys_for_q",
+        /* 119 */ "more_keys_for_x",
+        /* 120 */ "keylabel_for_q",
+        /* 121 */ "keylabel_for_w",
+        /* 122 */ "keylabel_for_y",
+        /* 123 */ "keylabel_for_x",
+        /* 124 */ "keylabel_for_spanish_row2_10",
+        /* 125 */ "more_keys_for_am_pm",
+        /* 126 */ "settings_as_more_key",
+        /* 127 */ "shortcut_as_more_key",
+        /* 128 */ "action_next_as_more_key",
+        /* 129 */ "action_previous_as_more_key",
+        /* 130 */ "label_to_more_symbol_key",
+        /* 131 */ "label_to_more_symbol_for_tablet_key",
+        /* 132 */ "label_tab_key",
+        /* 133 */ "label_to_phone_numeric_key",
+        /* 134 */ "label_to_phone_symbols_key",
+        /* 135 */ "label_time_am",
+        /* 136 */ "label_time_pm",
+        /* 137 */ "keylabel_for_popular_domain",
+        /* 138 */ "more_keys_for_popular_domain",
+        /* 139 */ "more_keys_for_smiley",
+        /* 140 */ "single_laqm_raqm",
+        /* 141 */ "single_laqm_raqm_rtl",
+        /* 142 */ "single_raqm_laqm",
+        /* 143 */ "double_laqm_raqm",
+        /* 144 */ "double_laqm_raqm_rtl",
+        /* 145 */ "double_raqm_laqm",
+        /* 146 */ "single_lqm_rqm",
+        /* 147 */ "single_9qm_lqm",
+        /* 148 */ "single_9qm_rqm",
+        /* 149 */ "double_lqm_rqm",
+        /* 150 */ "double_9qm_lqm",
+        /* 151 */ "double_9qm_rqm",
+        /* 152 */ "more_keys_for_single_quote",
+        /* 153 */ "more_keys_for_double_quote",
+        /* 154 */ "more_keys_for_tablet_double_quote",
+        /* 155 */ "emoji_key_as_more_key",
     };
 
     private static final String EMPTY = "";
@@ -262,145 +268,145 @@
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-        /* ~44 */
+        EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
-        /* 45 */ "ABC",
-        /* 46 */ "!text/single_lqm_rqm",
-        /* 47 */ "!text/double_lqm_rqm",
-        /* 48 */ "!text/single_laqm_raqm",
-        /* 49 */ "!text/double_laqm_raqm",
+        /* 51 */ "ABC",
+        /* 52 */ "!text/single_lqm_rqm",
+        /* 53 */ "!text/double_lqm_rqm",
+        /* 54 */ "!text/single_laqm_raqm",
+        /* 55 */ "!text/double_laqm_raqm",
         // U+00A2: "¢" CENT SIGN
         // U+00A3: "£" POUND SIGN
         // U+20AC: "€" EURO SIGN
         // U+00A5: "¥" YEN SIGN
         // U+20B1: "₱" PESO SIGN
-        /* 50 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
-        /* 51 */ "$",
-        /* 52 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
-        /* 53 */ "!fixedColumnOrder!3,!,\\,,?,:,;,@",
+        /* 56 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+        /* 57 */ "$",
+        /* 58 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
+        /* 59 */ "!fixedColumnOrder!4,#,!,\\,,?,-,:,',@",
         // U+2020: "†" DAGGER
         // U+2021: "‡" DOUBLE DAGGER
         // U+2605: "★" BLACK STAR
-        /* 54 */ "\u2020,\u2021,\u2605",
+        /* 60 */ "\u2020,\u2021,\u2605",
         // U+266A: "♪" EIGHTH NOTE
         // U+2665: "♥" BLACK HEART SUIT
         // U+2660: "♠" BLACK SPADE SUIT
         // U+2666: "♦" BLACK DIAMOND SUIT
         // U+2663: "♣" BLACK CLUB SUIT
-        /* 55 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+        /* 61 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
         // U+00B1: "±" PLUS-MINUS SIGN
-        /* 56 */ "\u00B1",
+        /* 62 */ "\u00B1",
         // The all letters need to be mirrored are found at
         // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
-        /* 57 */ "!fixedColumnOrder!3,<,{,[",
-        /* 58 */ "!fixedColumnOrder!3,>,},]",
+        /* 63 */ "!fixedColumnOrder!3,<,{,[",
+        /* 64 */ "!fixedColumnOrder!3,>,},]",
         // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
         // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
         // U+2264: "≤" LESS-THAN OR EQUAL TO
         // U+2265: "≥" GREATER-THAN EQUAL TO
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
-        /* 59 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
-        /* 60 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
-        /* 61 */ EMPTY,
-        /* 62 */ EMPTY,
-        /* 63 */ "1",
-        /* 64 */ "2",
-        /* 65 */ "3",
-        /* 66 */ "4",
-        /* 67 */ "5",
-        /* 68 */ "6",
-        /* 69 */ "7",
-        /* 70 */ "8",
-        /* 71 */ "9",
-        /* 72 */ "0",
+        /* 65 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
+        /* 66 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
+        /* 67 */ EMPTY,
+        /* 68 */ EMPTY,
+        /* 69 */ "1",
+        /* 70 */ "2",
+        /* 71 */ "3",
+        /* 72 */ "4",
+        /* 73 */ "5",
+        /* 74 */ "6",
+        /* 75 */ "7",
+        /* 76 */ "8",
+        /* 77 */ "9",
+        /* 78 */ "0",
         // Label for "switch to symbols" key.
-        /* 73 */ "?123",
+        /* 79 */ "?123",
         // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
         // part because it'll be appended by the code.
-        /* 74 */ "123",
-        /* 75~ */
+        /* 80 */ "123",
+        /* 81~ */
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-        /* ~84 */
+        /* ~90 */
         // 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
-        /* 85 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+        /* 91 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
         // U+00B2: "²" SUPERSCRIPT TWO
         // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
-        /* 86 */ "\u00B2,\u2154",
+        /* 92 */ "\u00B2,\u2154",
         // U+00B3: "³" SUPERSCRIPT THREE
         // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
         // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
-        /* 87 */ "\u00B3,\u00BE,\u215C",
+        /* 93 */ "\u00B3,\u00BE,\u215C",
         // U+2074: "⁴" SUPERSCRIPT FOUR
-        /* 88 */ "\u2074",
+        /* 94 */ "\u2074",
         // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
-        /* 89 */ "\u215D",
-        /* 90 */ EMPTY,
+        /* 95 */ "\u215D",
+        /* 96 */ EMPTY,
         // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
-        /* 91 */ "\u215E",
-        /* 92 */ EMPTY,
-        /* 93 */ EMPTY,
+        /* 97 */ "\u215E",
+        /* 98 */ EMPTY,
+        /* 99 */ EMPTY,
         // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
         // U+2205: "∅" EMPTY SET
-        /* 94 */ "\u207F,\u2205",
-        /* 95 */ ",",
-        /* 96 */ EMPTY,
-        /* 97 */ "?",
-        /* 98 */ ";",
-        /* 99 */ "%",
-        // U+00A1: "¡" INVERTED EXCLAMATION MARK
-        /* 100 */ "\u00A1",
-        // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 101 */ "\u00BF",
+        /* 100 */ "\u207F,\u2205",
+        /* 101 */ ",",
         /* 102 */ EMPTY,
+        /* 103 */ "?",
+        /* 104 */ ";",
+        /* 105 */ "%",
+        // U+00A1: "¡" INVERTED EXCLAMATION MARK
+        /* 106 */ "\u00A1",
+        // U+00BF: "¿" INVERTED QUESTION MARK
+        /* 107 */ "\u00BF",
+        /* 108 */ EMPTY,
         // U+2030: "‰" PER MILLE SIGN
-        /* 103 */ "\u2030",
-        /* 104 */ ",",
-        /* 105~ */
+        /* 109 */ "\u2030",
+        /* 110 */ ",",
+        /* 111~ */
         EMPTY, EMPTY, EMPTY,
-        /* ~107 */
+        /* ~113 */
         // U+2026: "…" HORIZONTAL ELLIPSIS
-        /* 108 */ "\u2026",
-        /* 109 */ "\'",
-        /* 110 */ "\"",
-        /* 111 */ "\"",
-        /* 112 */ EMPTY,
-        /* 113 */ EMPTY,
-        /* 114 */ "q",
-        /* 115 */ "w",
-        /* 116 */ "y",
-        /* 117 */ "x",
+        /* 114 */ "\u2026",
+        /* 115 */ "\'",
+        /* 116 */ "\"",
+        /* 117 */ "\"",
         /* 118 */ EMPTY,
-        /* 119 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
-        /* 120 */ "!icon/settings_key|!code/key_settings",
-        /* 121 */ "!icon/shortcut_key|!code/key_shortcut",
-        /* 122 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
-        /* 123 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+        /* 119 */ EMPTY,
+        /* 120 */ "q",
+        /* 121 */ "w",
+        /* 122 */ "y",
+        /* 123 */ "x",
+        /* 124 */ EMPTY,
+        /* 125 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+        /* 126 */ "!icon/settings_key|!code/key_settings",
+        /* 127 */ "!icon/shortcut_key|!code/key_shortcut",
+        /* 128 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+        /* 129 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
         // Label for "switch to more symbol" modifier key.  Must be short to fit on key!
-        /* 124 */ "= \\ <",
+        /* 130 */ "= \\ <",
         // Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key!
-        /* 125 */ "~ [ <",
+        /* 131 */ "~ [ <",
         // Label for "Tab" key.  Must be short to fit on key!
-        /* 126 */ "Tab",
+        /* 132 */ "Tab",
         // Label for "switch to phone numeric" key.  Must be short to fit on key!
-        /* 127 */ "123",
+        /* 133 */ "123",
         // Label for "switch to phone symbols" key.  Must be short to fit on key!
         // U+FF0A: "*" FULLWIDTH ASTERISK
         // U+FF03: "#" FULLWIDTH NUMBER SIGN
-        /* 128 */ "\uFF0A\uFF03",
+        /* 134 */ "\uFF0A\uFF03",
         // Key label for "ante meridiem"
-        /* 129 */ "AM",
+        /* 135 */ "AM",
         // Key label for "post meridiem"
-        /* 130 */ "PM",
-        /* 131 */ ".com",
+        /* 136 */ "PM",
+        /* 137 */ ".com",
         // popular web domains for the locale - most popular, displayed on the keyboard
-        /* 132 */ "!hasLabels!,.net,.org,.gov,.edu",
-        /* 133 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+        /* 138 */ "!hasLabels!,.net,.org,.gov,.edu",
+        /* 139 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
         // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
         // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -422,25 +428,25 @@
         // The following each quotation mark pair consist of
         // <opening quotation mark>, <closing quotation mark>
         // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
-        /* 134 */ "\u2039,\u203A",
-        /* 135 */ "\u2039|\u203A,\u203A|\u2039",
-        /* 136 */ "\u203A,\u2039",
-        /* 137 */ "\u00AB,\u00BB",
-        /* 138 */ "\u00AB|\u00BB,\u00BB|\u00AB",
-        /* 139 */ "\u00BB,\u00AB",
+        /* 140 */ "\u2039,\u203A",
+        /* 141 */ "\u2039|\u203A,\u203A|\u2039",
+        /* 142 */ "\u203A,\u2039",
+        /* 143 */ "\u00AB,\u00BB",
+        /* 144 */ "\u00AB|\u00BB,\u00BB|\u00AB",
+        /* 145 */ "\u00BB,\u00AB",
         // The following each quotation mark triplet consists of
         // <another quotation mark>, <opening quotation mark>, <closing quotation mark>
         // and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
-        /* 140 */ "\u201A,\u2018,\u2019",
-        /* 141 */ "\u2019,\u201A,\u2018",
-        /* 142 */ "\u2018,\u201A,\u2019",
-        /* 143 */ "\u201E,\u201C,\u201D",
-        /* 144 */ "\u201D,\u201E,\u201C",
-        /* 145 */ "\u201C,\u201E,\u201D",
-        /* 146 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
-        /* 147 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
-        /* 148 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
-        /* 149 */ "!icon/emoji_key|!code/key_emoji",
+        /* 146 */ "\u201A,\u2018,\u2019",
+        /* 147 */ "\u2019,\u201A,\u2018",
+        /* 148 */ "\u2018,\u201A,\u2019",
+        /* 149 */ "\u201E,\u201C,\u201D",
+        /* 150 */ "\u201D,\u201E,\u201C",
+        /* 151 */ "\u201C,\u201E,\u201D",
+        /* 152 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
+        /* 153 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
+        /* 154 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
+        /* 155 */ "!icon/emoji_key|!code/key_emoji",
     };
 
     /* Language af: Afrikaans */
@@ -502,44 +508,45 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0623: "ا" ARABIC LETTER ALEF
         // U+200C: ZERO WIDTH NON-JOINER
         // U+0628: "ب" ARABIC LETTER BEH
         // U+062C: "پ" ARABIC LETTER PEH
-        /* 45 */ "\u0623\u200C\u0628\u200C\u062C",
-        /* 46 */ null,
-        /* 47 */ null,
-        /* 48 */ "!text/single_laqm_raqm_rtl",
-        /* 49 */ "!text/double_laqm_raqm_rtl",
-        /* 50~ */
+        /* 51 */ "\u0623\u200C\u0628\u200C\u062C",
+        /* 52 */ null,
+        /* 53 */ null,
+        /* 54 */ "!text/single_laqm_raqm_rtl",
+        /* 55 */ "!text/double_laqm_raqm_rtl",
+        /* 56~ */
         null, null, null,
-        /* ~52 */
+        /* ~58 */
         // U+061F: "؟" ARABIC QUESTION MARK
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
-        /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(",
+        /* 59 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(",
         // U+2605: "★" BLACK STAR
         // U+066D: "٭" ARABIC FIVE POINTED STAR
-        /* 54 */ "\u2605,\u066D",
+        /* 60 */ "\u2605,\u066D",
         // U+266A: "♪" EIGHTH NOTE
-        /* 55 */ "\u266A",
-        /* 56 */ null,
+        /* 61 */ "\u266A",
+        /* 62 */ 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
-        /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
-        /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+        /* 63 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 64 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
         // U+2264: "≤" LESS-THAN OR EQUAL TO
         // U+2265: "≥" GREATER-THAN EQUAL TO
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
         // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
-        /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
-        /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        /* 65 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 66 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
         // U+0655: "ٕ" ARABIC HAMZA BELOW
         // U+0654: "ٔ" ARABIC HAMZA ABOVE
         // U+0652: "ْ" ARABIC SUKUN
@@ -556,70 +563,70 @@
         // U+0640: "ـ" ARABIC TATWEEL
         // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
         // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
-        /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
-        /* 62 */ "\u0651",
+        /* 67 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+        /* 68 */ "\u0651",
         // U+0661: "١" ARABIC-INDIC DIGIT ONE
-        /* 63 */ "\u0661",
+        /* 69 */ "\u0661",
         // U+0662: "٢" ARABIC-INDIC DIGIT TWO
-        /* 64 */ "\u0662",
+        /* 70 */ "\u0662",
         // U+0663: "٣" ARABIC-INDIC DIGIT THREE
-        /* 65 */ "\u0663",
+        /* 71 */ "\u0663",
         // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
-        /* 66 */ "\u0664",
+        /* 72 */ "\u0664",
         // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
-        /* 67 */ "\u0665",
+        /* 73 */ "\u0665",
         // U+0666: "٦" ARABIC-INDIC DIGIT SIX
-        /* 68 */ "\u0666",
+        /* 74 */ "\u0666",
         // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
-        /* 69 */ "\u0667",
+        /* 75 */ "\u0667",
         // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
-        /* 70 */ "\u0668",
+        /* 76 */ "\u0668",
         // U+0669: "٩" ARABIC-INDIC DIGIT NINE
-        /* 71 */ "\u0669",
+        /* 77 */ "\u0669",
         // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
-        /* 72 */ "\u0660",
+        /* 78 */ "\u0660",
         // Label for "switch to symbols" key.
         // U+061F: "؟" ARABIC QUESTION MARK
-        /* 73 */ "\u0663\u0662\u0661\u061F",
+        /* 79 */ "\u0663\u0662\u0661\u061F",
         // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
         // part because it'll be appended by the code.
-        /* 74 */ "\u0663\u0662\u0661",
-        /* 75 */ "1",
-        /* 76 */ "2",
-        /* 77 */ "3",
-        /* 78 */ "4",
-        /* 79 */ "5",
-        /* 80 */ "6",
-        /* 81 */ "7",
-        /* 82 */ "8",
-        /* 83 */ "9",
+        /* 80 */ "\u0663\u0662\u0661",
+        /* 81 */ "1",
+        /* 82 */ "2",
+        /* 83 */ "3",
+        /* 84 */ "4",
+        /* 85 */ "5",
+        /* 86 */ "6",
+        /* 87 */ "7",
+        /* 88 */ "8",
+        /* 89 */ "9",
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
-        /* 84 */ "0,\u066B,\u066C",
-        /* 85~ */
+        /* 90 */ "0,\u066B,\u066C",
+        /* 91~ */
         null, null, null, null, null, null, null, null, null, null,
-        /* ~94 */
+        /* ~100 */
         // U+060C: "،" ARABIC COMMA
-        /* 95 */ "\u060C",
-        /* 96 */ "\\,",
-        /* 97 */ "\u061F",
-        /* 98 */ "\u061B",
+        /* 101 */ "\u060C",
+        /* 102 */ "\\,",
+        /* 103 */ "\u061F",
+        /* 104 */ "\u061B",
         // U+066A: "٪" ARABIC PERCENT SIGN
-        /* 99 */ "\u066A",
-        /* 100 */ null,
-        /* 101 */ "?",
-        /* 102 */ ";",
+        /* 105 */ "\u066A",
+        /* 106 */ null,
+        /* 107 */ "?",
+        /* 108 */ ";",
         // U+2030: "‰" PER MILLE SIGN
-        /* 103 */ "\\%,\u2030",
-        /* 104~ */
+        /* 109 */ "\\%,\u2030",
+        /* 110~ */
         null, null, null, null, null,
-        /* ~108 */
+        /* ~114 */
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
         // U+061F: "؟" ARABIC QUESTION MARK
-        /* 109 */ "\u060C",
-        /* 110 */ "\u061F",
-        /* 111 */ "\u061F,\u061B,!,:,-,/,\',\"",
+        /* 115 */ "\u060C",
+        /* 116 */ "\u061F",
+        /* 117 */ "\u061F,\u061B,!,:,-,/,\',\"",
     };
 
     /* Language az: Azerbaijani */
@@ -694,14 +701,16 @@
         /* ~42 */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* 43 */ "\u0451",
-        /* 44 */ null,
+        /* 44~ */
+        null, null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language bg: Bulgarian */
@@ -710,15 +719,16 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ null,
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ null,
         // single_quotes of Bulgarian is default single_quotes_right_left.
-        /* 47 */ "!text/double_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language ca: Catalan */
@@ -782,22 +792,22 @@
         /* 15~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, 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+00B7: "·" MIDDLE DOT
-        /* 53 */ "!fixedColumnOrder!4,\u00B7,!,\\,,?,:,;,@",
-        /* 54~ */
+        /* 59 */ "!fixedColumnOrder!4,\u00B7,!,\\,,?,:,;,@",
+        /* 60~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null,
-        /* ~107 */
-        /* 108 */ "?,\u00B7",
-        /* 109~ */
+        /* ~113 */
+        /* 114 */ "?,\u00B7",
+        /* 115~ */
         null, null, null, null, null, null, null, null, null,
-        /* ~117 */
+        /* ~123 */
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
-        /* 118 */ "\u00E7",
+        /* 124 */ "\u00E7",
     };
 
     /* Language cs: Czech */
@@ -871,12 +881,12 @@
         /* 13~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language da: Danish */
@@ -940,12 +950,12 @@
         /* 24 */ "\u00F6",
         /* 25~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language de: German */
@@ -991,12 +1001,25 @@
         /* 7~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null,
+        /* ~44 */
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        /* 45 */ "\u00FC",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 46 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 47 */ "\u00E4",
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        /* 48 */ "\u00E8",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        /* 49 */ "\u00E9",
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        /* 50 */ "\u00E0",
+        /* 51 */ null,
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language el: Greek */
@@ -1005,12 +1028,13 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0391: "Α" GREEK CAPITAL LETTER ALPHA
         // U+0392: "Β" GREEK CAPITAL LETTER BETA
         // U+0393: "Γ" GREEK CAPITAL LETTER GAMMA
-        /* 45 */ "\u0391\u0392\u0393",
+        /* 51 */ "\u0391\u0392\u0393",
     };
 
     /* Language en: English */
@@ -1182,20 +1206,20 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null,
-        /* ~111 */
-        /* 112 */ "q",
-        /* 113 */ "x",
+        null, null, null, null, null, null, null, null,
+        /* ~117 */
+        /* 118 */ "q",
+        /* 119 */ "x",
         // U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
-        /* 114 */ "\u015D",
+        /* 120 */ "\u015D",
         // U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
-        /* 115 */ "\u011D",
+        /* 121 */ "\u011D",
         // U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
-        /* 116 */ "\u016D",
+        /* 122 */ "\u016D",
         // U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
-        /* 117 */ "\u0109",
+        /* 123 */ "\u0109",
         // U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
-        /* 118 */ "\u0135",
+        /* 124 */ "\u0135",
     };
 
     /* Language es: Spanish */
@@ -1254,29 +1278,30 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, 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,
+        /* ~58 */
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
         // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 53 */ "!fixedColumnOrder!4,;,!,\\,,?,:,\u00A1,@,\u00BF",
-        /* 54~ */
+        /* 59 */ "!fixedColumnOrder!4,;,!,\\,,?,:,\u00A1,@,\u00BF",
+        /* 60~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null,
-        /* ~105 */
+        /* ~111 */
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
-        /* 106 */ "!,\u00A1",
-        /* 107 */ null,
+        /* 112 */ "!,\u00A1",
+        /* 113 */ null,
         // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 108 */ "?,\u00BF",
-        /* 109 */ "\"",
-        /* 110 */ "\'",
-        /* 111 */ "\'",
-        /* 112~ */
+        /* 114 */ "?,\u00BF",
+        /* 115 */ "\"",
+        /* 116 */ "\'",
+        /* 117 */ "\'",
+        /* 118~ */
         null, null, null, null, null, null,
-        /* ~117 */
+        /* ~123 */
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
-        /* 118 */ "\u00F1",
+        /* 124 */ "\u00F1",
     };
 
     /* Language et: Estonian */
@@ -1379,10 +1404,10 @@
         /* 23 */ "\u00F5",
         /* 24~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language fa: Persian */
@@ -1391,45 +1416,46 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0627: "ا" ARABIC LETTER ALEF
         // U+200C: ZERO WIDTH NON-JOINER
         // U+0628: "ب" ARABIC LETTER BEH
         // U+067E: "پ" ARABIC LETTER PEH
-        /* 45 */ "\u0627\u200C\u0628\u200C\u067E",
-        /* 46 */ null,
-        /* 47 */ null,
-        /* 48 */ "!text/single_laqm_raqm_rtl",
-        /* 49 */ "!text/double_laqm_raqm_rtl",
-        /* 50 */ null,
-        // U+FDFC: "﷼" RIAL SIGN
-        /* 51 */ "\uFDFC",
+        /* 51 */ "\u0627\u200C\u0628\u200C\u067E",
         /* 52 */ null,
+        /* 53 */ null,
+        /* 54 */ "!text/single_laqm_raqm_rtl",
+        /* 55 */ "!text/double_laqm_raqm_rtl",
+        /* 56 */ null,
+        // U+FDFC: "﷼" RIAL SIGN
+        /* 57 */ "\uFDFC",
+        /* 58 */ null,
         // U+061F: "؟" ARABIC QUESTION MARK
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
-        /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(",
+        /* 59 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(",
         // U+2605: "★" BLACK STAR
         // U+066D: "٭" ARABIC FIVE POINTED STAR
-        /* 54 */ "\u2605,\u066D",
+        /* 60 */ "\u2605,\u066D",
         // U+266A: "♪" EIGHTH NOTE
-        /* 55 */ "\u266A",
-        /* 56 */ null,
+        /* 61 */ "\u266A",
+        /* 62 */ 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
-        /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
-        /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+        /* 63 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+        /* 64 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
         // U+2264: "≤" LESS-THAN OR EQUAL TO
         // U+2265: "≥" GREATER-THAN EQUAL TO
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
         // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
-        /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
-        /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
+        /* 65 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
+        /* 66 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
         // U+0655: "ٕ" ARABIC HAMZA BELOW
         // U+0652: "ْ" ARABIC SUKUN
         // U+0651: "ّ" ARABIC SHADDA
@@ -1446,74 +1472,74 @@
         // U+0640: "ـ" ARABIC TATWEEL
         // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
         // Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
-        /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
-        /* 62 */ "\u064B",
+        /* 67 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+        /* 68 */ "\u064B",
         // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
-        /* 63 */ "\u06F1",
+        /* 69 */ "\u06F1",
         // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
-        /* 64 */ "\u06F2",
+        /* 70 */ "\u06F2",
         // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
-        /* 65 */ "\u06F3",
+        /* 71 */ "\u06F3",
         // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
-        /* 66 */ "\u06F4",
+        /* 72 */ "\u06F4",
         // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
-        /* 67 */ "\u06F5",
+        /* 73 */ "\u06F5",
         // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
-        /* 68 */ "\u06F6",
+        /* 74 */ "\u06F6",
         // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
-        /* 69 */ "\u06F7",
+        /* 75 */ "\u06F7",
         // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
-        /* 70 */ "\u06F8",
+        /* 76 */ "\u06F8",
         // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
-        /* 71 */ "\u06F9",
+        /* 77 */ "\u06F9",
         // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
-        /* 72 */ "\u06F0",
+        /* 78 */ "\u06F0",
         // Label for "switch to symbols" key.
         // U+061F: "؟" ARABIC QUESTION MARK
-        /* 73 */ "\u06F3\u06F2\u06F1\u061F",
+        /* 79 */ "\u06F3\u06F2\u06F1\u061F",
         // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
         // part because it'll be appended by the code.
-        /* 74 */ "\u06F3\u06F2\u06F1",
-        /* 75 */ "1",
-        /* 76 */ "2",
-        /* 77 */ "3",
-        /* 78 */ "4",
-        /* 79 */ "5",
-        /* 80 */ "6",
-        /* 81 */ "7",
-        /* 82 */ "8",
-        /* 83 */ "9",
+        /* 80 */ "\u06F3\u06F2\u06F1",
+        /* 81 */ "1",
+        /* 82 */ "2",
+        /* 83 */ "3",
+        /* 84 */ "4",
+        /* 85 */ "5",
+        /* 86 */ "6",
+        /* 87 */ "7",
+        /* 88 */ "8",
+        /* 89 */ "9",
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
-        /* 84 */ "0,\u066B,\u066C",
-        /* 85~ */
+        /* 90 */ "0,\u066B,\u066C",
+        /* 91~ */
         null, null, null, null, null, null, null, null, null, null,
-        /* ~94 */
+        /* ~100 */
         // U+060C: "،" ARABIC COMMA
-        /* 95 */ "\u060C",
-        /* 96 */ "\\,",
-        /* 97 */ "\u061F",
-        /* 98 */ "\u061B",
+        /* 101 */ "\u060C",
+        /* 102 */ "\\,",
+        /* 103 */ "\u061F",
+        /* 104 */ "\u061B",
         // U+066A: "٪" ARABIC PERCENT SIGN
-        /* 99 */ "\u066A",
-        /* 100 */ null,
-        /* 101 */ "?",
-        /* 102 */ ";",
+        /* 105 */ "\u066A",
+        /* 106 */ null,
+        /* 107 */ "?",
+        /* 108 */ ";",
         // U+2030: "‰" PER MILLE SIGN
-        /* 103 */ "\\%,\u2030",
+        /* 109 */ "\\%,\u2030",
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
         // U+061F: "؟" ARABIC QUESTION MARK
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
-        /* 104 */ "\u060C",
-        /* 105 */ "!",
-        /* 106 */ "!,\\,",
-        /* 107 */ "\u061F",
-        /* 108 */ "\u061F,?",
-        /* 109 */ "\u060C",
-        /* 110 */ "\u061F",
-        /* 111 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
+        /* 110 */ "\u060C",
+        /* 111 */ "!",
+        /* 112 */ "!,\\,",
+        /* 113 */ "\u061F",
+        /* 114 */ "\u061F,?",
+        /* 115 */ "\u060C",
+        /* 116 */ "\u061F",
+        /* 117 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
     };
 
     /* Language fi: Finnish */
@@ -1614,6 +1640,23 @@
         /* 7 */ "\u00E7,\u0107,\u010D",
         // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
         /* 8 */ "%,\u00FF",
+        /* 9~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null,
+        /* ~44 */
+        // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+        /* 45 */ "\u00E8",
+        // U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
+        /* 46 */ "\u00E9",
+        // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+        /* 47 */ "\u00E0",
+        // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+        /* 48 */ "\u00FC",
+        // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+        /* 49 */ "\u00F6",
+        // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS
+        /* 50 */ "\u00E4",
     };
 
     /* Language hi: Hindi */
@@ -1622,55 +1665,56 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0915: "क" DEVANAGARI LETTER KA
         // U+0916: "ख" DEVANAGARI LETTER KHA
         // U+0917: "ग" DEVANAGARI LETTER GA
-        /* 45 */ "\u0915\u0916\u0917",
-        /* 46~ */
-        null, null, null, null, null,
-        /* ~50 */
-        // U+20B9: "₹" INDIAN RUPEE SIGN
-        /* 51 */ "\u20B9",
+        /* 51 */ "\u0915\u0916\u0917",
         /* 52~ */
+        null, null, null, null, null,
+        /* ~56 */
+        // U+20B9: "₹" INDIAN RUPEE SIGN
+        /* 57 */ "\u20B9",
+        /* 58~ */
         null, null, null, null, null, null, null, null, null, null, null,
-        /* ~62 */
+        /* ~68 */
         // U+0967: "१" DEVANAGARI DIGIT ONE
-        /* 63 */ "\u0967",
+        /* 69 */ "\u0967",
         // U+0968: "२" DEVANAGARI DIGIT TWO
-        /* 64 */ "\u0968",
+        /* 70 */ "\u0968",
         // U+0969: "३" DEVANAGARI DIGIT THREE
-        /* 65 */ "\u0969",
+        /* 71 */ "\u0969",
         // U+096A: "४" DEVANAGARI DIGIT FOUR
-        /* 66 */ "\u096A",
+        /* 72 */ "\u096A",
         // U+096B: "५" DEVANAGARI DIGIT FIVE
-        /* 67 */ "\u096B",
+        /* 73 */ "\u096B",
         // U+096C: "६" DEVANAGARI DIGIT SIX
-        /* 68 */ "\u096C",
+        /* 74 */ "\u096C",
         // U+096D: "७" DEVANAGARI DIGIT SEVEN
-        /* 69 */ "\u096D",
+        /* 75 */ "\u096D",
         // U+096E: "८" DEVANAGARI DIGIT EIGHT
-        /* 70 */ "\u096E",
+        /* 76 */ "\u096E",
         // U+096F: "९" DEVANAGARI DIGIT NINE
-        /* 71 */ "\u096F",
+        /* 77 */ "\u096F",
         // U+0966: "०" DEVANAGARI DIGIT ZERO
-        /* 72 */ "\u0966",
+        /* 78 */ "\u0966",
         // Label for "switch to symbols" key.
-        /* 73 */ "?\u0967\u0968\u0969",
+        /* 79 */ "?\u0967\u0968\u0969",
         // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
         // part because it'll be appended by the code.
-        /* 74 */ "\u0967\u0968\u0969",
-        /* 75 */ "1",
-        /* 76 */ "2",
-        /* 77 */ "3",
-        /* 78 */ "4",
-        /* 79 */ "5",
-        /* 80 */ "6",
-        /* 81 */ "7",
-        /* 82 */ "8",
-        /* 83 */ "9",
-        /* 84 */ "0",
+        /* 80 */ "\u0967\u0968\u0969",
+        /* 81 */ "1",
+        /* 82 */ "2",
+        /* 83 */ "3",
+        /* 84 */ "4",
+        /* 85 */ "5",
+        /* 86 */ "6",
+        /* 87 */ "7",
+        /* 88 */ "8",
+        /* 89 */ "9",
+        /* 90 */ "0",
     };
 
     /* Language hr: Croatian */
@@ -1701,12 +1745,12 @@
         /* 13~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language hu: Hungarian */
@@ -1755,12 +1799,13 @@
         /* 5~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language hy: Armenian */
@@ -1769,8 +1814,8 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, 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+058A: "֊" ARMENIAN HYPHEN
         // U+055C: "՜" ARMENIAN EXCLAMATION MARK
         // U+055D: "՝" ARMENIAN COMMA
@@ -1779,19 +1824,19 @@
         // U+055A: "՚" ARMENIAN APOSTROPHE
         // U+055B: "՛" ARMENIAN EMPHASIS MARK
         // U+055F: "՟" ARMENIAN ABBREVIATION MARK
-        /* 53 */ "!fixedColumnOrder!8,!,?,\\,,.,\u058A,\u055C,\u055D,\u055E,:,;,@,\u0559,\u055A,\u055B,\u055F",
-        /* 54~ */
+        /* 59 */ "!fixedColumnOrder!8,!,?,\\,,.,\u058A,\u055C,\u055D,\u055E,:,;,@,\u0559,\u055A,\u055B,\u055F",
+        /* 60~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null,
-        /* ~99 */
+        /* ~105 */
         // U+055C: "՜" ARMENIAN EXCLAMATION MARK
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
-        /* 100 */ "\u055C,\u00A1",
+        /* 106 */ "\u055C,\u00A1",
         // U+055E: "՞" ARMENIAN QUESTION MARK
         // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 101 */ "\u055E,\u00BF",
+        /* 107 */ "\u055E,\u00BF",
     };
 
     /* Language is: Icelandic */
@@ -1857,10 +1902,10 @@
         /* 22 */ "\u00FE",
         /* 23~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language it: Italian */
@@ -1914,12 +1959,13 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+05D0: "א" HEBREW LETTER ALEF
         // U+05D1: "ב" HEBREW LETTER BET
         // U+05D2: "ג" HEBREW LETTER GIMEL
-        /* 45 */ "\u05D0\u05D1\u05D2",
+        /* 51 */ "\u05D0\u05D1\u05D2",
         // The following characters don't need BIDI mirroring.
         // U+2018: "‘" LEFT SINGLE QUOTATION MARK
         // U+2019: "’" RIGHT SINGLE QUOTATION MARK
@@ -1927,42 +1973,42 @@
         // U+201C: "“" LEFT DOUBLE QUOTATION MARK
         // U+201D: "”" RIGHT DOUBLE QUOTATION MARK
         // U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
-        /* 46 */ "\u2018,\u2019,\u201A",
-        /* 47 */ "\u201C,\u201D,\u201E",
-        /* 48 */ "!text/single_laqm_raqm_rtl",
-        /* 49 */ "!text/double_laqm_raqm_rtl",
-        /* 50 */ null,
+        /* 52 */ "\u2018,\u2019,\u201A",
+        /* 53 */ "\u201C,\u201D,\u201E",
+        /* 54 */ "!text/single_laqm_raqm_rtl",
+        /* 55 */ "!text/double_laqm_raqm_rtl",
+        /* 56 */ null,
         // U+20AA: "₪" NEW SHEQEL SIGN
-        /* 51 */ "\u20AA",
-        /* 52 */ null,
-        /* 53 */ null,
+        /* 57 */ "\u20AA",
+        /* 58 */ null,
+        /* 59 */ null,
         // U+2605: "★" BLACK STAR
-        /* 54 */ "\u2605",
-        /* 55 */ null,
+        /* 60 */ "\u2605",
+        /* 61 */ null,
         // U+00B1: "±" PLUS-MINUS SIGN
         // U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
-        /* 56 */ "\u00B1,\uFB29",
+        /* 62 */ "\u00B1,\uFB29",
         // The all letters need to be mirrored are found at
         // http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
-        /* 57 */ "!fixedColumnOrder!3,<|>,{|},[|]",
-        /* 58 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
+        /* 63 */ "!fixedColumnOrder!3,<|>,{|},[|]",
+        /* 64 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
         // U+2264: "≤" LESS-THAN OR EQUAL TO
         // U+2265: "≥" GREATER-THAN EQUAL TO
         // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
         // U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
         // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
-        /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
-        /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
-        /* 61~ */
+        /* 65 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+        /* 66 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        /* 67~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~104 */
-        /* 105 */ "!",
-        /* 106 */ "!",
-        /* 107 */ "?",
-        /* 108 */ "?",
+        /* ~110 */
+        /* 111 */ "!",
+        /* 112 */ "!",
+        /* 113 */ "?",
+        /* 114 */ "?",
     };
 
     /* Language ka: Georgian */
@@ -1971,14 +2017,15 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+10D0: "ა" GEORGIAN LETTER AN
         // U+10D1: "ბ" GEORGIAN LETTER BAN
         // U+10D2: "გ" GEORGIAN LETTER GAN
-        /* 45 */ "\u10D0\u10D1\u10D2",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        /* 51 */ "\u10D0\u10D1\u10D2",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language kk: Kazakh */
@@ -2021,12 +2068,14 @@
         /* ~42 */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* 43 */ "\u0451",
-        /* 44 */ null,
+        /* 44~ */
+        null, null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
+        /* 51 */ "\u0410\u0411\u0412",
     };
 
     /* Language km: Khmer */
@@ -2035,17 +2084,18 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+1780: "ក" KHMER LETTER KA
         // U+1781: "ខ" KHMER LETTER KHA
         // U+1782: "គ" KHMER LETTER KO
-        /* 45 */ "\u1780\u1781\u1782",
-        /* 46~ */
+        /* 51 */ "\u1780\u1781\u1782",
+        /* 52~ */
         null, null, null, null,
-        /* ~49 */
+        /* ~55 */
         // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
-        /* 50 */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+        /* 56 */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
     };
 
     /* Language ky: Kirghiz */
@@ -2081,12 +2131,14 @@
         /* ~42 */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* 43 */ "\u0451",
-        /* 44 */ null,
+        /* 44~ */
+        null, null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
+        /* 51 */ "\u0410\u0411\u0412",
     };
 
     /* Language lo: Lao */
@@ -2095,17 +2147,18 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0E81: "ກ" LAO LETTER KO
         // U+0E82: "ຂ" LAO LETTER KHO SUNG
         // U+0E84: "ຄ" LAO LETTER KHO TAM
-        /* 45 */ "\u0E81\u0E82\u0E84",
-        /* 46~ */
+        /* 51 */ "\u0E81\u0E82\u0E84",
+        /* 52~ */
         null, null, null, null, null,
-        /* ~50 */
+        /* ~56 */
         // U+20AD: "₭" KIP SIGN
-        /* 51 */ "\u20AD",
+        /* 57 */ "\u20AD",
     };
 
     /* Language lt: Lithuanian */
@@ -2199,9 +2252,10 @@
         /* 16~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language lv: Latvian */
@@ -2294,9 +2348,10 @@
         /* 16~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language mk: Macedonian */
@@ -2318,13 +2373,16 @@
         /* 43 */ "\u0450",
         // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
         /* 44 */ "\u045D",
+        /* 45~ */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language mn: Mongolian */
@@ -2333,17 +2391,18 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46~ */
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52~ */
         null, null, null, null, null,
-        /* ~50 */
+        /* ~56 */
         // U+20AE: "₮" TUGRIK SIGN
-        /* 51 */ "\u20AE",
+        /* 57 */ "\u20AE",
     };
 
     /* Language nb: Norwegian Bokmål */
@@ -2393,10 +2452,10 @@
         /* 24 */ "\u00E4",
         /* 25~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
+        null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
     };
 
     /* Language ne: Nepali */
@@ -2405,55 +2464,56 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0915: "क" DEVANAGARI LETTER KA
         // U+0916: "ख" DEVANAGARI LETTER KHA
         // U+0917: "ग" DEVANAGARI LETTER GA
-        /* 45 */ "\u0915\u0916\u0917",
-        /* 46~ */
-        null, null, null, null, null,
-        /* ~50 */
-        // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
-        /* 51 */ "\u0930\u0941.",
+        /* 51 */ "\u0915\u0916\u0917",
         /* 52~ */
+        null, null, null, null, null,
+        /* ~56 */
+        // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
+        /* 57 */ "\u0930\u0941.",
+        /* 58~ */
         null, null, null, null, null, null, null, null, null, null, null,
-        /* ~62 */
+        /* ~68 */
         // U+0967: "१" DEVANAGARI DIGIT ONE
-        /* 63 */ "\u0967",
+        /* 69 */ "\u0967",
         // U+0968: "२" DEVANAGARI DIGIT TWO
-        /* 64 */ "\u0968",
+        /* 70 */ "\u0968",
         // U+0969: "३" DEVANAGARI DIGIT THREE
-        /* 65 */ "\u0969",
+        /* 71 */ "\u0969",
         // U+096A: "४" DEVANAGARI DIGIT FOUR
-        /* 66 */ "\u096A",
+        /* 72 */ "\u096A",
         // U+096B: "५" DEVANAGARI DIGIT FIVE
-        /* 67 */ "\u096B",
+        /* 73 */ "\u096B",
         // U+096C: "६" DEVANAGARI DIGIT SIX
-        /* 68 */ "\u096C",
+        /* 74 */ "\u096C",
         // U+096D: "७" DEVANAGARI DIGIT SEVEN
-        /* 69 */ "\u096D",
+        /* 75 */ "\u096D",
         // U+096E: "८" DEVANAGARI DIGIT EIGHT
-        /* 70 */ "\u096E",
+        /* 76 */ "\u096E",
         // U+096F: "९" DEVANAGARI DIGIT NINE
-        /* 71 */ "\u096F",
+        /* 77 */ "\u096F",
         // U+0966: "०" DEVANAGARI DIGIT ZERO
-        /* 72 */ "\u0966",
+        /* 78 */ "\u0966",
         // Label for "switch to symbols" key.
-        /* 73 */ "?\u0967\u0968\u0969",
+        /* 79 */ "?\u0967\u0968\u0969",
         // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
         // part because it'll be appended by the code.
-        /* 74 */ "\u0967\u0968\u0969",
-        /* 75 */ "1",
-        /* 76 */ "2",
-        /* 77 */ "3",
-        /* 78 */ "4",
-        /* 79 */ "5",
-        /* 80 */ "6",
-        /* 81 */ "7",
-        /* 82 */ "8",
-        /* 83 */ "9",
-        /* 84 */ "0",
+        /* 80 */ "\u0967\u0968\u0969",
+        /* 81 */ "1",
+        /* 82 */ "2",
+        /* 83 */ "3",
+        /* 84 */ "4",
+        /* 85 */ "5",
+        /* 86 */ "6",
+        /* 87 */ "7",
+        /* 88 */ "8",
+        /* 89 */ "9",
+        /* 90 */ "0",
     };
 
     /* Language nl: Dutch */
@@ -2508,10 +2568,10 @@
         /* 9~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
+        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
     };
 
     /* Language pl: Polish */
@@ -2569,10 +2629,10 @@
         /* 15~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
+        null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
     };
 
     /* Language pt: Portuguese */
@@ -2675,10 +2735,10 @@
         /* 12~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_rqm",
-        /* 47 */ "!text/double_9qm_rqm",
+        null, null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_rqm",
+        /* 53 */ "!text/double_9qm_rqm",
     };
 
     /* Language ru: Russian */
@@ -2707,14 +2767,16 @@
         /* ~42 */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* 43 */ "\u0451",
-        /* 44 */ null,
+        /* 44~ */
+        null, null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
     };
 
     /* Language sk: Slovak */
@@ -2808,11 +2870,12 @@
         /* 16~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language sl: Slovenian */
@@ -2836,12 +2899,12 @@
         /* 13~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null,
-        /* ~45 */
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null,
+        /* ~51 */
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language sr: Serbian */
@@ -2881,16 +2944,19 @@
         /* 43 */ "\u0450",
         // U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
         /* 44 */ "\u045D",
+        /* 45~ */
+        null, null, null, null, null, null,
+        /* ~50 */
         // END: More keys definitions for Serbian (Cyrillic)
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language sv: Swedish */
@@ -2972,10 +3038,10 @@
         /* 24 */ "\u00E6",
         /* 25~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null,
-        /* ~47 */
-        /* 48 */ "!text/single_raqm_laqm",
-        /* 49 */ "!text/double_raqm_laqm",
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~53 */
+        /* 54 */ "!text/single_raqm_laqm",
+        /* 55 */ "!text/double_raqm_laqm",
     };
 
     /* Language sw: Swahili */
@@ -3035,17 +3101,18 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0E01: "ก" THAI CHARACTER KO KAI
         // U+0E02: "ข" THAI CHARACTER KHO KHAI
         // U+0E04: "ค" THAI CHARACTER KHO KHWAI
-        /* 45 */ "\u0E01\u0E02\u0E04",
-        /* 46~ */
+        /* 51 */ "\u0E01\u0E02\u0E04",
+        /* 52~ */
         null, null, null, null, null,
-        /* ~50 */
+        /* ~56 */
         // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
-        /* 51 */ "\u0E3F",
+        /* 57 */ "\u0E3F",
     };
 
     /* Language tl: Tagalog */
@@ -3175,20 +3242,20 @@
         // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
         /* 37 */ "\u044A",
         /* 38~ */
-        null, null, null, null, null, null, null,
-        /* ~44 */
+        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~50 */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
-        /* 45 */ "\u0410\u0411\u0412",
-        /* 46 */ "!text/single_9qm_lqm",
-        /* 47 */ "!text/double_9qm_lqm",
-        /* 48~ */
+        /* 51 */ "\u0410\u0411\u0412",
+        /* 52 */ "!text/single_9qm_lqm",
+        /* 53 */ "!text/double_9qm_lqm",
+        /* 54~ */
         null, null, null,
-        /* ~50 */
+        /* ~56 */
         // U+20B4: "₴" HRYVNIA SIGN
-        /* 51 */ "\u20B4",
+        /* 57 */ "\u20B4",
     };
 
     /* Language vi: Vietnamese */
@@ -3273,10 +3340,11 @@
         /* 10~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~50 */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null,
+        /* ~56 */
         // U+20AB: "₫" DONG SIGN
-        /* 51 */ "\u20AB",
+        /* 57 */ "\u20AB",
     };
 
     /* Language zu: Zulu */
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index c4f9601..9a96530 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -174,6 +174,7 @@
     public static final int CODE_SLASH = '/';
     public static final int CODE_COMMERCIAL_AT = '@';
     public static final int CODE_PLUS = '+';
+    public static final int CODE_PERCENT = '%';
     public static final int CODE_CLOSING_PARENTHESIS = ')';
     public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
     public static final int CODE_CLOSING_CURLY_BRACKET = '}';
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 642b3a4..2e9280c 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -16,8 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.latin.utils.StringUtils;
-
 import android.text.TextUtils;
 
 /**
@@ -85,8 +83,4 @@
     private boolean didCommitTypedWord() {
         return TextUtils.equals(mTypedWord, mCommittedWord);
     }
-
-    public static int getSeparatorLength(final String separatorString) {
-        return StringUtils.codePointCount(separatorString);
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ccdbd0d..e8ebf88 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -99,6 +99,7 @@
 import com.android.inputmethod.latin.utils.LatinImeLoggerUtils;
 import com.android.inputmethod.latin.utils.RecapitalizeStatus;
 import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
 import com.android.inputmethod.latin.utils.TextRange;
 import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
@@ -1261,9 +1262,7 @@
             final boolean needsInputViewShown) {
         // TODO: Modify this if we support suggestions with hard keyboard
         if (onEvaluateInputViewShown() && mSuggestionStripView != null) {
-            final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
-            final boolean inputViewShown = (mainKeyboardView != null)
-                    ? mainKeyboardView.isShown() : false;
+            final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes();
             final boolean shouldShowSuggestions = shown
                     && (needsInputViewShown ? inputViewShown : true);
             if (isFullscreenMode()) {
@@ -1329,7 +1328,7 @@
         if (visibleKeyboardView.isShown()) {
             // Note that the height of Emoji layout is the same as the height of the main keyboard
             // and the suggestion strip
-            if (mKeyboardSwitcher.isShowingEmojiKeyboard()
+            if (mKeyboardSwitcher.isShowingEmojiPalettes()
                     || mSuggestionStripView.getVisibility() == View.VISIBLE) {
                 visibleTopY -= suggestionsHeight;
             }
@@ -1503,6 +1502,7 @@
                 || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET
                 || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET
                 || codePoint == Constants.CODE_PLUS
+                || codePoint == Constants.CODE_PERCENT
                 || Character.getType(codePoint) == Character.OTHER_SYMBOL;
     }
 
@@ -1588,8 +1588,7 @@
             // relying on this behavior so we continue to support it for older apps.
             sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER);
         } else {
-            final String text = new String(new int[] { code }, 0, 1);
-            mConnection.commitText(text, text.length());
+            mConnection.commitText(StringUtils.newSingleCodePointString(code), 1);
         }
     }
 
@@ -1624,8 +1623,6 @@
         case Constants.CODE_DELETE:
             mSpaceState = SPACE_STATE_NONE;
             handleBackspace(spaceState);
-            mDeleteCount++;
-            mExpectingUpdateSelection = true;
             LatinImeLogger.logOnDelete(x, y);
             break;
         case Constants.CODE_SHIFT:
@@ -1712,7 +1709,8 @@
         mSpaceState = SPACE_STATE_NONE;
         final boolean didAutoCorrect;
         final SettingsValues settingsValues = mSettings.getCurrent();
-        if (settingsValues.isWordSeparator(primaryCode)) {
+        if (settingsValues.isWordSeparator(primaryCode)
+                || Character.getType(primaryCode) == Character.OTHER_SYMBOL) {
             didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
         } else {
             didAutoCorrect = false;
@@ -2052,6 +2050,10 @@
     }
 
     private void handleBackspace(final int spaceState) {
+        // We revert these in this method if the deletion doesn't happen.
+        mDeleteCount++;
+        mExpectingUpdateSelection = true;
+
         // In many cases, we may have to put the keyboard in auto-shift state again. However
         // we want to wait a few milliseconds before doing it to avoid the keyboard flashing
         // during key repeat.
@@ -2141,8 +2143,16 @@
                     // This should never happen.
                     Log.e(TAG, "Backspace when we don't know the selection position");
                 }
-                final int lengthToDelete = Character.isSupplementaryCodePoint(
-                        mConnection.getCodePointBeforeCursor()) ? 2 : 1;
+                final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
+                if (codePointBeforeCursor == Constants.NOT_A_CODE) {
+                    // Nothing to delete before the cursor. We have to revert the deletion states
+                    // that were updated at the beginning of this method.
+                    mDeleteCount--;
+                    mExpectingUpdateSelection = false;
+                    return;
+                }
+                final int lengthToDelete =
+                        Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
                 if (mAppWorkAroundsUtils.isBeforeJellyBean() ||
                         currentSettings.mInputAttributes.isTypeNull()) {
                     // There are two possible reasons to send a key event: either the field has
@@ -2161,12 +2171,16 @@
                             true /* shouldUncommitLogUnit */);
                 }
                 if (mDeleteCount > DELETE_ACCELERATE_AT) {
-                    final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
-                            mConnection.getCodePointBeforeCursor()) ? 2 : 1;
-                    mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
-                    if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
-                        ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
-                                true /* shouldUncommitLogUnit */);
+                    final int codePointBeforeCursorToDeleteAgain =
+                            mConnection.getCodePointBeforeCursor();
+                    if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
+                        final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
+                                codePointBeforeCursorToDeleteAgain) ? 2 : 1;
+                        mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
+                        if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+                            ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
+                                    true /* shouldUncommitLogUnit */);
+                        }
                     }
                 }
             }
@@ -2305,9 +2319,9 @@
             if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
                 mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart();
                 mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd();
-                mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd);
             }
         }
+        mConnection.finishComposingText();
         mRecapitalizeStatus.rotate();
         final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart;
         mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd);
@@ -2336,11 +2350,11 @@
         if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing
             if (currentSettings.mCorrectionEnabled) {
                 final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
-                        : new String(new int[] { primaryCode }, 0, 1);
+                        : StringUtils.newSingleCodePointString(primaryCode);
                 commitCurrentAutoCorrection(separator);
                 didAutoCorrect = true;
             } else {
-                commitTyped(new String(new int[]{primaryCode}, 0, 1));
+                commitTyped(StringUtils.newSingleCodePointString(primaryCode));
             }
         }
 
@@ -2979,8 +2993,8 @@
         final String originallyTypedWord = mLastComposedWord.mTypedWord;
         final String committedWord = mLastComposedWord.mCommittedWord;
         final int cancelLength = committedWord.length();
-        final int separatorLength = LastComposedWord.getSeparatorLength(
-                mLastComposedWord.mSeparatorString);
+        // We want java chars, not codepoints for the following.
+        final int separatorLength = mLastComposedWord.mSeparatorString.length();
         // TODO: should we check our saved separator against the actual contents of the text view?
         final int deleteLength = cancelLength + separatorLength;
         if (DEBUG) {
diff --git a/java/src/com/android/inputmethod/latin/about/AboutPreferences.java b/java/src/com/android/inputmethod/latin/about/AboutPreferences.java
new file mode 100644
index 0000000..f60b189
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/about/AboutPreferences.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 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.about;
+
+import android.app.Fragment;
+
+/**
+ * Dummy class of AboutPreferences. Never use this.
+ */
+public final class AboutPreferences extends Fragment {
+    private AboutPreferences() {
+        // Prevents this from being instantiated
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
index 9f7f502..fda97da 100644
--- a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java
@@ -60,7 +60,8 @@
                         0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG),
                         0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)),
                         new FormatOptions(version,
-                                0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE)));
+                                0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE),
+                                0 != (optionsFlags & FormatSpec.CONTAINS_TIMESTAMP_FLAG)));
         return header;
     }
 
diff --git a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
index 3362771..28da9ff 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java
@@ -22,6 +22,7 @@
 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
 import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
 import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -217,6 +218,25 @@
     }
 
     /**
+     * Converts a list of WeightedString to a list of PendingAttribute.
+     */
+    public static ArrayList<PendingAttribute> resolveBigramPositions(final DictUpdater dictUpdater,
+            final ArrayList<WeightedString> bigramStrings)
+                    throws IOException, UnsupportedFormatException {
+        if (bigramStrings == null) return CollectionUtils.newArrayList();
+        final ArrayList<PendingAttribute> bigrams = CollectionUtils.newArrayList();
+        for (final WeightedString bigram : bigramStrings) {
+            final int pos = dictUpdater.getTerminalPosition(bigram.mWord);
+            if (pos == FormatSpec.NOT_VALID_WORD) {
+                // TODO: figure out what is the correct thing to do here.
+            } else {
+                bigrams.add(new PendingAttribute(bigram.mFrequency, pos));
+            }
+        }
+        return bigrams;
+    }
+
+    /**
      * Insert a word into a binary dictionary.
      *
      * @param dictUpdater the dict updater.
@@ -238,18 +258,9 @@
             final ArrayList<WeightedString> shortcuts, final boolean isNotAWord,
             final boolean isBlackListEntry)
                     throws IOException, UnsupportedFormatException {
-        final ArrayList<PendingAttribute> bigrams = new ArrayList<PendingAttribute>();
+        final ArrayList<PendingAttribute> bigrams = resolveBigramPositions(dictUpdater,
+                bigramStrings);
         final DictBuffer dictBuffer = dictUpdater.getDictBuffer();
-        if (bigramStrings != null) {
-            for (final WeightedString bigram : bigramStrings) {
-                int position = dictUpdater.getTerminalPosition(bigram.mWord);
-                if (position == FormatSpec.NOT_VALID_WORD) {
-                    // TODO: figure out what is the correct thing to do here.
-                } else {
-                    bigrams.add(new PendingAttribute(bigram.mFrequency, position));
-                }
-            }
-        }
 
         final boolean isTerminal = true;
         final boolean hasBigrams = !bigrams.isEmpty();
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index 5a5d7af..6d58270 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -37,13 +37,15 @@
      * sion
      *
      * o |
-     * p | not used                                4 bits
-     * t | has bigrams ?                           1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG
-     * i | FRENCH_LIGATURE_PROCESSING_FLAG
-     * o | supports dynamic updates ?              1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE
-     * n | GERMAN_UMLAUT_PROCESSING_FLAG
-     * f |
-     * lags
+     * p | not used                                3 bits
+     * t | each unigram and bigram entry has a time stamp?
+     * i |                                         1 bit, 1 = yes, 0 = no : CONTAINS_TIMESTAMP_FLAG
+     * o | has bigrams ?                           1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG
+     * n | FRENCH_LIGATURE_PROCESSING_FLAG
+     * f | supports dynamic updates ?              1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE
+     * l | GERMAN_UMLAUT_PROCESSING_FLAG
+     * a |
+     * gs
      *
      * h |
      * e | size of the file header, 4bytes
@@ -211,6 +213,7 @@
     static final int SUPPORTS_DYNAMIC_UPDATE = 0x2;
     static final int FRENCH_LIGATURE_PROCESSING_FLAG = 0x4;
     static final int CONTAINS_BIGRAMS_FLAG = 0x8;
+    static final int CONTAINS_TIMESTAMP_FLAG = 0x10;
 
     // TODO: Make this value adaptative to content data, store it in the header, and
     // use it in the reading code.
@@ -263,6 +266,7 @@
     // These values are used only by version 4 or later.
     static final String TRIE_FILE_EXTENSION = ".trie";
     static final String FREQ_FILE_EXTENSION = ".freq";
+    static final String UNIGRAM_TIMESTAMP_FILE_EXTENSION = ".timestamp";
     // tat = Terminal Address Table
     static final String TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat";
     static final String BIGRAM_FILE_EXTENSION = ".bigram";
@@ -271,14 +275,20 @@
     static final String CONTENT_TABLE_FILE_SUFFIX = "_index";
     static final int FREQUENCY_AND_FLAGS_SIZE = 2;
     static final int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3;
+    static final int UNIGRAM_TIMESTAMP_SIZE = 4;
 
     // With the English main dictionary as of October 2013, the size of bigram address table is
     // is 584KB with the block size being 4.
     // This is 91% of that of full address table.
     static final int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 4;
-    static final int BIGRAM_CONTENT_COUNT = 1;
+    static final int BIGRAM_CONTENT_COUNT = 2;
     static final int BIGRAM_FREQ_CONTENT_INDEX = 0;
+    static final int BIGRAM_TIMESTAMP_CONTENT_INDEX = 1;
     static final String BIGRAM_FREQ_CONTENT_ID = "_freq";
+    static final String BIGRAM_TIMESTAMP_CONTENT_ID = "_timestamp";
+    static final int BIGRAM_TIMESTAMP_SIZE = 4;
+    static final int BIGRAM_COUNTER_SIZE = 1;
+    static final int BIGRAM_LEVEL_SIZE = 1;
 
     static final int SHORTCUT_CONTENT_COUNT = 1;
     static final int SHORTCUT_CONTENT_INDEX = 0;
@@ -321,6 +331,7 @@
         public final int mVersion;
         public final boolean mSupportsDynamicUpdate;
         public final boolean mHasTerminalId;
+        public final boolean mHasTimestamp;
         @UsedForTesting
         public FormatOptions(final int version) {
             this(version, false);
@@ -328,6 +339,11 @@
 
         @UsedForTesting
         public FormatOptions(final int version, final boolean supportsDynamicUpdate) {
+            this(version, supportsDynamicUpdate, false /* hasTimestamp */);
+        }
+
+        public FormatOptions(final int version, final boolean supportsDynamicUpdate,
+                final boolean hasTimestamp) {
             mVersion = version;
             if (version < FIRST_VERSION_WITH_DYNAMIC_UPDATE && supportsDynamicUpdate) {
                 throw new RuntimeException("Dynamic updates are only supported with versions "
@@ -335,6 +351,7 @@
             }
             mSupportsDynamicUpdate = supportsDynamicUpdate;
             mHasTerminalId = (version >= FIRST_VERSION_WITH_TERMINAL_ID);
+            mHasTimestamp = hasTimestamp;
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
index 5372907..734223e 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
@@ -153,8 +153,12 @@
         final File contentFile = new File(mDictDirectory, mDictDirectory.getName()
                 + FormatSpec.SHORTCUT_FILE_EXTENSION + FormatSpec.CONTENT_TABLE_FILE_SUFFIX
                 + FormatSpec.SHORTCUT_CONTENT_ID);
+        final File timestampsFile = new File(mDictDirectory, mDictDirectory.getName()
+                + FormatSpec.SHORTCUT_FILE_EXTENSION + FormatSpec.CONTENT_TABLE_FILE_SUFFIX
+                + FormatSpec.SHORTCUT_CONTENT_ID);
         mShortcutAddressTable = SparseTable.readFromFiles(lookupIndexFile,
-                new File[] { contentFile }, FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE);
+                new File[] { contentFile, timestampsFile },
+                FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE);
     }
 
     protected static class PtNodeReader extends AbstractDictDecoder.PtNodeReader {
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
index f9dcacf..5d5ab04 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
@@ -45,6 +45,7 @@
     private int mHeaderSize;
     private OutputStream mTrieOutStream;
     private OutputStream mFreqOutStream;
+    private OutputStream mUnigramTimestampOutStream;
     private OutputStream mTerminalAddressTableOutStream;
     private File mDictDir;
     private String mBaseFilename;
@@ -69,16 +70,16 @@
         private final File[] mContentFiles;
         protected final OutputStream[] mContentOutStreams;
 
-        public SparseTableContentWriter(final String name, final int contentCount,
-                final int initialCapacity, final int blockSize, final File baseDir,
-                final String[] contentFilenames, final String[] contentIds) {
+        public SparseTableContentWriter(final String name, final int initialCapacity,
+                final int blockSize, final File baseDir, final String[] contentFilenames,
+                final String[] contentIds) {
             if (contentFilenames.length != contentIds.length) {
                 throw new RuntimeException("The length of contentFilenames and the length of"
                         + " contentIds are different " + contentFilenames.length + ", "
                         + contentIds.length);
             }
-            mContentCount = contentCount;
-            mSparseTable = new SparseTable(initialCapacity, blockSize, contentCount);
+            mContentCount = contentFilenames.length;
+            mSparseTable = new SparseTable(initialCapacity, blockSize, mContentCount);
             mLookupTableFile = new File(baseDir, name + FormatSpec.LOOKUP_TABLE_FILE_SUFFIX);
             mAddressTableFiles = new File[mContentCount];
             mContentFiles = new File[mContentCount];
@@ -113,16 +114,40 @@
     }
 
     private static class BigramContentWriter extends SparseTableContentWriter {
+        private final boolean mWriteTimestamp;
 
         public BigramContentWriter(final String name, final int initialCapacity,
-                final File baseDir) {
-            super(name + FormatSpec.BIGRAM_FILE_EXTENSION, FormatSpec.BIGRAM_CONTENT_COUNT,
-                    initialCapacity, FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, baseDir,
-                    new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION },
-                    new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID });
+                final File baseDir, final boolean writeTimestamp) {
+            super(name + FormatSpec.BIGRAM_FILE_EXTENSION, initialCapacity,
+                    FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, baseDir,
+                    getContentFilenames(name, writeTimestamp), getContentIds(writeTimestamp));
+            mWriteTimestamp = writeTimestamp;
         }
 
-        public void writeBigramsForOneWord(final int terminalId,
+        private static String[] getContentFilenames(final String name,
+                final boolean writeTimestamp) {
+            final String[] contentFilenames;
+            if (writeTimestamp) {
+                contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION,
+                        name + FormatSpec.BIGRAM_FILE_EXTENSION };
+            } else {
+                contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION };
+            }
+            return contentFilenames;
+        }
+
+        private static String[] getContentIds(final boolean writeTimestamp) {
+            final String[] contentIds;
+            if (writeTimestamp) {
+                contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID,
+                        FormatSpec.BIGRAM_TIMESTAMP_CONTENT_ID };
+            } else {
+                contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID };
+            }
+            return contentIds;
+        }
+
+        public void writeBigramsForOneWord(final int terminalId, final int bigramCount,
                 final Iterator<WeightedString> bigramIterator, final FusionDictionary dict)
                         throws IOException {
             write(FormatSpec.BIGRAM_FREQ_CONTENT_INDEX, terminalId,
@@ -130,8 +155,16 @@
                         @Override
                         public void write(final OutputStream outStream) throws IOException {
                             writeBigramsForOneWordInternal(outStream, bigramIterator, dict);
-                        }
-            });
+                        }});
+            if (mWriteTimestamp) {
+                write(FormatSpec.BIGRAM_TIMESTAMP_CONTENT_INDEX, terminalId,
+                        new SparseTableContentWriterInterface() {
+                            @Override
+                            public void write(final OutputStream outStream) throws IOException {
+                                initBigramTimestampsCountersAndLevelsForOneWordInternal(outStream,
+                                        bigramCount);
+                            }});
+            }
         }
 
         private void writeBigramsForOneWordInternal(final OutputStream outStream,
@@ -151,13 +184,26 @@
                         FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE);
             }
         }
+
+        private void initBigramTimestampsCountersAndLevelsForOneWordInternal(
+                final OutputStream outStream, final int bigramCount) throws IOException {
+            for (int i = 0; i < bigramCount; ++i) {
+                // TODO: Figure out what initial values should be.
+                BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */,
+                        FormatSpec.BIGRAM_TIMESTAMP_SIZE);
+                BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */,
+                        FormatSpec.BIGRAM_COUNTER_SIZE);
+                BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */,
+                        FormatSpec.BIGRAM_LEVEL_SIZE);
+            }
+        }
     }
 
     private static class ShortcutContentWriter extends SparseTableContentWriter {
         public ShortcutContentWriter(final String name, final int initialCapacity,
                 final File baseDir) {
-            super(name + FormatSpec.SHORTCUT_FILE_EXTENSION, FormatSpec.SHORTCUT_CONTENT_COUNT,
-                    initialCapacity, FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, baseDir,
+            super(name + FormatSpec.SHORTCUT_FILE_EXTENSION, initialCapacity,
+                    FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, baseDir,
                     new String[] { name + FormatSpec.SHORTCUT_FILE_EXTENSION },
                     new String[] { FormatSpec.SHORTCUT_CONTENT_ID });
         }
@@ -193,18 +239,20 @@
         mDictDir = new File(mDictPlacedDir, mBaseFilename);
         final File trieFile = new File(mDictDir, mBaseFilename + FormatSpec.TRIE_FILE_EXTENSION);
         final File freqFile = new File(mDictDir, mBaseFilename + FormatSpec.FREQ_FILE_EXTENSION);
+        final File timestampFile = new File(mDictDir,
+                mBaseFilename + FormatSpec.UNIGRAM_TIMESTAMP_FILE_EXTENSION);
         final File terminalAddressTableFile = new File(mDictDir,
                 mBaseFilename + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION);
         if (!mDictDir.isDirectory()) {
             if (mDictDir.exists()) mDictDir.delete();
             mDictDir.mkdirs();
         }
-        if (!trieFile.exists()) trieFile.createNewFile();
-        if (!freqFile.exists()) freqFile.createNewFile();
-        if (!terminalAddressTableFile.exists()) terminalAddressTableFile.createNewFile();
         mTrieOutStream = new FileOutputStream(trieFile);
         mFreqOutStream = new FileOutputStream(freqFile);
         mTerminalAddressTableOutStream = new FileOutputStream(terminalAddressTableFile);
+        if (formatOptions.mHasTimestamp) {
+            mUnigramTimestampOutStream = new FileOutputStream(timestampFile);
+        }
     }
 
     private void close() throws IOException {
@@ -218,6 +266,9 @@
             if (mTerminalAddressTableOutStream != null) {
                 mTerminalAddressTableOutStream.close();
             }
+            if (mUnigramTimestampOutStream != null) {
+                mUnigramTimestampOutStream.close();
+            }
         } finally {
             mTrieOutStream = null;
             mFreqOutStream = null;
@@ -257,7 +308,11 @@
         if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes);
 
         writeTerminalData(flatNodes, terminalCount);
-        mBigramWriter = new BigramContentWriter(mBaseFilename, terminalCount, mDictDir);
+        if (formatOptions.mHasTimestamp) {
+            initUnigramTimestamps(terminalCount);
+        }
+        mBigramWriter = new BigramContentWriter(mBaseFilename, terminalCount, mDictDir,
+                formatOptions.mHasTimestamp);
         writeBigrams(flatNodes, dict);
         mShortcutWriter = new ShortcutContentWriter(mBaseFilename, terminalCount, mDictDir);
         writeShortcuts(flatNodes);
@@ -348,7 +403,7 @@
         for (final PtNodeArray nodeArray : flatNodes) {
             for (final PtNode ptNode : nodeArray.mData) {
                 if (ptNode.mBigrams != null) {
-                    mBigramWriter.writeBigramsForOneWord(ptNode.mTerminalId,
+                    mBigramWriter.writeBigramsForOneWord(ptNode.mTerminalId, ptNode.mBigrams.size(),
                             ptNode.mBigrams.iterator(), dict);
                 }
             }
@@ -408,4 +463,11 @@
         mFreqOutStream.write(freqBuf);
         mTerminalAddressTableOutStream.write(terminalAddressTableBuf);
     }
+
+    private void initUnigramTimestamps(final int terminalCount) throws IOException {
+        // Initial value of time stamps for each word is 0.
+        final byte[] unigramTimestampBuf =
+                new byte[terminalCount * FormatSpec.UNIGRAM_TIMESTAMP_SIZE];
+        mUnigramTimestampOutStream.write(unigramTimestampBuf);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsActivity.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsActivity.java
index ef6ab2a..a23e377 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsActivity.java
@@ -21,6 +21,7 @@
 import android.preference.PreferenceActivity;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.FragmentUtils;
 
 public final class DebugSettingsActivity extends PreferenceActivity {
     private static final String DEFAULT_FRAGMENT = DebugSettings.class.getName();
@@ -42,6 +43,6 @@
     // TODO: Uncomment the override annotation once we start using SDK version 19.
     // @Override
     public boolean isValidFragment(String fragmentName) {
-        return fragmentName.equals(DEFAULT_FRAGMENT);
+        return FragmentUtils.isValidFragment(fragmentName);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 1a0fecc..dc005bb 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -101,6 +101,7 @@
     // Emoji
     public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
     public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
+    public static final String PREF_LAST_SHOWN_EMOJI_CATEGORY_ID = "last_shown_emoji_category_id";
 
     private Resources mRes;
     private SharedPreferences mPrefs;
@@ -383,15 +384,25 @@
         return prefs.getString(PREF_EMOJI_RECENT_KEYS, "");
     }
 
-    public static void writeEmojiCategoryLastTypedId(
-            final SharedPreferences prefs, final int category, final int id) {
-        final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
-        prefs.edit().putInt(key, id).apply();
+    public static void writeLastTypedEmojiCategoryPageId(
+            final SharedPreferences prefs, final int categoryId, final int categoryPageId) {
+        final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + categoryId;
+        prefs.edit().putInt(key, categoryPageId).apply();
     }
 
-    public static int readEmojiCategoryLastTypedId(
-            final SharedPreferences prefs, final int category) {
-        final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+    public static int readLastTypedEmojiCategoryPageId(
+            final SharedPreferences prefs, final int categoryId) {
+        final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + categoryId;
         return prefs.getInt(key, 0);
     }
+
+    public static void writeLastShownEmojiCategoryId(
+            final SharedPreferences prefs, final int categoryId) {
+        prefs.edit().putInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID, categoryId).apply();
+    }
+
+    public static int readLastShownEmojiCategoryId(
+            final SharedPreferences prefs, final int defValue) {
+        return prefs.getInt(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID, defValue);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
index ad68f8c..c899507 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.settings;
 
+import com.android.inputmethod.latin.utils.FragmentUtils;
+
 import android.content.Intent;
 import android.preference.PreferenceActivity;
 
@@ -36,6 +38,6 @@
     // TODO: Uncomment the override annotation once we start using SDK version 19.
     // @Override
     public boolean isValidFragment(String fragmentName) {
-        return fragmentName.equals(DEFAULT_FRAGMENT);
+        return FragmentUtils.isValidFragment(fragmentName);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
index aba5637..df9a761 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.spellcheck;
 
+import com.android.inputmethod.latin.utils.FragmentUtils;
+
 import android.content.Intent;
 import android.os.Bundle;
 import android.preference.PreferenceActivity;
@@ -42,6 +44,6 @@
     // TODO: Uncomment the override annotation once we start using SDK version 19.
     // @Override
     public boolean isValidFragment(String fragmentName) {
-        return fragmentName.equals(DEFAULT_FRAGMENT);
+        return FragmentUtils.isValidFragment(fragmentName);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 8d2689a..faa5560 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -302,18 +302,19 @@
         final int countInStrip = mSuggestionsCountInStrip;
         setupWordViewsTextAndColor(suggestedWords, countInStrip);
         final TextView centerWordView = mWordViews.get(mCenterPositionInStrip);
-        final int stripWidth = placerView.getWidth();
-        final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth);
+        final int availableStripWidth = placerView.getWidth()
+                - placerView.getPaddingRight() - placerView.getPaddingLeft();
+        final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, availableStripWidth);
         if (getTextScaleX(centerWordView.getText(), centerWidth, centerWordView.getPaint())
                 < MIN_TEXT_XSCALE) {
             // Layout only the most relevant suggested word at the center of the suggestion strip
             // by consolidating all slots in the strip.
             mMoreSuggestionsAvailable = (suggestedWords.size() > 1);
-            layoutWord(mCenterPositionInStrip, stripWidth);
+            layoutWord(mCenterPositionInStrip, availableStripWidth - mPadding);
             stripView.addView(centerWordView);
             setLayoutWeight(centerWordView, 1.0f, ViewGroup.LayoutParams.MATCH_PARENT);
             if (SuggestionStripView.DBG) {
-                layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth);
+                layoutDebugInfo(mCenterPositionInStrip, placerView, availableStripWidth);
             }
             return;
         }
@@ -328,7 +329,7 @@
                 x += divider.getMeasuredWidth();
             }
 
-            final int width = getSuggestionWidth(positionInStrip, stripWidth);
+            final int width = getSuggestionWidth(positionInStrip, availableStripWidth);
             final TextView wordView = layoutWord(positionInStrip, width);
             stripView.addView(wordView);
             setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
@@ -373,9 +374,9 @@
         // Disable this suggestion if the suggestion is null or empty.
         wordView.setEnabled(!TextUtils.isEmpty(word));
         final CharSequence text = getEllipsizedText(word, width, wordView.getPaint());
-        final float scaleX = wordView.getTextScaleX();
+        final float scaleX = getTextScaleX(word, width, wordView.getPaint());
         wordView.setText(text); // TextView.setText() resets text scale x to 1.0.
-        wordView.setTextScaleX(scaleX);
+        wordView.setTextScaleX(Math.max(scaleX, MIN_TEXT_XSCALE));
         return wordView;
     }
 
@@ -545,8 +546,24 @@
 
         // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To
         // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
-        final CharSequence ellipsized = TextUtils.ellipsize(
-                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
+        final float upscaledWidth = maxWidth / MIN_TEXT_XSCALE;
+        CharSequence ellipsized = TextUtils.ellipsize(
+                text, paint, upscaledWidth, TextUtils.TruncateAt.MIDDLE);
+        // For an unknown reason, ellipsized seems to return a text that does indeed fit inside the
+        // passed width according to paint.measureText, but not according to paint.getTextWidths.
+        // But when rendered, the text seems to actually take up as many pixels as returned by
+        // paint.getTextWidths, hence problem.
+        // To save this case, we compare the measured size of the new text, and if it's too much,
+        // try it again removing the difference. This may still give a text too long by one or
+        // two pixels so we take an additional 2 pixels cushion and call it a day.
+        // TODO: figure out why getTextWidths and measureText don't agree with each other, and
+        // remove the following code.
+        final float ellipsizedTextWidth = getTextWidth(ellipsized, paint);
+        if (upscaledWidth <= ellipsizedTextWidth) {
+            ellipsized = TextUtils.ellipsize(
+                    text, paint, upscaledWidth - (ellipsizedTextWidth - upscaledWidth) - 2,
+                    TextUtils.TruncateAt.MIDDLE);
+        }
         paint.setTextScaleX(MIN_TEXT_XSCALE);
         return ellipsized;
     }
diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
index ff332cd..d87f6f3 100644
--- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java
@@ -25,6 +25,7 @@
 import android.text.TextUtils;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 
@@ -143,12 +144,17 @@
         // from the current users. So, you should be really careful to change it.
         final int subtypeId = getInputMethodSubtypeId(nameId, localeString, layoutExtraValue,
                 additionalSubtypeExtraValue);
-        // TODO: Use InputMethodSubtypeBuilder once we use SDK version 19.
-        return new InputMethodSubtype(nameId, R.drawable.ic_ime_switcher_dark,
-                localeString, KEYBOARD_MODE, layoutExtraValue + "," + additionalSubtypeExtraValue
-                        + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
-                        + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE, false, false,
-                        subtypeId);
+        final String extraValue;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue
+                    + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
+                    + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
+        } else {
+            extraValue = layoutExtraValue + "," + additionalSubtypeExtraValue;
+        }
+        return InputMethodSubtypeCompatUtils.newInputMethodSubtype(nameId,
+                R.drawable.ic_ime_switcher_dark, localeString, KEYBOARD_MODE, extraValue,
+                false, false, subtypeId);
     }
 
     private static int getInputMethodSubtypeId(int nameId, String localeString,
diff --git a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
new file mode 100644
index 0000000..ee2b97b
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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.utils;
+
+import com.android.inputmethod.dictionarypack.DictionarySettingsFragment;
+import com.android.inputmethod.latin.about.AboutPreferences;
+import com.android.inputmethod.latin.settings.AdditionalSubtypeSettings;
+import com.android.inputmethod.latin.settings.DebugSettings;
+import com.android.inputmethod.latin.settings.SettingsFragment;
+import com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment;
+import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordFragment;
+import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
+import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker;
+import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
+import com.android.inputmethod.research.FeedbackFragment;
+
+import java.util.HashSet;
+
+public class FragmentUtils {
+    private static final HashSet<String> sLatinImeFragments = new HashSet<String>();
+    static {
+        sLatinImeFragments.add(DictionarySettingsFragment.class.getName());
+        sLatinImeFragments.add(AboutPreferences.class.getName());
+        sLatinImeFragments.add(AdditionalSubtypeSettings.class.getName());
+        sLatinImeFragments.add(DebugSettings.class.getName());
+        sLatinImeFragments.add(SettingsFragment.class.getName());
+        sLatinImeFragments.add(SpellCheckerSettingsFragment.class.getName());
+        sLatinImeFragments.add(UserDictionaryAddWordFragment.class.getName());
+        sLatinImeFragments.add(UserDictionaryList.class.getName());
+        sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName());
+        sLatinImeFragments.add(UserDictionarySettings.class.getName());
+        sLatinImeFragments.add(FeedbackFragment.class.getName());
+    }
+
+    public static boolean isValidFragment(String fragmentName) {
+        return sLatinImeFragments.contains(fragmentName);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 121aecf..a365483 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -48,6 +48,16 @@
         return text.codePointCount(0, text.length());
     }
 
+    public static String newSingleCodePointString(int codePoint) {
+        if (Character.charCount(codePoint) == 1) {
+            // Optimization: avoid creating an temporary array for characters that are
+            // represented by a single char value
+            return String.valueOf((char) codePoint);
+        }
+        // For surrogate pair
+        return new String(Character.toChars(codePoint));
+    }
+
     public static boolean containsInArray(final String text, final String[] array) {
         for (final String element : array) {
             if (text.equals(element)) return true;
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 102a41b..fdbe81a 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -197,7 +197,9 @@
     //  es_US spanish F  Español (EE.UU.)        exception
     //  fr    azerty  F  Français
     //  fr_CA qwerty  F  Français (Canada)
+    //  fr_CH swiss   F  Français (Suisse)
     //  de    qwertz  F  Deutsch
+    //  de_CH swiss   T  Deutsch (Schweiz)
     //  zz    qwerty  F  No language (QWERTY)    in system locale
     //  fr    qwertz  T  Français (QWERTZ)
     //  de    qwerty  T  Deutsch (QWERTY)
@@ -298,7 +300,9 @@
     //  es_US spanish F  Es  Español   Español (EE.UU.)       exception
     //  fr    azerty  F  Fr  Français  Français
     //  fr_CA qwerty  F  Fr  Français  Français (Canada)
+    //  fr_CH swiss   F  Fr  Français  Français (Suisse)
     //  de    qwertz  F  De  Deutsch   Deutsch
+    //  de_CH swiss   T  De  Deutsch   Deutsch (Schweiz)
     //  zz    qwerty  F      QWERTY    QWERTY
     //  fr    qwertz  T  Fr  Français  Français
     //  de    qwerty  T  De  Deutsch   Deutsch
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 6bc8b9d..8ad8689 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -183,7 +183,7 @@
         final String[] STRINGS_TO_TYPE =
                 new String[] { "this   ", "a+  ", "\u1F607  ", "..  ", ")  ", "(  ", "%  " };
         final String[] EXPECTED_RESULTS =
-                new String[] { "this.  ", "a+. ", "\u1F607. ", "..  ", "). ", "(  ", "%  " };
+                new String[] { "this.  ", "a+. ", "\u1F607. ", "..  ", "). ", "(  ", "%. " };
         for (int i = 0; i < STRINGS_TO_TYPE.length; ++i) {
             mEditText.setText("");
             type(STRINGS_TO_TYPE[i]);
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 0189b33..32c07e1 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -80,6 +80,9 @@
             new FormatSpec.FormatOptions(4, false /* supportsDynamicUpdate */);
     private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE =
             new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */);
+    private static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP =
+            new FormatSpec.FormatOptions(4, true /* supportsDynamicUpdate */,
+                    true /* hasTimestamp */);
 
     private static final String TEST_DICT_FILE_EXTENSION = ".testDict";
 
@@ -363,6 +366,7 @@
         runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
         runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
+        runReadAndWriteTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         for (final String result : results) {
             Log.d(TAG, result);
@@ -377,6 +381,7 @@
         runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
         runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
+        runReadAndWriteTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         for (final String result : results) {
             Log.d(TAG, result);
@@ -508,6 +513,8 @@
         runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
         runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
+        runReadUnigramsAndBigramsTests(results, USE_BYTE_BUFFER,
+                VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         for (final String result : results) {
             Log.d(TAG, result);
@@ -522,6 +529,8 @@
         runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
         runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
+        runReadUnigramsAndBigramsTests(results, USE_BYTE_ARRAY,
+                VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         for (final String result : results) {
             Log.d(TAG, result);
@@ -634,12 +643,14 @@
         runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION3_WITH_DYNAMIC_UPDATE);
         runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE);
+        runGetTerminalPositionTests(USE_BYTE_ARRAY, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION2);
         runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITHOUT_DYNAMIC_UPDATE);
         runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION3_WITH_DYNAMIC_UPDATE);
         runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITHOUT_DYNAMIC_UPDATE);
         runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE);
+        runGetTerminalPositionTests(USE_BYTE_BUFFER, VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP);
 
         for (final String result : results) {
             Log.d(TAG, result);
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index 856b2db..ccdd567 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -41,7 +41,9 @@
     InputMethodSubtype ES_US;
     InputMethodSubtype FR;
     InputMethodSubtype FR_CA;
+    InputMethodSubtype FR_CH;
     InputMethodSubtype DE;
+    InputMethodSubtype DE_CH;
     InputMethodSubtype ZZ;
     InputMethodSubtype DE_QWERTY;
     InputMethodSubtype FR_QWERTZ;
@@ -70,8 +72,12 @@
                 Locale.FRENCH.toString(), "azerty");
         FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
                 Locale.CANADA_FRENCH.toString(), "qwerty");
+        FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "fr_CH", "swiss");
         DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
                 Locale.GERMAN.toString(), "qwertz");
+        DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "de_CH", "swiss");
         ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
                 SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
         DE_QWERTY = AdditionalSubtypeUtils.createAdditionalSubtype(
@@ -112,7 +118,9 @@
         assertEquals("es_US", "spanish", SubtypeLocaleUtils.getKeyboardLayoutSetName(ES_US));
         assertEquals("fr   ", "azerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR));
         assertEquals("fr_CA", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CA));
+        assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH));
         assertEquals("de   ", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE));
+        assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH));
         assertEquals("zz   ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ));
     }
 
@@ -125,7 +133,9 @@
     //  es_US spanish F  Spanish (US)            exception
     //  fr    azerty  F  French
     //  fr_CA qwerty  F  French (Canada)
+    //  fr_CH swiss   F  French (Switzerland)
     //  de    qwertz  F  German
+    //  de_CH swiss   F  German (Switzerland)
     //  zz    qwerty  F  Alphabet (QWERTY)
     //  fr    qwertz  T  French (QWERTZ)
     //  de    qwerty  T  German (QWERTY)
@@ -148,8 +158,12 @@
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR));
                 assertEquals("fr_CA", "French (Canada)",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA));
+                assertEquals("fr_CH", "French (Switzerland)",
+                        SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH));
                 assertEquals("de   ", "German",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE));
+                assertEquals("de_CH", "German (Switzerland)",
+                        SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH));
                 assertEquals("zz   ", "Alphabet (QWERTY)",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ));
                 return null;
@@ -189,7 +203,9 @@
     //  es_US spanish F  Espagnol (États-Unis)            exception
     //  fr    azerty  F  Français
     //  fr_CA qwerty  F  Français (Canada)
+    //  fr_CH swiss   F  Français (Suisse)
     //  de    qwertz  F  Allemand
+    //  de_CH swiss   F  Allemand (Suisse)
     //  zz    qwerty  F  Aucune langue (QWERTY)
     //  fr    qwertz  T  Français (QWERTZ)
     //  de    qwerty  T  Allemand (QWERTY)
@@ -212,8 +228,12 @@
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR));
                 assertEquals("fr_CA", "Français (Canada)",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CA));
+                assertEquals("fr_CH", "Français (Suisse)",
+                        SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(FR_CH));
                 assertEquals("de   ", "Allemand",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE));
+                assertEquals("de_CH", "Allemand (Suisse)",
+                        SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH));
                 assertEquals("zz   ", "Alphabet latin (QWERTY)",
                         SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ));
                 return null;
@@ -300,7 +320,9 @@
     //  es_US spanish F  Es  Español   Español (EE.UU.)       exception
     //  fr    azerty  F  Fr  Français  Français
     //  fr_CA qwerty  F  Fr  Français  Français (Canada)
+    //  fr_CH swiss   F  Fr  Français  Français (Suisse)
     //  de    qwertz  F  De  Deutsch   Deutsch
+    //  de_CH swiss   F  De  Deutsch   Deutsch (Schweiz)
     //  zz    qwerty  F      QWERTY    QWERTY
     //  fr    qwertz  T  Fr  Français  Français
     //  de    qwerty  T  De  Deutsch   Deutsch
@@ -317,7 +339,11 @@
             assertEquals("fr   ", "Français",     SubtypeLocaleUtils.getFullDisplayName(FR));
             assertEquals("fr_CA", "Français (Canada)",
                     SubtypeLocaleUtils.getFullDisplayName(FR_CA));
+            assertEquals("fr_CH", "Français (Suisse)",
+                    SubtypeLocaleUtils.getFullDisplayName(FR_CH));
             assertEquals("de   ", "Deutsch",      SubtypeLocaleUtils.getFullDisplayName(DE));
+            assertEquals("de_CH", "Deutsch (Schweiz)",
+                    SubtypeLocaleUtils.getFullDisplayName(DE_CH));
             assertEquals("zz   ", "QWERTY",       SubtypeLocaleUtils.getFullDisplayName(ZZ));
 
             assertEquals("en_US", "English",  SubtypeLocaleUtils.getMiddleDisplayName(EN_US));
@@ -325,7 +351,9 @@
             assertEquals("es_US", "Español",  SubtypeLocaleUtils.getMiddleDisplayName(ES_US));
             assertEquals("fr   ", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR));
             assertEquals("fr_CA", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CA));
+            assertEquals("fr_CH", "Français", SubtypeLocaleUtils.getMiddleDisplayName(FR_CH));
             assertEquals("de   ", "Deutsch",  SubtypeLocaleUtils.getMiddleDisplayName(DE));
+            assertEquals("de_CH", "Deutsch",  SubtypeLocaleUtils.getMiddleDisplayName(DE_CH));
             assertEquals("zz   ", "QWERTY",   SubtypeLocaleUtils.getMiddleDisplayName(ZZ));
 
             assertEquals("en_US", "En", SubtypeLocaleUtils.getShortDisplayName(EN_US));
@@ -333,7 +361,9 @@
             assertEquals("es_US", "Es", SubtypeLocaleUtils.getShortDisplayName(ES_US));
             assertEquals("fr   ", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR));
             assertEquals("fr_CA", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_CA));
+            assertEquals("fr_CH", "Fr", SubtypeLocaleUtils.getShortDisplayName(FR_CH));
             assertEquals("de   ", "De", SubtypeLocaleUtils.getShortDisplayName(DE));
+            assertEquals("de_CH", "De", SubtypeLocaleUtils.getShortDisplayName(DE_CH));
             assertEquals("zz   ", "",   SubtypeLocaleUtils.getShortDisplayName(ZZ));
             return null;
         }
diff --git a/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml
index 9dc8717..bb8bb72 100644
--- a/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-de/donottranslate-more-keys.xml
@@ -55,6 +55,18 @@
     <!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
          U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE -->
     <string name="more_keys_for_n">&#x00F1;,&#x0144;</string>
+    <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS -->
+    <string name="keylabel_for_swiss_row1_11">&#x00FC;</string>
+    <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE -->
+    <string name="more_keys_for_swiss_row1_11">&#x00E8;</string>
+    <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS -->
+    <string name="keylabel_for_swiss_row2_10">&#x00F6;</string>
+    <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE -->
+    <string name="more_keys_for_swiss_row2_10">&#x00E9;</string>
+    <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS -->
+    <string name="keylabel_for_swiss_row2_11">&#x00E4;</string>
+    <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE -->
+    <string name="more_keys_for_swiss_row2_11">&#x00E0;</string>
     <string name="single_quotes">!text/single_9qm_lqm</string>
     <string name="double_quotes">!text/double_9qm_lqm</string>
     <string name="single_angle_quotes">!text/single_raqm_laqm</string>
diff --git a/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml
index 7b11a18..6656776 100644
--- a/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-fr/donottranslate-more-keys.xml
@@ -65,4 +65,16 @@
     <string name="more_keys_for_c">&#x00E7;,&#x0107;,&#x010D;</string>
     <!-- U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS -->
     <string name="more_keys_for_y">%,&#x00FF;</string>
+    <!-- U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE -->
+    <string name="keylabel_for_swiss_row1_11">&#x00E8;</string>
+    <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS -->
+    <string name="more_keys_for_swiss_row1_11">&#x00FC;</string>
+    <!-- U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE -->
+    <string name="keylabel_for_swiss_row2_10">&#x00E9;</string>
+    <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS -->
+    <string name="more_keys_for_swiss_row2_10">&#x00F6;</string>
+    <!-- U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE -->
+    <string name="keylabel_for_swiss_row2_11">&#x00E0;</string>
+    <!-- U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS -->
+    <string name="more_keys_for_swiss_row2_11">&#x00E4;</string>
 </resources>
diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
index 39ecfab..008ef30 100644
--- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
@@ -63,6 +63,12 @@
     <string name="keylabel_for_south_slavic_row3_8"></string>
     <string name="more_keys_for_cyrillic_ie"></string>
     <string name="more_keys_for_cyrillic_i"></string>
+    <string name="keylabel_for_swiss_row1_11"></string>
+    <string name="keylabel_for_swiss_row2_10"></string>
+    <string name="keylabel_for_swiss_row2_11"></string>
+    <string name="more_keys_for_swiss_row1_11"></string>
+    <string name="more_keys_for_swiss_row2_10"></string>
+    <string name="more_keys_for_swiss_row2_11"></string>
     <!-- Label for "switch to alphabetic" key. -->
     <string name="label_to_alpha_key">ABC</string>
     <string name="single_quotes">!text/single_lqm_rqm</string>
@@ -77,7 +83,7 @@
     <string name="more_keys_for_currency_dollar">&#x00A2;,&#x00A3;,&#x20AC;,&#x00A5;,&#x20B1;</string>
     <string name="keylabel_for_currency">$</string>
     <string name="more_keys_for_currency">$,&#x00A2;,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
-    <string name="more_keys_for_punctuation">"!fixedColumnOrder!3,!,\\,,\?,:,;,\@"</string>
+    <string name="more_keys_for_punctuation">"!fixedColumnOrder!4,#,!,\\,,\?,-,:,',\@"</string>
     <!-- U+2020: "†" DAGGER
          U+2021: "‡" DOUBLE DAGGER
          U+2605: "★" BLACK STAR -->