diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index cc4c744411a780828b2b3ee62d69ebc23ac88e1e..e0eecfc7d842f4eece27a65bf5af2f9b90fb690e 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -1,8 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.inputmethod.latin">
 
-    <original-package android:name="com.android.inputmethod.latin" />
-
     <uses-permission android:name="android.permission.VIBRATE"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
diff --git a/java/proguard.flags b/java/proguard.flags
index 9096855e8fd37801b6ad3a2197248b68da9907b2..914bd7595eb1d6c7f02c6bcbb80d394fbccd011c 100644
--- a/java/proguard.flags
+++ b/java/proguard.flags
@@ -14,3 +14,11 @@
   void waitUntilUpdateDBDone();
   void waitForDictionaryLoading();
 }
+
+-keep class com.android.inputmethod.latin.AutoCorrection {
+  java.lang.CharSequence getAutoCorrectionWord();
+}
+
+-keep class com.android.inputmethod.latin.Utils {
+  boolean equalsIgnoreCase(...);
+}
diff --git a/java/res/drawable-hdpi/key_hint_comma_holo.9.png b/java/res/drawable-hdpi/key_hint_comma_holo.9.png
index 47ae5efafa82dc75c126db683265e82476c2197b..da0d6fdd661210d38c1496be23f1bd4bf8af4c2b 100644
Binary files a/java/res/drawable-hdpi/key_hint_comma_holo.9.png and b/java/res/drawable-hdpi/key_hint_comma_holo.9.png differ
diff --git a/java/res/drawable-hdpi/key_hint_comma_large_holo.9.png b/java/res/drawable-hdpi/key_hint_comma_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f2f707625ecd210bab5b017131bfcafe82e6714
Binary files /dev/null and b/java/res/drawable-hdpi/key_hint_comma_large_holo.9.png differ
diff --git a/java/res/drawable-hdpi/key_hint_minus_holo.9.png b/java/res/drawable-hdpi/key_hint_minus_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c34ef90b5f11df19a8f40710f891908676e260d
Binary files /dev/null and b/java/res/drawable-hdpi/key_hint_minus_holo.9.png differ
diff --git a/java/res/drawable-hdpi/key_hint_minus_large_holo.9.png b/java/res/drawable-hdpi/key_hint_minus_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..0df056ee13cf76dd59ef46413a4b066034f6ca7e
Binary files /dev/null and b/java/res/drawable-hdpi/key_hint_minus_large_holo.9.png differ
diff --git a/java/res/drawable-hdpi/key_hint_underscore_holo.9.png b/java/res/drawable-hdpi/key_hint_underscore_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4f271918d0af626179838fbe20f56560cb1d58c
Binary files /dev/null and b/java/res/drawable-hdpi/key_hint_underscore_holo.9.png differ
diff --git a/java/res/drawable-hdpi/key_hint_underscore_large_holo.9.png b/java/res/drawable-hdpi/key_hint_underscore_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..dad34fc72dc3c9c83dd94af2407030bcada31378
Binary files /dev/null and b/java/res/drawable-hdpi/key_hint_underscore_large_holo.9.png differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_settings_holo.png b/java/res/drawable-hdpi/sym_keyboard_settings_holo.png
index b3af0c638c12ae5fcbfaa2ac087d4aa2ba860fb0..471bd0b86600ede4bc84bf9c4c39c307ca0e199f 100644
Binary files a/java/res/drawable-hdpi/sym_keyboard_settings_holo.png and b/java/res/drawable-hdpi/sym_keyboard_settings_holo.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_comma_holo.9.png b/java/res/drawable-land-hdpi/key_hint_comma_holo.9.png
index 9ab5dadacefdf138ea6528aee44bebc9b429151c..da0d6fdd661210d38c1496be23f1bd4bf8af4c2b 100644
Binary files a/java/res/drawable-land-hdpi/key_hint_comma_holo.9.png and b/java/res/drawable-land-hdpi/key_hint_comma_holo.9.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_comma_large_holo.9.png b/java/res/drawable-land-hdpi/key_hint_comma_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f2f707625ecd210bab5b017131bfcafe82e6714
Binary files /dev/null and b/java/res/drawable-land-hdpi/key_hint_comma_large_holo.9.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_minus_holo.9.png b/java/res/drawable-land-hdpi/key_hint_minus_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c34ef90b5f11df19a8f40710f891908676e260d
Binary files /dev/null and b/java/res/drawable-land-hdpi/key_hint_minus_holo.9.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_minus_large_holo.9.png b/java/res/drawable-land-hdpi/key_hint_minus_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..0df056ee13cf76dd59ef46413a4b066034f6ca7e
Binary files /dev/null and b/java/res/drawable-land-hdpi/key_hint_minus_large_holo.9.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_underscore_holo.9.png b/java/res/drawable-land-hdpi/key_hint_underscore_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4f271918d0af626179838fbe20f56560cb1d58c
Binary files /dev/null and b/java/res/drawable-land-hdpi/key_hint_underscore_holo.9.png differ
diff --git a/java/res/drawable-land-hdpi/key_hint_underscore_large_holo.9.png b/java/res/drawable-land-hdpi/key_hint_underscore_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..dad34fc72dc3c9c83dd94af2407030bcada31378
Binary files /dev/null and b/java/res/drawable-land-hdpi/key_hint_underscore_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_at_holo.9.png b/java/res/drawable-land-mdpi/key_hint_at_holo.9.png
index d1ea313c0277cfbca3c1f4a0db0e28bb46236413..5b946ff9bfbb7228f9707f3da06dffce38d3d717 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_at_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_at_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png
index 786bbc5de05e15b14d4a39e54fb263882ae10b18..852f899edb1bb17265043cc4ab1f7f186b331988 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png b/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png
index 12ce26758ea3c92fcad2179193f841a67519428e..1d9346e6ffb277eb5d5fd4ff1598603ca26f6a23 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png
index a51bada576ddaf37e04caacba783be324d10d780..17e9091b4ffb6b28d1e10ea7cfb4a1124d3474db 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png b/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png
index f9391623b4d9e4ecaa38341d1daa816e9bbc6c1c..c2a913c0459c070793a700fb3ef856393d99c447 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_comma_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_comma_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..846f213f1cdb2ed07c519214ff9d7cb811236fbc
Binary files /dev/null and b/java/res/drawable-land-mdpi/key_hint_comma_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png b/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png
index a14623dc0ab63790f83948f60a1ebc8b6f1f7789..ce8e8de431ca41c3353d2d2f06b1b6e437992282 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png
index ce52d3a0246628dca095573018f68c450e3f5ba0..035dcf85d46f4857ecbee16ac67ae8e4500a08c9 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_minus_holo.9.png b/java/res/drawable-land-mdpi/key_hint_minus_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..e59a315877b9aa4762bc5f0253e8d82a9188d8c2
Binary files /dev/null and b/java/res/drawable-land-mdpi/key_hint_minus_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_minus_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_minus_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..52c28dd87ba6ac0f884d63509eb842af5403021f
Binary files /dev/null and b/java/res/drawable-land-mdpi/key_hint_minus_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png b/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png
index a80c03169d4168324e15c36e6d594fc5ea5d4503..931390b45150d1a6db41da5a77186ba21882cfd2 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png
index e8daaf0855dc101c96169b4ec838da70c5293510..e6f9f8a9c685b0c13c238434933f5a7bf71deb5a 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_question_holo.9.png b/java/res/drawable-land-mdpi/key_hint_question_holo.9.png
index 2b71d744fab8f4e97ca8cff05b2632943d2a37fc..6cbeb59932817bc5eec3e8a0917a12f07c268189 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_question_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_question_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png
index 041336832e49c7cef18e88c370ebf51ffb7adb15..bfd58de099492f7f4cf459789d4fba20e02ec1e0 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png b/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png
index 486e5e19d2074266d40abaf5a0925a9ee8a83721..3b361b71c86eda9768b6e19b221d50c9de3f90a3 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png
index 49770314f733083844575e33dee01e57b9c44a52..2a08aa12e68ade1bb02b12b009b9792473ccab01 100644
Binary files a/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png and b/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_underscore_holo.9.png b/java/res/drawable-land-mdpi/key_hint_underscore_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..52e871e0a9c76fb1f1c5f415fb9587adb748be7f
Binary files /dev/null and b/java/res/drawable-land-mdpi/key_hint_underscore_holo.9.png differ
diff --git a/java/res/drawable-land-mdpi/key_hint_underscore_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_underscore_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee0e83578cf6e60dcec1523e049f8d851126cbb3
Binary files /dev/null and b/java/res/drawable-land-mdpi/key_hint_underscore_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_at_holo.9.png b/java/res/drawable-mdpi/key_hint_at_holo.9.png
index e596144f94219c2768af89dc9584178b3c324ea0..5b946ff9bfbb7228f9707f3da06dffce38d3d717 100644
Binary files a/java/res/drawable-mdpi/key_hint_at_holo.9.png and b/java/res/drawable-mdpi/key_hint_at_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_at_large_holo.9.png b/java/res/drawable-mdpi/key_hint_at_large_holo.9.png
index 63d071405bc034450ceae8f803838b948a3ff9e4..852f899edb1bb17265043cc4ab1f7f186b331988 100644
Binary files a/java/res/drawable-mdpi/key_hint_at_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_at_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_colon_holo.9.png b/java/res/drawable-mdpi/key_hint_colon_holo.9.png
index 12ce26758ea3c92fcad2179193f841a67519428e..1d9346e6ffb277eb5d5fd4ff1598603ca26f6a23 100644
Binary files a/java/res/drawable-mdpi/key_hint_colon_holo.9.png and b/java/res/drawable-mdpi/key_hint_colon_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png b/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png
index a51bada576ddaf37e04caacba783be324d10d780..17e9091b4ffb6b28d1e10ea7cfb4a1124d3474db 100644
Binary files a/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_comma_holo.9.png b/java/res/drawable-mdpi/key_hint_comma_holo.9.png
index 82e4a93b7f979618bfde1a1f2cf7768f2977a9ff..c2a913c0459c070793a700fb3ef856393d99c447 100644
Binary files a/java/res/drawable-mdpi/key_hint_comma_holo.9.png and b/java/res/drawable-mdpi/key_hint_comma_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_comma_large_holo.9.png b/java/res/drawable-mdpi/key_hint_comma_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..846f213f1cdb2ed07c519214ff9d7cb811236fbc
Binary files /dev/null and b/java/res/drawable-mdpi/key_hint_comma_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png b/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png
index b57351b575642839d4264c293b285b61ddc59513..ce8e8de431ca41c3353d2d2f06b1b6e437992282 100644
Binary files a/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png and b/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png b/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png
index a8a17eb44a001a0a1bdebca71a4b21e39ae55eb4..035dcf85d46f4857ecbee16ac67ae8e4500a08c9 100644
Binary files a/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_minus_holo.9.png b/java/res/drawable-mdpi/key_hint_minus_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..e59a315877b9aa4762bc5f0253e8d82a9188d8c2
Binary files /dev/null and b/java/res/drawable-mdpi/key_hint_minus_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_minus_large_holo.9.png b/java/res/drawable-mdpi/key_hint_minus_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..52c28dd87ba6ac0f884d63509eb842af5403021f
Binary files /dev/null and b/java/res/drawable-mdpi/key_hint_minus_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_plus_holo.9.png b/java/res/drawable-mdpi/key_hint_plus_holo.9.png
index a80c03169d4168324e15c36e6d594fc5ea5d4503..931390b45150d1a6db41da5a77186ba21882cfd2 100644
Binary files a/java/res/drawable-mdpi/key_hint_plus_holo.9.png and b/java/res/drawable-mdpi/key_hint_plus_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png b/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png
index e8daaf0855dc101c96169b4ec838da70c5293510..e6f9f8a9c685b0c13c238434933f5a7bf71deb5a 100644
Binary files a/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_question_holo.9.png b/java/res/drawable-mdpi/key_hint_question_holo.9.png
index 9491d878f8f81a417c91c2c78e73b36fb36c6009..6cbeb59932817bc5eec3e8a0917a12f07c268189 100644
Binary files a/java/res/drawable-mdpi/key_hint_question_holo.9.png and b/java/res/drawable-mdpi/key_hint_question_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_question_large_holo.9.png b/java/res/drawable-mdpi/key_hint_question_large_holo.9.png
index c9902ffa87a689074ad81fe5059afff86f44a2af..bfd58de099492f7f4cf459789d4fba20e02ec1e0 100644
Binary files a/java/res/drawable-mdpi/key_hint_question_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_question_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_quote_holo.9.png b/java/res/drawable-mdpi/key_hint_quote_holo.9.png
index a036421d8332e7ad3ac645ee522b553ebba99687..3b361b71c86eda9768b6e19b221d50c9de3f90a3 100644
Binary files a/java/res/drawable-mdpi/key_hint_quote_holo.9.png and b/java/res/drawable-mdpi/key_hint_quote_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png b/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png
index 5381b13370a1303a658316120a93443ec3749d01..2a08aa12e68ade1bb02b12b009b9792473ccab01 100644
Binary files a/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png and b/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_underscore_holo.9.png b/java/res/drawable-mdpi/key_hint_underscore_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..52e871e0a9c76fb1f1c5f415fb9587adb748be7f
Binary files /dev/null and b/java/res/drawable-mdpi/key_hint_underscore_holo.9.png differ
diff --git a/java/res/drawable-mdpi/key_hint_underscore_large_holo.9.png b/java/res/drawable-mdpi/key_hint_underscore_large_holo.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee0e83578cf6e60dcec1523e049f8d851126cbb3
Binary files /dev/null and b/java/res/drawable-mdpi/key_hint_underscore_large_holo.9.png differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_settings_holo.png b/java/res/drawable-mdpi/sym_keyboard_settings_holo.png
index 8233623e3947450fe7e41ec534007b6e1c03e372..784a4505405470a347e3dacc074ae0c17dabae01 100644
Binary files a/java/res/drawable-mdpi/sym_keyboard_settings_holo.png and b/java/res/drawable-mdpi/sym_keyboard_settings_holo.png differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png b/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png
new file mode 100644
index 0000000000000000000000000000000000000000..594fe211c1cea0aa27bb27ce1f9c8b89c9af7ebd
Binary files /dev/null and b/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png differ
diff --git a/java/res/layout/recognition_status.xml b/java/res/layout/recognition_status.xml
index 9474d6f587dea48b48e7b236877c17b6562f9ae9..45f68974ab1ea70f56e4448f33340c9c3ecdde15 100644
--- a/java/res/layout/recognition_status.xml
+++ b/java/res/layout/recognition_status.xml
@@ -45,7 +45,7 @@
                 android:layout_height="0dip"
                 android:layout_width="match_parent"
                 android:layout_weight="1.0">
-            <com.android.inputmethod.voice.SoundIndicator
+            <com.android.inputmethod.deprecated.voice.SoundIndicator
                     android:id="@+id/sound_indicator"
                     android:src="@drawable/mic_full"
                     android:background="@drawable/mic_base"
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 377ee2c7bd8083dadbf468ba4325f893a32aef50..d1d70ff74b2c7883078b7cfb9db0a5d1668eb151 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند الضغط على مفتاح"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"صوت عند الضغط على مفتاح"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"انبثاق عند الضغط على المفاتيح"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"إعدادات اقتراحات الكلمات"</string>
+    <string name="general_category" msgid="1859088467017573195">"عام"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"تصحيح النص"</string>
     <string name="auto_cap" msgid="1719746674854628252">"استخدام الأحرف الكبيرة تلقائيًا"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"إصلاحات سريعة"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"تصحيح الأخطاء المكتوبة الشائعة"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"عرض اقتراحات التصحيح"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"عرض الكلمات المقترحة أثناء الكتابة"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"عرض دومًا"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"عرض في وضع رأسي"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"إخفاء دومًا"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"عرض مفتاح الإعدادات"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"تلقائي"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"إظهار بشكل دائم"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"إخفاء دومًا"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"اقتراحات الكلمات"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"تصحيح الكلمة السابقة تلقائيًا"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"التصحيح التلقائي"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"تؤدي المسافة والترقيم إلى تصحيح الكلمات المكتوبة بشكل غير صحيح"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"إيقاف"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"معتدل"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"حاد"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"اقتراحات ثنائية"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"استخدام الكلمة السابقة لتحسين الاقتراح"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"التالي"</string>
     <string name="label_done_key" msgid="2441578748772529288">"تم"</string>
     <string name="label_send_key" msgid="2815056534433717444">"إرسال"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"أ ب ج د"</string>
     <string name="label_more_key" msgid="3760239494604948502">"المزيد"</string>
     <string name="label_pause_key" msgid="181098308428035340">"توقف مؤقت"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"انتظار"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"حذف"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"رجوع"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"الإعدادات"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"العالي"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"مسافة"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"الرموز"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"الإدخال الصوتي"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"تشغيل الرموز"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"إيقاف الرموز"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"تشغيل العالي"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"إيقاف العالي"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"الإدخال الصوتي"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"الإدخال الصوتي غير معتمد حاليًا للغتك، ولكنه يعمل باللغة الإنجليزية."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"الإدخال الصوتي هو ميزة تجريبية تستخدم التعرف على الكلام المتصل في Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"لتشغيل الإدخال الصوتي، انتقل إلى إعدادات لوحة المفاتيح."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"لاستخدام الإدخال الصوتي، اضغط على زر الميكروفون أو مرر إصبعك عبر لوحة المفاتيح على الشاشة."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"يستخدم الإدخال الصوتي خاصية التعرف على الكلام من Google. تنطبق "<a href="http://m.google.com/privacy">"سياسة خصوصية الجوال"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"لإيقاف الإدخال الصوتي، انتقل إلى إعدادات طريقة الإدخال."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"لاستخدام الإدخال الصوتي، اضغط على زر الميكروفون."</string>
     <string name="voice_listening" msgid="467518160751321844">"تحدث الآن"</string>
     <string name="voice_working" msgid="6666937792815731889">"العمل"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"إلغاء"</string>
     <string name="ok" msgid="7898366843681727667">"موافق"</string>
     <string name="voice_input" msgid="2466640768843347841">"الإدخال الصوتي"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"لوحة مفاتيح رئيسية"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"لوحة مفاتيح الرموز"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"إيقاف"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ميكروفون على لوحة مفاتيح رئيسية"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"ميكروفون على لوحة مفاتيح الرموز"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"الإدخال الصوتي مُعطل"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"تحديد طريقة الإرسال"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"لغات الإدخال"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"مرر إصبعك على مفتاح المسافة لتغيير اللغة"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"تمكين ملاحظات المستخدم"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"المساعدة في تحسين محرر طريقة الإرسال هذا من خلال إرسال إحصاءات الاستخدام وتقارير الأعطال تلقائيًا إلى Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"المس لتصحيح الكلمات"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"المس الكلمات المدخلة لتصحيحها"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"المس الكلمات التي تم إدخالها لتصحيحها، وذلك فقط عندما تكون الاقتراحات مرئية."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"مظهر لوحة المفاتيح"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"لوحة مفاتيح تشيكية"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"لوحة مفاتيح دانماركية"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"لوحة مفاتيح ألمانية"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"لوحة مفاتيح إنجليزية (بريطانيا العظمى)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"لوحة مفاتيح إنجليزية (الولايات المتحدة)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"لوحة مفاتيح ألمانية"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"لوحة مفاتيح إنجليزية (بريطانيا)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"لوحة مفاتيح إنجليزية (الولايات المتحدة)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"لوحة مفاتيح إسبانية"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"لوحة مفاتيح إسبانية (الولايات المتحدة)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"لوحة مفاتيح فرنسية"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"لوحة مفاتيح إيطالية"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"لوحة مفاتيح فرنسية (كندا)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"لوحة مفاتيح فرنسية (سويسرا)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"لوحة مفاتيح إيطالية"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"لوحة مفاتيح نرويجية"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"لوحة مفاتيح بولندية"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"لوحة مفاتيح روسية"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"لوحة مفاتيح صربية"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"لوحة مفاتيح سويدية"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"صوت تشيكي"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"صوت ألماني"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"صوت إنجليزي (أستراليا)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"صوت إنجليزي (بريطانيا العظمى)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"صوت إنجليزي (الهند)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"صوت إنجليزي (نيوزلندا)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"صوت إنجليزي (الولايات المتحدة)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"صوت أفريقاني"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"صوت تشيكي"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"صوت ألماني"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"صوت إنجليزي"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"صوت إسباني"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"صوت فرنسي"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"صوت إيطالي"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"صوت ياباني"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"صوت كوري"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"صوت هولندي"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"صوت بولندي"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"صوت برتغالي"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"صوت روسي"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"صوت تركي"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"صوت صيني (الصين)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"صوت صيني (تايوان)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"صوت صيني، يوي"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"صوت صيني، الماندارين"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"صوت زولوي"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"وضع دراسة الاستخدام"</string>
 </resources>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 8940adc6d424302ad611845822fef13b3c126ac9..418bb18a1c6793d5dce650ddff49b7d21a6ae0e2 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натискане на клавиш"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Изскачащ прозорец при натискане на клавиш"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Настройки за предложения на думи"</string>
+    <string name="general_category" msgid="1859088467017573195">"Общи"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Корекция на текста"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Автоматично поставяне на главни букви"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Бързи корекции"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Коригира най-честите грешки при въвеждане"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Показване на предложения за поправка"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Показване на предложения, докато пишете"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Винаги да се показва"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Показване с вертикална ориентация"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Винаги да се скрива"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Показване на клавиша за настройки"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Автоматично"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Да се показва винаги"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Да се скрива винаги"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Предложения на думи"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Автоматично коригиране на предишната дума"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Автоко"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Клавишът за интервал и пунктуация авт. поправя сгрешени думи"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Изкл."</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умерено"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Агресивно"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Предложения за биграми"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Използване на предишната дума за подобряване на предложението"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Напред"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Изпращане"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Още"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Чака"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Изтриване"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Настройки"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Интервал"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Символи"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Гласово въвеждане"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Символите са включени"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Символите са изключени"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift е включен"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift е изключен"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Гласово въвеждане"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"За вашия език понастоящем не се поддържа гласово въвеждане, но можете да го използвате на английски."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовото въвеждане е експериментална функция, използваща разпознаването на реч в мрежата на Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"За да изключите гласовото въвеждане, отворете настройките на клавиатурата."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"За да използвате гласово въвеждане, натиснете бутона на микрофона или плъзнете пръст през екранната клавиатура."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовото въвеждане използва функцията на Google за разпознаване на говор. В сила е "<a href="http://m.google.com/privacy">"Декларацията за поверителност за мобилни устройства"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"За да изключите гласовото въвеждане, отворете настройките за метода за въвеждане."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"За да използвате гласово въвеждане, натиснете бутона на микрофона."</string>
     <string name="voice_listening" msgid="467518160751321844">"Говорете сега"</string>
     <string name="voice_working" msgid="6666937792815731889">"Обработва се"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Отказ"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Гласово въвеждане"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На осн. клавиатура"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"На клав. на симв."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Изкл."</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Микр. на осн. клав."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Микр. на клав. на симв."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Глас. въвежд. е деакт."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Избор на метод на въвеждане"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Плъзнете пръст по клавиша за интервал за промяна на езика"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Активиране на отзивите от потребителите"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Помогнете за подобряването на този редактор за въвеждане чрез автоматично изпращане до Google на статистически данни за употребата и сигнали за сривове."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Докоснете, за да поправите думите"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Докоснете въведените думи, за да ги поправите"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Докоснете въведените думи, за да ги поправите – само когато предложенията са видими"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Тема на клавиатурата"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"чешка клавиатура"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"датска клавиатура"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"немска клавиатура"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"английска (Великобритания) клавиатура"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"английска (САЩ) клавиатура"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"немска клавиатура"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"английска (Великобрит.) клавиатура"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"английска (САЩ) клавиатура"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"испанска клавиатура"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"испанска (САЩ) клавиатура"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"френска клавиатура"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"италианска клавиатура"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"френска (Канада) клавиатура"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"френска (Швейцария) клавиатура"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"италианска клавиатура"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"норвежка клавиатура"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"нидерландска клавиатура"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"руска клавиатура"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"сръбска клавиатура"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"шведска клавиатура"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"чешки, гласово"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"немски, гласово"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"английски (Австралия), гласово"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"английски (Великобритания), гласово"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"английски (Индия), гласово"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"английски (Нова Зеландия), гласово"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"английски (САЩ), гласово"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"африкаанс, гласово"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"чешки, гласово"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"немски, гласово"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"английски, гласово"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"испански, гласово"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"френски, гласово"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"италиански, гласово"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"японски, гласово"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"корейски, гласово"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"нидерландски, гласово"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"полски, гласово"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"португалски, гласово"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"руски, гласово"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"турски, гласово"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"китайски (Китай), гласово"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"китайски (Тайван), гласово"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"китайски, кантонски, гласово"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"китайски, мандарин, гласово"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"зулуски, гласово"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Режим за изследване на използваемостта"</string>
 </resources>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index cd9191e06b7d740841429d1b79dcb93568190d50..1bfa3a9abfdb00ff95d2c316862218a6fea0e55a 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"So en prémer una tecla"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Finestra emergent en prémer un botó"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Configuració de suggeriment de paraules"</string>
+    <string name="general_category" msgid="1859088467017573195">"General"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Correcció de text"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Majúscules automàtiques"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correccions ràpides"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corregeix els errors d\'ortografia habituals"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostra els suggeriments de correcció"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Mostra paraules suggerides mentre s\'escriu"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostra sempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostra en mode vertical"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Amaga sempre"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostra la tecla de configuració"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automàtic"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostra sempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Amaga sempre"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Suggeriments de paraules"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corregeix automàticament la paraula anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Correcció automàtica"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Barra espaiadora i punt. correg. autom. paraules mal escrites"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desactiva"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderada"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Suggeriments Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilitza la paraula anterior per millorar el suggeriment"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Següent"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Fet"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Envia"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Més"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Suprimeix"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Retorn"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Configuració"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Majúscules"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espai"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Símbols"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulador"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Entrada de veu"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Símbols activats"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Símbols desactivats"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Majúscules activades"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Majúscules desactivades"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de veu"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualment, l\'entrada de veu no és compatible amb el vostre idioma, però funciona en anglès."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'entrada de veu és una funció experimental que utilitza el reconeixement de la parla en xarxa de Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per desactivar l\'entada de veu, aneu a la configuració del teclat."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilitzar l\'entrada de veu, premeu el botó del micròfon o feu lliscar el dit pel teclat en pantalla."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'entrada de veu utilitza el reconeixement de veu de Google. S\'hi aplica la "<a href="http://m.google.com/privacy">"Política de privadesa de Google Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per desactivar l\'entada de veu, vés a la configuració del mètode d\'entrada."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilitzar l\'entrada de veu, prem el botó del micròfon."</string>
     <string name="voice_listening" msgid="467518160751321844">"Parleu ara"</string>
     <string name="voice_working" msgid="6666937792815731889">"S\'està treballant"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancel·la"</string>
     <string name="ok" msgid="7898366843681727667">"D\'acord"</string>
     <string name="voice_input" msgid="2466640768843347841">"Entrada de veu"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Al teclat principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Al tecl. de símb."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Desactivada"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro en tecl. princ."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro en tecl. símb."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entr. veu desactiv."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Selecciona el mètode d\'entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomes d\'entrada"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Feu lliscar el dit a la barra espaiadora per canviar l\'idioma"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Activa els comentaris de l\'usuari"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ajuda a millorar aquest editor de mètodes d\'entrada enviant automàticament estadístiques d\'ús i informes de bloqueigs a Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Toca per corregir paraules"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca les paraules introduïdes per corregir-les"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca les paraules introduïdes per corregir-les, només quan els suggeriments siguin visibles"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema del teclat"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Teclat txec"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Teclat danès"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclat alemany "</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclat anglès (Gran Bretanya)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclat anglès (Estats Units)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclat alemany"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclat anglès (Regne Unit)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclat anglès (Estats Units)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Teclat espanyol"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Teclat espanyol (Estats Units)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Teclat francès"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclat italià "</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Teclat francès (Canadà)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Teclat francès (Suïssa)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclat italià"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Teclat noruec"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Teclat holandès"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Teclat rus"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Teclat serbi"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Teclat suec"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Veu txeca"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Veu alemanya"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Veu anglesa (Austràlia)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Veu anglesa (Gran Bretanya)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Veu anglesa (Índia)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Veu anglesa (Nova Zelanda)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Veu anglesa (Estats Units)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Veu en afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Veu txeca"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Veu alemanya"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Veu anglesa"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Veu espanyola"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Veu francesa"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Veu italiana"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Veu japonesa"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Veu coreana"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Veu holandesa"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Veu polonesa"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Veu portuguesa"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Veu russa"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Veu turca"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Veu xinesa (Xina)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Veu xinesa (Taiwan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Veu xinesa (Yue)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Veu xinesa (mandarí)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Veu en zulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Mode d\'estudi d\'usabilitat"</string>
 </resources>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 70f66ecd7eaa4816251e3873d7591c257bbebf40..b0cb7daf7a8cc3020ffac2a7f452d7d56eba2618 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Při stisku klávesy vibrovat"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk při stisku klávesy"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Zobrazit znaky při stisku klávesy"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Nastavení návrhů slov"</string>
+    <string name="general_category" msgid="1859088467017573195">"Obecné"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Oprava textu"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Velká písmena automaticky"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Rychlé opravy"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Opravuje nejčastější chyby při psaní"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Zobrazit návrhy oprav"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Zobrazovat navržená slova během psaní"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vždy zobrazovat"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Zobrazit v režimu na výšku"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Vždy skrývat"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Zobrazit klávesu Nastavení"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automaticky"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vždy zobrazovat"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Vždy skrývat"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Návrhy slov"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automaticky opravit předchozí slovo"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatické opravy"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Stisknutím mezerníku a interpunkce se automaticky opravují chybně napsaná slova"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Vypnuto"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mírné"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivní"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Návrh Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Použít předchozí slovo ke zlepšení návrhu"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Další"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Odeslat"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Další"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"ÄŒekat"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Smazat"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Nastavení"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"mezera"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboly"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Karta"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Hlasový vstup"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symboly jsou zapnuty"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symboly jsou vypnuty"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Režim Shift je zapnutý"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Režim Shift je vypnutý"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pro váš jazyk aktuálně není hlasový vstup podporován, ale funguje v angličtině."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup je experimentální funkce, která využívá síťové rozpoznávání řeči společnosti Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Chcete-li vypnout hlasový vstup, přejděte do nastavení klávesnice."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu nebo přejeďte prstem přes klávesnici na obrazovce."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup používá rozpoznávání hlasu Google a vztahují se na něj "<a href="http://m.google.com/privacy">"Zásady ochrany osobních údajů pro mobilní služby"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Chcete-li vypnout hlasový vstup, přejděte do nastavení metod vstupu."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu."</string>
     <string name="voice_listening" msgid="467518160751321844">"Mluvte"</string>
     <string name="voice_working" msgid="6666937792815731889">"Probíhá zpracování"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Zrušit"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Hlasový vstup"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na hlavní klávesnici"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klávesnici se symb."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Vypnuto"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr. na hlav. kláv."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. na kláv. se symb."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hlasový vstup vypnut"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Výběr metody zadávání dat"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Vstupní jazyky"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Jazyk můžete změnit posunutím prstu po mezerníku."</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"K dispozici je slovník"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivovat zasílání statistik užívání a zpráv o selhání"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Automatickým zasíláním statistik o užívání editoru zadávání dat a zpráv o jeho selhání do Googlu můžete přispět k vylepšení tohoto nástroje."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotykem aktivujete opravy"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotknete-li se slov, která jste napsali, můžete je opravit."</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotykem aktivovat opravy"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Klepnutím na zadaná slova tato slova opravíte, musí však být viditelné návrhy."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Motiv klávesnice"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Klávesnice – čeština"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Klávesnice – dánština"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Klávesnice – němčina"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Klávesnice – angličtina (VB)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Klávesnice – angličtina (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Klávesnice – španělština"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Klávesnice – španělština (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Klávesnice – francouzština"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Klávesnice – francouzština (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Klávesnice – francouzština (Švýc.)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Klávesnice – italština"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Klávesnice – norština"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Klávesnice – holandština"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Klávesnice – ruština"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Klávesnice – srbština"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Klávesnice – švédština"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voice – afrikánština"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voice – čeština"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voice – němčina"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voice – angličtina"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voice – španělština"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voice – francouzština"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Hlasový vstup – italština"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voice – japonština"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voice – korejština"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Hlasový vstup – holandština"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voice – polština"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voice – portugalština"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voice – ruština"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voice – turečtina"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voice – čínština, kantonština"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voice – čínština, mandarínština"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voice – zulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Režim studie použitelnosti"</string>
 </resources>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index d748d10fb0670cea91dea549122c41b2cd34d246..eb79888d60b0bef7fb27f6f2787dee88edac6756 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibration ved tastetryk"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetryk"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Popup ved tastetryk"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Indstillinger for ordforslag"</string>
+    <string name="general_category" msgid="1859088467017573195">"Generelt"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Tekstkorrigering"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Skriv aut. med stort"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Hurtige løsninger"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Retter almindelige stavefejl"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Vis rettelsesforslag"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Vis ordforslag under indtastning"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vis altid"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Vis i portrættilstand"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Skjul altid"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Vis indstillingsnøgle"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisk"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vis altid"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Skjul altid"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Ordforslag"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Ret automatisk det forrige ord"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatisk retning"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Mellemrumstast og tegnsætning retter automatisk forkerte ord"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Fra"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Beskeden"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressiv"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram-forslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Brug forrige ord for at forbedre forslag"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Næste"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Udfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mere"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Slet"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Tilbage"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Indstillinger"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Mellemrum"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboler"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Fane"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Stemmeinput"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symboler: Til"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symboler: Fra"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift: Til"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift: Fra"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Stemmeinput"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmeinput understøttes i øjeblikket ikke for dit sprog, men fungerer på engelsk."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Stemme-input er en funktion på forsøgsbasis, som bruger Googles netværksstemmegenkendelse."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Slå stemmeinput fra i indstillingerne for tastaturet."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"For at bruge stemme-input skal du trykke på knappen mikrofon eller lade glide fingeren hen over skærmtastaturet."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Stemmeinput anvender Googles stemmegenkendelse. "<a href="http://m.google.com/privacy">"Fortrolighedspolitikken for mobilenheder"</a>" gælder."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Slå stemmeinput fra i indstillingerne for inputmetode."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Brug stemmeinput ved at trykke på mikrofonknappen."</string>
     <string name="voice_listening" msgid="467518160751321844">"Tal nu"</string>
     <string name="voice_working" msgid="6666937792815731889">"Arbejder"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Annuller"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Stemmeinput"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"PÃ¥ hovedtastatur"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"PÃ¥ symboltastatur"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Fra"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. på hovedtastatur"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. på symboltastatur"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Stemmeinput deaktiveret"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Vælg inputmetode"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inputsprog"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Træk fingeren på mellemrumstasten for at skifte sprog"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbog er tilgængelig"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brugerfeedback"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Vær med til at forbedre denne inputmetode ved at sende anvendelsesstatistikker og rapporter om nedbrud til Google."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryk for at rette ord igen"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan rette ordene igen ved at trykke på de ord, du har indtastet"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryk for at rette ord"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tryk på de indtastede ord for at rette dem. Kun når der er synlige forslag."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturtema"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tjekkisk tastatur"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Dansk tastatur"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tysk tastatur"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engelsk tastatur (Storbritannien)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engelsk tastatur (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spansk tastatur"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spansk tastatur (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Fransk tastatur"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Fransk tastatur (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Fransk tastatur (Schweiz)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italiensk tastatur"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norsk tastatur"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Hollandsk tastatur"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russisk tastatur"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbisk tastatur"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Svensk tastatur"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaans stemme"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Tjekkisk stemme"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Tysk stemme"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Engelsk stemme"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spansk stemme"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Fransk stemme"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italiensk stemme"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japansk stemme"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Koreansk stemme"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Hollandsk stemme"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Polsk stemme"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugisisk stemme"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russisk stemme"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Tyrkisk stemme"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Kinesisk, Yue stemme"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Kinesisk, mandarin stemme"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu stemme"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Tilstand for brugsstudie"</string>
 </resources>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 330946e5cdb718072515ab31847c0d6d7cda854b..396d74dd8586b85332e191fe0594c9e59deae88c 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrieren b. Tastendruck"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Ton bei Tastendruck"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bei Tastendruck"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Einstellungen für Wortvorschläge"</string>
+    <string name="general_category" msgid="1859088467017573195">"Allgemein"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Textkorrektur"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Autom. Groß-/Kleinschr."</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Quick Fixes"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Korrigiert gängige Tippfehler"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Änderungsvorschläge anzeigen"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Vorgeschlagene Wörter während des Tippens anzeigen"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Immer anzeigen"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Im Hochformat anzeigen"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Immer ausblenden"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Einstellungstaste anz."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisch"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Immer anzeigen"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Immer ausblenden"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Wortvorschläge"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Vorheriges Wort automatisch korrigieren"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Auto-Korrektur"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Korrektur fehlerhafter Wörter durch Leertaste und Satzzeichen"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Aus"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mäßig"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressiv"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigramm-Vorschläge"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Zur Verbesserung des Vorschlags vorheriges Wort verwenden"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Weiter"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Fertig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Senden"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mehr"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Warten"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Löschen"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Eingabe"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Einstellungen"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Umschalt"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Leerzeichen"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symbole"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Spracheingabe"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symbole an"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symbole aus"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Umschalt an"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Umschalt aus"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Spracheingabe"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spracheingaben werden derzeit nicht für Ihre Sprache unterstützt, funktionieren jedoch in Englisch."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Die Spracheingabe ist eine Funktion im Versuchsstadium, die die vernetzte Spracherkennung von Google verwendet."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Wenn Sie die Spracheingabe deaktivieren möchten, rufen Sie die Tastatureinstellungen auf."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Um die Spracheingabe zu verwenden, drücken Sie die Mikrofontaste oder ziehen Sie Ihren Finger über die Bildschirmtastatur."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Die Spracheingabe verwendet die Spracherkennung von Google. Es gelten die "<a href="http://m.google.com/privacy">"Google Mobile-Datenschutzbestimmungen"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Rufen Sie zum Deaktivieren der Spracheingabe die Einstellungen für die Eingabemethode auf."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Drücken Sie zur Verwendung der Spracheingabe die Mikrofonschaltfläche."</string>
     <string name="voice_listening" msgid="467518160751321844">"Jetzt sprechen"</string>
     <string name="voice_working" msgid="6666937792815731889">"Vorgang läuft"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Abbrechen"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Spracheingabe"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Auf Haupttastatur"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Auf Symboltastatur"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Aus"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikro auf Haupttastatur"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikro auf Symboltastatur"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Spracheing. deaktiviert"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Eingabemethode auswählen"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Eingabesprachen"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Finger über die Leertaste bewegen, um die Eingabesprache zu wechseln"</string>
@@ -105,74 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Nutzer-Feedback aktivieren"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Tragen Sie zur Verbesserung dieses Eingabemethodeneditors bei, indem Sie automatisch Nutzungsstatistiken und Absturzberichte an Google senden."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Wortkorrektur"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Sie können Wörter korrigieren, indem Sie die eingegebenen Wörter berühren."</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tippen Sie zum Korrigieren auf eingegebene Wörter (nur, wenn Vorschläge angezeigt werden)."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturdesign"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tschechische Tastatur"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Dänische Tastatur"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Deutsche Tastatur"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Englische Tastatur (GB)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Englische Tastatur (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spanische Tastatur"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spanische Tastatur (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Französische Tastatur"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Französische Tastatur (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Französische Tastatur (Schweiz)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italienische Tastatur"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norwegische Tastatur"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Niederländische Tastatur"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russische Tastatur"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbische Tastatur"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Schwedische Tastatur"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Stimme in Afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Tschechische Sprache"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Deutsche Sprache"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Englische Stimme"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spanische Sprache"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Französische Sprache"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italienisch"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japanische Sprache"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Koreanische Sprache"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Niederländisch"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Polnische Sprache"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugiesische Sprache"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russische Sprache"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Türkische Sprache"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Chinesische Stimme (Yue)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Chinesische Stimme (Mandarin)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Stimme in isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modus der Studie zur Benutzerfreundlichkeit"</string>
 </resources>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index ff6a73ad442da78c429bf8e533c3f7293e3c6806..6d0869bf1486f319f98d4878740d95a17d4107e1 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Δόνηση κατά το πάτημα πλήκτρων"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Ήχος κατά το πάτημα πλήκτρων"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Εμφάνιση με το πάτημα πλήκτρου"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Ρυθμίσεις υποδείξεων λέξεων"</string>
+    <string name="general_category" msgid="1859088467017573195">"Γενικά"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Διόρθωση κειμένου"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Αυτόματη χρήση κεφαλαίων"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Γρήγορες διορθώσεις"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Διορθώνει συνηθισμένα λάθη πληκτρολόγησης"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Εμφάνιση προτάσεων διόρθωσης"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Προβολή προτεινόμενων λέξεων κατά την πληκτρολόγηση"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Να εμφανίζεται πάντα"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Εμφάνιση σε λειτουργία κατακόρυφης προβολής"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Πάντα απόκρυψη"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Εμφάνιση πλήκτρου ρυθμίσεων"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Αυτόματο"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Να εμφανίζεται πάντα"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Πάντα απόκρυψη"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Υποδείξεις λέξεων"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Αυτόματη διόρθωση της προηγούμενης λέξης"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Αυτόματη διόρθωση"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Τα πλήκτρα διαστήματος και στίξης διορθ. αυτόμ. λάθος λέξεις"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Απενεργοποίηση"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Μέτρια"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Υψηλή"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Προτάσεις bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Χρήση προηγούμενης λέξης για τη βελτίωση πρότασης"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Επόμενο"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Τέλος"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Αποστολή"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ΑΒΓ"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Περισσότερα"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Παύση"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Αναμ."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Ρυθμίσεις"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Κενό"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Σύμβολα"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Φωνητική εντολή"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Σύμβολα ενεργά"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Σύμβολα ανενεργά"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift ενεργό"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift ανενεργό"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Φωνητική είσοδος"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Η φωνητική είσοδος δεν υποστηρίζεται αυτή τη στιγμή για τη γλώσσα σας, ωστόσο λειτουργεί στα Αγγλικά."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Οι φωνητικές εντολές είναι μια πειραματική λειτουργία, η οποία χρησιμοποιεί τη δικτυακή αναγνώριση ομιλίας της Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Για να απενεργοποιήσετε τη φωνητική είσοδο, μεταβείτε στις ρυθμίσεις πληκτρολογίου."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Για να χρησιμοποιήσετε τις φωνητικές εντολές, πιέστε το κουμπί μικροφώνου ή σύρετε το δάχτυλό σας κατά μήκος του πληκτρολογίου της οθόνης."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Οι φωνητικές εντολές χρησιμοποιούν την τεχνολογία αναγνώρισης φωνής της Google. Ισχύει "<a href="http://m.google.com/privacy">"η Πολιτική Απορρήτου για κινητά"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Για να απενεργοποιήσετε τις φωνητικές εντολές, μεταβείτε στις ρυθμίσεις της μεθόδου εισαγωγής."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Για τη χρήση φωνητικών εντολών, πατήστε το κουμπί του μικροφώνου."</string>
     <string name="voice_listening" msgid="467518160751321844">"Μιλήστε τώρα"</string>
     <string name="voice_working" msgid="6666937792815731889">"Σε λειτουργία"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Ακύρωση"</string>
     <string name="ok" msgid="7898366843681727667">"ΟΚ"</string>
     <string name="voice_input" msgid="2466640768843347841">"Φωνητική είσοδος"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Στο κύριο πληκτρολ."</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Πληκτρ. συμβ. ενερ."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Απενεργοποίηση"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Μικ. στο κύριο πληκ."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Μικ. στο πληκ. συμβ."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Απεν. φωνητ. είσοδος"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Επιλογή μεθόδου εισόδου"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Γλώσσες εισόδου"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Σύρετε το δάχτυλο στο πλήκτρο διαστήματος για να αλλάξετε γλώσσα"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Λεξικό διαθέσιμο"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Ενεργοποίηση σχολίων χρηστών"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Βοηθήστε μας να βελτιώσουμε αυτό το πρόγραμμα επεξεργασίας μεθόδου εισόδου στέλνοντας αυτόματα στατιστικά στοιχεία και αναφορές σφαλμάτων στην Google."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Αγγίξτε για να διορθώσετε ξανά τις λέξεις"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Μπορείτε να διορθώσετε ξανά τις λέξεις αγγίζοντας τις λέξεις που έχετε πληκτρολογήσει"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Αγγίξτε για διόρθωση λέξεων"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Αγγίξτε τις λέξες για να τις διορθώσετε, μόνο όταν οι προτάσεις είναι ορατές"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Θέμα πληκτρολογίου"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Τσεχικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Δανικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Γερμανικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Αγγλικό (ΗΒ) πληκτρολόγιο"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Αγγλικό (ΗΠΑ) πληκτρολόγιο"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Ισπανικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Ισπανικό (ΗΠΑ) πληκτρολόγιο"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Γαλλικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Γαλλικό (Καναδάς) πληκτρολόγιο"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Γαλλικό (Ελβετία) πληκτρολόγιο"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Ιταλικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Νορβηγικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Ολλανδικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Ρωσικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Σερβικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Σουηδικό πληκτρολόγιο"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Αφρικάανς"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Τσεχικά"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Γερμανικά"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Αγγλικά"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Ισπανικά"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Γαλλικά"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Φωνητικές εντολές στα Ιταλικά"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Ιαπωνικά"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Κορεατικά"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Φωνητικές εντολές στα Ολλανδικά"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Πολωνικά"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Πορτογαλικά"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Ρωσικά"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Τουρκικά"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Κινεζικά, Γιούε"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Κινεζικά, Μανδαρινικά"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Ζουλού"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Λειτουργία μελέτης χρηστικότητας"</string>
 </resources>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 8f1815f5bffeef6f7f49b69754ece4a1487254b2..b2e62b0cd23a3cc57d057322669d55c686c4d3d9 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on key-press"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on key-press"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up on key press"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Word suggestion settings"</string>
+    <string name="general_category" msgid="1859088467017573195">"General"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Text correction"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Quick fixes"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrects commonly typed mistakes"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Show correction suggestions"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Display suggested words while typing"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Always show"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Show on portrait mode"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Always hide"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Show settings key"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatic"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Always show"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Always hide"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Word suggestions"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automatically correct the previous word"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Auto-correction"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Spacebar and punctuation correct mistyped words automatically"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Off"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressive"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram Suggestions"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Use previous word to improve suggestion"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Next"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Done"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"More"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Wait"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Settings"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Space"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symbols"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Voice Input"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symbols on"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symbols off"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift on"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift off"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Voice input"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Voice input is not currently supported for your language, but does work in English."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Voice input is an experimental feature using Google\'s networked speech recognition."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"To turn off voice input, go to keyboard settings."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"To use voice input, press the microphone button or slide your finger across the on-screen keyboard."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Voice input uses Google\'s speech recognition. "<a href="http://m.google.com/privacy">"The Mobile Privacy Policy"</a>" applies."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"To turn off voice input, go to input method settings."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"To use voice input, press the microphone button."</string>
     <string name="voice_listening" msgid="467518160751321844">"Speak now"</string>
     <string name="voice_working" msgid="6666937792815731889">"Working"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancel"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Voice input"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"On main keyboard"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"On symbols keyboard"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Off"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic on main keyboard"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic on symbols keyboard"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Voice input is disabled"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Select input method"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Slide finger on spacebar to change language"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Enable user feedback"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Help improve this input method editor by sending usage statistics and crash reports automatically to Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Touch to correct words"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Touch words entered to correct them"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Touch words entered to correct them, only when suggestions are visible"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Keyboard Theme"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Czech Keyboard"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danish Keyboard"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"German Keyboard"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"English (Great Britain) Keyboard"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"English (United States) Keyboard"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"German Keyboard"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"English (UK) Keyboard"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"English (US) Keyboard"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spanish Keyboard"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spanish (US) Keyboard"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"French Keyboard"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italian Keyboard"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"French (Canada) Keyboard"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"French (Switzerland) Keyboard"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italian Keyboard"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norwegian Keyboard"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Dutch Keyboard"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russian Keyboard"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbian Keyboard"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Swedish Keyboard"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Czech Voice"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"German Voice"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"English (Australia) Voice"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"English (Great Britain) Voice"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"English (India) Voice"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"English (New Zealand) Voice"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"English (United States) Voice"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaans Voice"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Czech Voice"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"German Voice"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"English Voice"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spanish Voice"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"French Voice"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italian Voice"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japanese Voice"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Korean Voice"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Dutch Voice"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Polish Voice"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portuguese Voice"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russian Voice"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Turkish Voice"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Chinese (China) Voice"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Chinese (Taiwan) Voice"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Chinese, Yue Voice"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Chinese, Mandarin Voice"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu Voice"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Usability Study Mode"</string>
 </resources>
diff --git a/java/res/values-en/donottranslate-altchars.xml b/java/res/values-en/donottranslate-altchars.xml
index 3950d7dff3ca50cf70c73184568280fd3fd67006..29582c950f4aaf90c9c45df2a09c2d5a2a75afbd 100644
--- a/java/res/values-en/donottranslate-altchars.xml
+++ b/java/res/values-en/donottranslate-altchars.xml
@@ -22,6 +22,7 @@
     <string name="alternates_for_e">3,è,é,ê,ë,ē</string>
     <string name="alternates_for_i">8,î,ï,í,ī,ì</string>
     <string name="alternates_for_o">9,ô,ö,ò,ó,œ,ø,ō,õ</string>
+    <string name="alternates_for_s">ß</string>
     <string name="alternates_for_u">7,û,ü,ù,ú,ū</string>
     <string name="alternates_for_n">ñ</string>
     <string name="alternates_for_c">ç</string>
diff --git a/java/res/values-es-rUS-xlarge/strings.xml b/java/res/values-es-rUS-xlarge/strings.xml
deleted file mode 100644
index 24d2b4f909dccf948527541c3aa9a709238f076e..0000000000000000000000000000000000000000
--- a/java/res/values-es-rUS-xlarge/strings.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- XL -->
-    <string name="sound_on_keypress" msgid="5115009797011251176">"Sonar al pulsar teclas"</string>
-    <!-- XL -->
-    <string name="auto_cap" msgid="6033382411344449470">"Uso de mayúsculas automático"</string>
-    <!-- XL -->
-    <string name="auto_correction" msgid="7961335093790493671">"Corrección automática"</string>
-    <!-- XL -->
-    <string name="auto_correction_summary" msgid="6260001790426244084">"La barra espaciadora o la puntuación insertan automáticamente la palabra resaltada."</string>
-    <!-- XL -->
-    <string name="bigram_suggestion" msgid="7146707435859263625">"Sugerencias de bigramas"</string>
-    <!-- XL -->
-    <string name="label_done_key" msgid="5392116476778838314">"Listo"</string>
-    <!-- XL -->
-    <string name="voice_warning_title" msgid="7559175513146431282">"Entrada de voz"</string>
-    <!-- XL -->
-    <string name="voice_warning_may_not_understand" msgid="5450473727606344027">"La entrada de voz utiliza el reconocimiento de voz de Google. "<a href="http://m.google.com/privacy">"Aplica la Política de privacidad de Google para celulares"</a>"."</string>
-    <!-- XL -->
-    <string name="voice_warning_how_to_turn_off" msgid="8461922898209345270">"Para desactivar la entrada por voz, ve a la configuración de métodos de entrada."</string>
-    <!-- XL -->
-    <string name="voice_hint_dialog_message" msgid="6099357096490592798">"Para utilizar entrada de voz, presiona el botón micrófono."</string>
-    <!-- XL -->
-    <string name="voice_input" msgid="6634874497844843576">"Entrada de voz"</string>
-    <!-- XL -->
-    <string name="prefs_enable_recorrection_summary" msgid="3119549956172710725">"Toca las palabras ingresadas que desees corregir, solo cuando las sugerencias estén visibles."</string>
-    <!-- XL -->
-    <string name="prefs_show_suggestions" msgid="1375526087676269770">"Mostrar sugerencias"</string>
-    <!-- XL -->
-    <string name="prefs_show_suggestions_summary" msgid="2564386479780335351">"Mostrar palabras sugeridas al escribir"</string>
-    <!-- XL -->
-    <string name="prefs_suggestion_visibility_show_name" msgid="8350173747634837929">"Mostrar siempre"</string>
-    <!-- XL -->
-    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="670278993111469619">"Mostrar en modo retrato"</string>
-    <!-- XL -->
-    <string name="prefs_suggestion_visibility_hide_name" msgid="2750493093338023345">"Ocultar siempre"</string>
-    <!-- XL -->
-    <string name="auto_correction_threshold_mode_off" msgid="4899978031827517261">"Apagado"</string>
-    <!-- XL -->
-    <string name="auto_correction_threshold_mode_modest" msgid="3316394123368070951">"Moderado"</string>
-    <!-- XL -->
-    <string name="auto_correction_threshold_mode_aggeressive" msgid="6091003457668724585">"Intenso"</string>
-    <!-- XL -->
-    <string name="label_to_alpha_key" msgid="3103719164112604010">"ABC"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_main_keyboard" msgid="1403596961453846365">"En el teclado principal"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_symbols_keyboard" msgid="5916050323076830126">"En el teclado de símbolos"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_off" msgid="1577817314089496020">"Apagado"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_summary_main_keyboard" msgid="5118121899312172508">"Micrófono en el teclado principal"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_summary_symbols_keyboard" msgid="8181616553734217736">"Micrófono en el teclado de símbolos"</string>
-    <!-- XL -->
-    <string name="voice_input_modes_summary_off" msgid="3854831353403775554">"La entrada por voz está inhabilitada."</string>
-    <!-- XL -->
-    <string name="subtype_mode_cs_keyboard" msgid="1186679497674833204">"Teclado en checo"</string>
-    <!-- XL -->
-    <string name="subtype_mode_da_keyboard" msgid="1395637124037817510">"Teclado en danés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_de_keyboard" msgid="1145552122692431122">"Teclado en alemán"</string>
-    <!-- XL -->
-    <string name="subtype_mode_en_GB_keyboard" msgid="5050923189634470413">"Teclado en inglés (Reino Unido)"</string>
-    <!-- XL -->
-    <string name="subtype_mode_en_US_keyboard" msgid="3435344903704397043">"Teclado en inglés (EE.UU.)"</string>
-    <!-- XL -->
-    <string name="subtype_mode_es_keyboard" msgid="1030419781157491328">"Teclado en español"</string>
-    <!-- XL -->
-    <string name="subtype_mode_es_US_keyboard" msgid="5792199241357098918">"Teclado en español (EE.UU.)"</string>
-    <!-- XL -->
-    <string name="subtype_mode_fr_keyboard" msgid="4855416218650524164">"Teclado en francés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_fr_CA_keyboard" msgid="6458285776720480201">"Teclado en francés (Canadá)"</string>
-    <!-- XL -->
-    <string name="subtype_mode_fr_CH_keyboard" msgid="5966960427086795964">"Teclado en francés (Suiza)"</string>
-    <!-- XL -->
-    <string name="subtype_mode_it_keyboard" msgid="6927754583816493555">"Teclado en italiano"</string>
-    <!-- XL -->
-    <string name="subtype_mode_nb_keyboard" msgid="771634025467668613">"Teclado en noruego"</string>
-    <!-- XL -->
-    <string name="subtype_mode_nl_keyboard" msgid="3397048533451717478">"Teclado en holandés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_ru_keyboard" msgid="3812694929448916712">"Teclado en ruso"</string>
-    <!-- XL -->
-    <string name="subtype_mode_sr_keyboard" msgid="7947963963114184275">"Teclado en serbio"</string>
-    <!-- XL -->
-    <string name="subtype_mode_sv_keyboard" msgid="3874083866564515371">"Teclado en sueco"</string>
-    <!-- XL -->
-    <string name="subtype_mode_af_voice">"Voz en Afrikáans"</string>
-    <!-- XL -->
-    <string name="subtype_mode_cs_voice" msgid="8290007904951946296">"Voz en checo"</string>
-    <!-- XL -->
-    <string name="subtype_mode_de_voice" msgid="672328729666823853">"Voz en alemán"</string>
-    <!-- XL -->
-    <string name="subtype_mode_en_voice">"Voz en inglés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_es_voice" msgid="1243071504878834350">"Voz en español"</string>
-    <!-- XL -->
-    <string name="subtype_mode_fr_voice" msgid="2048805677248981105">"Voz en francés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_ja_voice" msgid="1855513591711108481">"Voz en japonés"</string>
-    <!-- XL -->
-    <string name="subtype_mode_ko_voice" msgid="3453153041889151316">"Voz en coreano"</string>
-    <!-- XL -->
-    <string name="subtype_mode_pl_voice" msgid="6730658974157645735">"Voz en polaco"</string>
-    <!-- XL -->
-    <string name="subtype_mode_pt_voice" msgid="4508062762756741654">"Voz en portugués"</string>
-    <!-- XL -->
-    <string name="subtype_mode_ru_voice" msgid="554299262138845594">"Voz en ruso"</string>
-    <!-- XL -->
-    <string name="subtype_mode_tr_voice" msgid="5242644971865917801">"Voz en turco"</string>
-    <!-- XL -->
-    <string name="subtype_mode_yue_voice">"Voz en chino, yue"</string>
-    <!-- XL -->
-    <string name="subtype_mode_zh_voice">"Voz en chino, mandarín"</string>
-    <!-- XL -->
-    <string name="subtype_mode_zu_voice">"Voz en isiZulu"</string>
-    <!-- XL -->
-    <string name="prefs_usability_study_mode" msgid="8423000345880575687">"Modo estudio de usabilidad"</string>
-</resources>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 44007e2eaf87897610160e802ded5e0e5c83ec3e..02f36ff793a105e56d51a70aa71f349a27f14c0f 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones de entrada"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar teclas"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sonar al pulsar las teclas"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Aviso emergente sobre keypress"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Configuración de sugerencia de palabra"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Aviso emergente al pulsar tecla"</string>
+    <string name="general_category" msgid="1859088467017573195">"General"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Corrección de texto"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Arreglos rápidos"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige errores de escritura comunes"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostrar sugerencias de correcciones"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Mostrar palabras sugeridas al escribir"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostrar siempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostrar en modo retrato"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Ocultar siempre"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de configuración"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar siempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Ocultar siempre"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugerencias de palabras"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corregir automáticamente la palabra anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Corrección automática"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"La barra espaciadora y puntuación insertan automáticamente las palabras corregidas"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desactivado"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugerencias de Vigoran"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utiliza la palabra anterior para mejorar la sugerencia"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Siguiente"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Hecho"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Más"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Eliminar"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Volver"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Configuración"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Mayús"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espacio"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Símbolos"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Entrada de voz"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Símbolos activados"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Símbolos desactivados"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Mayús activado"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Mayús desactivado"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada por voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La entrada por voz no está admitida en tu idioma, pero sí funciona en inglés."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada por voz es una característica experimental que utiliza la red de reconocimiento de voz de Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la entrada por voz, ve a configuración del teclado."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para realizar entrada por voz, presiona el botón del micrófono o desliza tus dedos por el teclado en pantalla."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada de voz usa el reconocimiento de voz de Google. "<a href="http://m.google.com/privacy">"Se aplica la política de privacidad para"</a>" celulares."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la entrada de voz, ve a la configuración de métodos de entrada."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar entrada de voz, presiona el botón micrófono."</string>
     <string name="voice_listening" msgid="467518160751321844">"Habla ahora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Procesando"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
     <string name="ok" msgid="7898366843681727667">"Aceptar"</string>
     <string name="voice_input" msgid="2466640768843347841">"Entrada por voz"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"En el teclado principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"En el teclado de símbolos"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Desactivado"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micrófono en el teclado principal"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micrófono en el teclado de símbolos"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"La entrada por voz está inhabilitada"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Seleccionar método de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Deslizarse manualmente por la barra espaciadora para cambiar el idioma"</string>
@@ -105,74 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar los comentarios del usuario"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto al enviar las estadísticas de uso y los informes de error a Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corregir palabras"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca las palabras ingresadas que desees corregir"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca las palabras ingresadas que desees corregir solo cuando las sugerencias estén visibles."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema del teclado"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Teclado en checo"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Teclado en danés"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclado en alemán"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclado en inglés (Reino Unido)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclado en inglés (EE.UU.)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Teclado en español"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Teclado en español (EE.UU.)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Teclado en francés"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Teclado en francés (Canadá)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Teclado en francés (Suiza)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclado en italiano"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Teclado en noruego"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Teclado en holandés"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Teclado en ruso"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Teclado en serbio"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Teclado en sueco"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voz en Afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voz en checo"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voz en alemán"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voz en inglés"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voz en español"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voz en francés"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voz italiana"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voz en japonés"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voz en coreano"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voz holandesa"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voz en polaco"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voz en portugués"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voz en ruso"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voz en turco"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voz en Yue, chino"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voz en mandarín, chino"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voz en isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modo estudio de usabilidad"</string>
 </resources>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 511141c042edb247ec140956b6d6443791a50b71..f9a86ffd636299c6c4037ed6432c322aa456d137 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opciones introducción texto"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar al pulsar tecla"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sonido al pulsar tecla"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Popup al pulsar"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Ajustes de sugerencia de palabras"</string>
-    <string name="auto_cap" msgid="1719746674854628252">"Uso de mayúsculas auto."</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Popup al pulsar tecla"</string>
+    <string name="general_category" msgid="1859088467017573195">"General"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Corrección ortográfica"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Mayúsculas automáticas"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcciones rápidas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige los errores tipográficos que se cometen con más frecuencia."</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostrar sugerencias de correcciones"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Muestra las palabras sugeridas mientras se escribe."</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostrar siempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostrar en modo vertical"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Ocultar siempre"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de ajustes"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automáticamente"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar siempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Ocultar siempre"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugerencias de palabras"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corregir automáticamente la palabra anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autocorrección"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Espacio y punt para corregir errores"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desactivada"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Parcial"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Total"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugerencias de bigramas"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Usar palabra anterior para mejorar sugerencias"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Sig."</string>
     <string name="label_done_key" msgid="2441578748772529288">"Listo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Más"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Eliminar"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Retroceso"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Ajustes"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Mayús"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espacio"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Símbolos"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulador"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Entrada de voz"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Símbolos activados"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Símbolos desactivados"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Mayús activadas"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Mayús desactivadas"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Introducción de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente la introducción de voz no está disponible en tu idioma, pero se puede utilizar en inglés."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La introducción de voz es una función en fase experimental que utiliza la tecnología de reconocimiento de voz en red de Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la función de introducción de voz, accede a la configuración del teclado."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar la función de introducción de voz, pulsa el botón de micrófono o desliza el dedo por el teclado en pantalla."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada de voz utiliza el reconocimiento de voz de Google. Se aplica la "<a href="http://m.google.com/privacy">"Política de privacidad de Google para móviles"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la función de entrada de voz, accede a los ajustes del método de introducción de texto."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar la entrada de voz, pulsa el botón de micrófono."</string>
     <string name="voice_listening" msgid="467518160751321844">"Habla ahora"</string>
     <string name="voice_working" msgid="6666937792815731889">"En curso"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
     <string name="ok" msgid="7898366843681727667">"Aceptar"</string>
     <string name="voice_input" msgid="2466640768843347841">"Introducción de voz"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"En teclado principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"En teclado símbolos"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Desactivada"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro en tecl princ"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro en tecl símb"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entrada de voz inhab"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Seleccionar método de introducción de texto"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Deslizar el dedo por la barra espaciadora para cambiar el idioma"</string>
@@ -105,74 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar comentarios de usuarios"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto enviando estadísticas de uso e informes de error a Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corregir palabras"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tocar palabras introducidas para corregirlas"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca las palabras introducidas para corregirlas, solo cuando las sugerencias sean visibles."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema de teclado"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Teclado checo"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Teclado danés"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclado alemán"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclado inglés (Reino Unido)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclado de inglés (EE.UU.)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Teclado español"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Teclado en español (EE.UU.)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Teclado francés"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Teclado francés (Canadá)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Teclado francés (Suiza)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclado italiano"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Teclado noruego"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Teclado holandés"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Teclado ruso"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Teclado serbio"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Teclado sueco"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voz afrikáans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Google Voice en checo"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Google Voice en alemán"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voz inglesa"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Google Voice en español"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Google Voice en francés"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voz italiana"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Google Voice en japonés"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Google Voice en coreano"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voz holandesa"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Google Voice en polaco"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Google Voice en portugués"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Google Voice en ruso"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Google Voice en turco"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voz china (cantonés)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voz china (mandarín)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voz zulú"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modo de estudio de uso"</string>
 </resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index db370757cefd5f5ae4025ec553d07356d0415c26..b594411accaa4b5691819123b0ff6e409c6aae15 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"صدا با فشار کلید"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"بازشو با فشار کلید"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"تنظیمات پیشنهاد کلمه"</string>
+    <string name="general_category" msgid="1859088467017573195">"کلی"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"تصحیح متن"</string>
     <string name="auto_cap" msgid="1719746674854628252">"نوشتن با حروف بزرگ خودکار"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"راه حل های سریع"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"تصحیح خطاهای تایپی رایج"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"نمایش پیشنهادات تصحیح"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"نمایش واژه های پیشنهادی در حین تایپ"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"همیشه نمایش داده شود"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"نمایش در حالت عمودی"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"همیشه پنهان شود"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"نمایش کلید تنظیمات"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"خودکار"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"همیشه نمایش"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"همیشه پنهان"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"پیشنهادات کلمه"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"تصحیح خودکار کلمه قبلی"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"تصحیح خودکار"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"کلید فاصله و علائم نگارشی به صورت خودکار کلماتی را که غلط تایپ شده اند تصحیح می کنند"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"خاموش"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"متوسط"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"فعال"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"توضیحات بیگرام"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"برای بهبود پیشنهاد از کلمه قبلی استفاده شود"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"بعدی"</string>
     <string name="label_done_key" msgid="2441578748772529288">"انجام شد"</string>
     <string name="label_send_key" msgid="2815056534433717444">"ارسال"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"بیشتر"</string>
     <string name="label_pause_key" msgid="181098308428035340">"توقف موقت"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"منتظر بمانید"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"تنظیمات"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"فاصله"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"نمادها"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"ورودی صوتی"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"نمادها روشن"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"نمادها خاموش"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift روشن"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift خاموش"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"ورودی صوتی"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ورودی صوتی در حال حاضر برای زبان شما پشتیبانی نمی شود اما برای زبان انگلیسی فعال است."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ورودی صوتی یک ویژگی آزمایشی با استفاده از تشخیص گفتار شبکه Google است."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"برای خاموش کردن ورودی صدا، به تنظیمات صفحه کلید بروید."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"برای استفاده از ورودی صوتی، دکمه میکروفن را فشار دهید یا انگشت خود را روی صفحه کلید روی صفحه حرکت دهید."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ورودی صوتی از تشخیص صدای Google استفاده می کند. "<a href="http://m.google.com/privacy">"خط مشی رازداری Mobile "</a>" اعمال می شود."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"برای خاموش کردن ورودی صدا، به تنظیمات روش ورودی بروید."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"برای استفاده از ورودی صوتی، دکمه میکروفن را فشار دهید."</string>
     <string name="voice_listening" msgid="467518160751321844">"اکنون صحبت کنید"</string>
     <string name="voice_working" msgid="6666937792815731889">"در حال کار"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"لغو"</string>
     <string name="ok" msgid="7898366843681727667">"تأیید"</string>
     <string name="voice_input" msgid="2466640768843347841">"ورودی صوتی"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"در صفحه کلید اصلی"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"در صفحه کلید نمادها"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"خاموش"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"میکروفن در صفحه کلید اصلی"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"میکروفن در صفحه کلید نمادها"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ورودی صدا غیرفعال است"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"انتخاب روش ورودی"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"زبان های ورودی"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"برای تغییر زبان انگشت را روی کلید فاصله بلغزانید"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"فعال کردن بازخورد کاربر"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"با ارسال خودکار آمارهای کاربرد و گزارش های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"برای تصحیح کلمات لمس کنید"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"برای تصحیح کلمات وارد شده آنها را لمس کنید"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"فقط هنگامی که پیشنهادات قابل مشاهده هستند، برای تصحیح کلمات وارد شده آنها را لمس کنید"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"طرح زمینه صفحه کلید"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"صفحه کلید چک"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"صفحه کلید دانمارکی"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"صفحه کلید آلمانی"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"صفحه کلید انگلیسی (بریتانیای کبیر)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"صفحه کلید انگلیسی (ایالات متحده)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"صفحه کلید آلمانی"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"صفحه کلید انگلیسی (بریتانیایی)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"صفحه کلید انگلیسی (آمریکایی)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"صفحه کلید اسپانیایی"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"صفحه کلید اسپانیایی (آمریکایی)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"صفحه کلید فرانسوی"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"صفحه کلید ایتالیایی"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"صفحه کلید فرانسوی (کانادایی)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"صفحه کلید فرانسوی (سوئیس)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"صفحه کلید ایتالیایی"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"صفحه کلید نروژی"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"صفحه کلید هلندی"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"صفحه کلید روسی"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"صفحه کلید صربی"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"صفحه کلید سوئدی"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"صدای چک"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"صدای آلمانی"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"صدای انگلیسی (استرالیا)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"صدای انگلیسی (بریتانیای کبیر)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"صدای انگلیسی (هندوستان)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"صدای انگلیسی (نیوزیلند)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"صدای انگلیسی (ایالات متحده)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"صدای آفریکانس"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"صدای چک"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"صدای آلمانی"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"صدای انگلیسی"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"صدای اسپانیایی"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"صدای فرانسوی"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"صدای ایتالیایی"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"صدای ژاپنی"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"صدای کره ای"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"صدای هلندی"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"صدای لهستانی"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"صدای پرتغالی"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"صدای روسی"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"صدای ترکی"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"صدای چینی (چین)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"صدای چینی (تایوان)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"صدای چینی، یوئه"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"صدای چینی، ماندارین"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"صدای ایزی زولو"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"حالت تست قابلیت استفاده"</string>
 </resources>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index 71c0a9b865965c31613ddceb5e078a08f21be6c4..0bf385552b9b1a82cc245807312854209f34f3c1 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Toista ääni näppäimiä painettaessa"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Ponnahdusikkuna painalluksella"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Sanaehdotusasetukset"</string>
+    <string name="general_category" msgid="1859088467017573195">"Yleinen"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Tekstin korjaus"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automaattiset isot kirjaimet"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Pikakorjaukset"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Korjaa yleiset kirjoitusvirheet"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Näytä korjausehdotukset"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Näytä sanaehdotukset kirjoitettaessa"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Näytä aina"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Näytä pystysuunnassa"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Piilota aina"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Näytä asetukset-näppäin"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automaattinen"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Näytä aina"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Piilota aina"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sanaehdotukset"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Korjaa edellinen sana automaattisesti"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autom. korjaus"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Välilyönnit ja välimerkit korjaavat väärinkirjoitetut sanat automaattisesti"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Älä käytä"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Osittainen"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Täysi"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram-ehdotukset"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Paranna ehdotusta aiemman sanan avulla"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Tallennettu"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Seuraava"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Lisää"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Tauko"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Odota"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Poista"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Rivinvaihto"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Asetukset"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Välilyönti"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symbolit"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Sarkain"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Äänisyöte"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symbolit käytössä"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symbolit pois käytöstä"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift käytössä"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift pois käytöstä"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Äänisyöte"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Äänisyötettä ei vielä tueta kielelläsi, mutta voit käyttää sitä englanniksi."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Äänisyöte on kokeellinen Googlen puheentunnistusta käyttävä ominaisuus."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Siirry näppäimistön asetuksiin poistaaksesi äänisyötteen käytöstä."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Käytä äänisyötettä painamalla mikrofonipainiketta tai liu\'uttamalla sormeasi näytön näppäimistön poikki."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Äänisyöte käyttää Googlen puheentunnistusta. "<a href="http://m.google.com/privacy">"Mobile-tietosuojakäytäntö"</a>" on voimassa."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Siirry syöttöasetuksiin poistaaksesi äänisyötteen käytöstä."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ota äänisyöte käyttöön painamalla mikrofonikuvaketta."</string>
     <string name="voice_listening" msgid="467518160751321844">"Puhu nyt"</string>
     <string name="voice_working" msgid="6666937792815731889">"Työstetään"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Peruuta"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Äänisyöte"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Päänäppäimistössä"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Symbolinäppäimistössä"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Älä näytä"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr. päänäppäim."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. symbolinäppäim."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Ääniohjaus on pois käytöstä"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Valitse syöttötapa"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Syöttökielet"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Vaihda kieltä liu\'uttamalla sormea välilyöntinäppäimellä"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Ota käyttäjäpalaute käyttöön"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Auta parantamaan tätä syöttötavan muokkausohjelmaa lähettämällä automaattisesti käyttötietoja ja kaatumisraportteja Googlelle."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Korjaa sanoja koskettamalla"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Korjaa sanoja koskettamalla niitä"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Korjaa annetut sanat napauttamalla. (Vain, kun ehdotuksia on näkyvillä.)"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Näppäimistön teema"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Näppäimistö: tšekki"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Näppäimistö: tanska"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Ääni: saksa"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Ääni: englanti (Iso-Britannia)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Näppäimistö: englanti (Yhdysvallat)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Näppäimistö: saksa"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Näppäimistö: englanti (UK)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Näppäimistö: englanti (US)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Näppäimistö: espanja"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Näppäimistö: espanja (US)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Näppäimistö: ranska"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Näppäimistö: italia"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Näppäimistö: ranska (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Näppäimistö: ranska (Sveitsi)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Näppäimistö: italia"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Näppäimistö: norja"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Näppäimistö: hollanti"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Näppäimistö: venäjä"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Näppäimistö: serbia"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Näppäimistö: ruotsi"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Ääni: tšekki"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Ääni: saksa"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Ääni: englanti (Australia)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Ääni: englanti (Iso-Britannia)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Ääni: englanti (Intia)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Ääni: englanti (Uusi-Seelanti)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Ääni: englanti (Yhdysvallat)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Ääni: afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Ääni: tšekki"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Ääni: saksa"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Ääni: englanti"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Ääni: espanja"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Ääni: ranska"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"italia (ääni)"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Ääni: japani"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Ääni: korea"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"hollanti (ääni)"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Ääni: puola"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Ääni: portugali"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Ääni: venäjä"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Ääni: turkki"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Ääni: kiina (Kiina)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Ääni: kiina (Taiwan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Ääni: kiina, yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Ääni: mandariinikiina"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Ääni: isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Käytettävyystutkimustila"</string>
 </resources>
diff --git a/java/res/values-fr/donottranslate.xml b/java/res/values-fr/donottranslate.xml
index b79df7b3702f1324f2c3bfd18ebdf2c1f55773d1..6c3536210fd4f15a2838f5579b928dcfaa264d1b 100644
--- a/java/res/values-fr/donottranslate.xml
+++ b/java/res/values-fr/donottranslate.xml
@@ -19,7 +19,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Symbols that are commonly considered word separators in this language -->
-    <string name="word_separators">.\u0009\u0020,;:!?\'\n()[]*&amp;@{}/&lt;&gt;_+=|\u0022</string>
+    <string name="word_separators">.\u0009\u0020,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|\u0022</string>
     <!-- Symbols that are sentence separators, for purposes of making it hug the last sentence. -->
     <string name="sentence_separators">.,</string>
 </resources>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 7148ef53267c13275680201f7891b28d58160d48..b7aac944567270e74b3894d95e3bce2a37180f1f 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Options de saisie"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer à chaque touche"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Son à chaque touche"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères à chaque touche"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Paramètres de la saisie prédictive"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Agrandir les caractères"</string>
+    <string name="general_category" msgid="1859088467017573195">"Général"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Correction du texte"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Majuscules auto"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Corrections rapides"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige les fautes de frappe courantes"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
-    <string name="prefs_settings_key" msgid="4623341240804046498">"Afficher la touche des paramètres"</string>
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Afficher les suggestions de correction"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Afficher les suggestions de terme lors de la saisie"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Toujours afficher"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Afficher en mode Portrait"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Toujours masquer"</string>
+    <string name="prefs_settings_key" msgid="4623341240804046498">"Afficher touche param."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatique"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Toujours afficher"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Toujours masquer"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Saisie prédictive"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corriger automatiquement le mot précédent"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Correction auto"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Corriger autom. orthographe (pression sur barre espace/signes ponctuation)"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Désactiver"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Simple"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Proactive"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Suggestions de type bigramme"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Améliorer la suggestion en fonction du mot précédent"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Suivant"</string>
     <string name="label_done_key" msgid="2441578748772529288">"OK"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Envoyer"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Plus"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Attente"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Supprimer"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Entrée"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Paramètres"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Maj"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espace"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboles"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulation"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Saisie vocale"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symboles activés"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symboles désactivés"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Maj activée"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Maj désactivée"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Saisie vocale"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La saisie vocale est une fonctionnalité expérimentale qui fait appel à la reconnaissance vocale en réseau de Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pour désactiver la saisie vocale, accédez aux paramètres du clavier."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone ou faites glisser votre doigt sur le clavier à l\'écran."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La saisie vocale fait appel à la reconnaissance vocale de Google. Les "<a href="http://m.google.com/privacy">"Règles de confidentialité Google Mobile"</a>" s\'appliquent."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pour désactiver la saisie vocale, accédez aux paramètres du mode de saisie."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone."</string>
     <string name="voice_listening" msgid="467518160751321844">"Parlez maintenant"</string>
     <string name="voice_working" msgid="6666937792815731889">"Traitement en cours"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Annuler"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Saisie vocale"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sur clavier principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sur clavier symboles"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Désactiver"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micro clavier principal"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micro sur clavier symboles"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Saisie vocale désactivée"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Sélectionner un mode de saisie."</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Faites glisser votre doigt sur la barre d\'espacement pour changer la langue."</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Autoriser les commentaires des utilisateurs"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Contribuer à l\'amélioration de cet éditeur du mode de saisie grâce à l\'envoi automatique de statistiques d\'utilisation et de rapports d\'incident à Google."</string>
-    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Appuyer pour corriger les suggestions"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Appuyer sur les mots saisis pour les corriger"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Appuyer pour corriger"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Appuyer sur les mots saisis pour les corriger, uniquement lorsque des suggestions sont visibles"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Thème du clavier"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Clavier tchèque"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Clavier danois"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Clavier allemand"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Clavier anglais (Royaume-Uni)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Clavier anglais (États-Unis)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Clavier espagnol"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Clavier espagnol (États-Unis)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Clavier français"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Clavier français (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Clavier français (Suisse)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Clavier italien"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Clavier norvégien"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Clavier néerlandais"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Clavier russe"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Clavier serbe"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Clavier suédois"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voix parlant afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voix tchèque"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voix allemande"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voix parlant anglais"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voix espagnole"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voix française"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voix parlant italien"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voix japonaise"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voix coréenne"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voix parlant néerlandais"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voix polonaise"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voix portugaise"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voix russe"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voix turque"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voix parlant chinois (cantonais)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voix parlant chinois (mandarin)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voix parlant zoulou"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Mode d\'étude de l\'utilisation"</string>
 </resources>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index dcee1b1d25cb0bc9a830b594c506a8e43c7558a6..e6879a6d1cc7e01ab6dd9982008d03d607bbebef 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri pritisku tipke"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Povećanja na pritisak tipke"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Postavke prijedloga riječi"</string>
+    <string name="general_category" msgid="1859088467017573195">"Općenito"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Ispravak teksta"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automatsko pisanje velikih slova"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Brzi popravci"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Ispravlja uobičajene pogreške u pisanju"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Pokaži prijedloge ispravka"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Prikazivanje predloženih riječi prilikom upisivanja"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Uvijek prikaži"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Prikaži u portretnom načinu"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Uvijek sakrij"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Prikaži tipku postavki"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatski"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Uvijek prikaži"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Uvijek sakrij"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Prijedlozi riječi"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automatsko ispravljanje prethodne riječi"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Samoispravak"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Razm. i intrp. aut. ispr. kr. rči."</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Isključeno"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Skromno"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivno"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram prijedlozi"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Upotrijebi prethodnu riječ radi poboljšanja prijedloga"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Dalje"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Gotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Pošalji"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Više"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Pričekaj"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Postavke"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Razmaknica"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simboli"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulator"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Glasovni unos"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simboli uključeni"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simboli isključeni"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift uključen"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift isključen"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni unos"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Vaš jezik trenutno nije podržan za glasovni unos, ali radi za engleski."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni unos je pokusna značajka koja koristi Googleovo umreženo prepoznavanje govora."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Za isključivanje glasovnog unosa idite na postavke tipkovnice."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Da biste koristili glasovni unos pritisnite gumb mikrofona ili kliznite prstom preko tipkovnice na zaslonu."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni unos upotrebljava Googleovo prepoznavanje govora. Primjenjuju se "<a href="http://m.google.com/privacy">"Pravila o privatnosti za uslugu Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Za isključivanje glasovnog unosa idite na postavke načina unosa."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Za upotrebu glasovnog unosa pritisnite gumb mikrofona."</string>
     <string name="voice_listening" msgid="467518160751321844">"Govorite sad"</string>
     <string name="voice_working" msgid="6666937792815731889">"Obrada"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Odustani"</string>
     <string name="ok" msgid="7898366843681727667">"U redu"</string>
     <string name="voice_input" msgid="2466640768843347841">"Glasovni unos"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na glavnoj tipkovnici"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na tipkovnici simb."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Isključeno"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. na gl. tipk."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. na tipk. simb."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Glas. unos onemog."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Odabir ulazne metode"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jezici unosa"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Kliznite prstom po razmaknici za promjenu jezika"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Omogući korisničke povratne informacije"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Pomozite u poboljšanju ovog urednika ulazne metode automatskim slanjem statistike upotrebe i padova Googleu."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dodirnite za ispravak riječi"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dodirnite unesene riječi radi ispravka"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dodirnite unesene riječi da biste ih ispravili samo kada su prijedlozi vidljivi"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema tipkovnice"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Češka tipkovnica"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danska tipkovnica"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Njemačka tipkovnica"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engleska (Velika Britanija) tipkovnica"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engleska (SAD) tipkovnica"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Njemačka tipkovnica"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engleska (UK) tipkovnica"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engleska (SAD) tipkovnica"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Å panjolska tipkovnica"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Tipkovnica za Å¡panjolski (SAD)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Francuska tipkovnica"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Talijanska tipkovnica"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Francuska (Kanada) tipkovnica"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Francuska (Å vicarska) tipkovnica"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Talijanska tipkovnica"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norveška tipkovnica"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Nizozemska tipkovnica"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Ruska tipkovnica"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Srpska tipkovnica"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Å vedska tipkovnica"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Češki glas"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Njemački glas"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Engleski (Australija) glas"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Engleski (Velika Britanija) glas"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Engleski (Indija) glas"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Engleski (Novi Zeland) glas"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Engleski (SAD) glas"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"afrikaans glasovno"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Češki glasovni"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Njemački glasovni"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"engleski glasovno"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Å panjolski glas"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Francuski glas"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Talijanski glas"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japanski glas"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Korejski glas"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Nizozemski glas"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Poljski glas"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugalski glas"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Ruski glas"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Turski glas"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Kineski (Kina) glas"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Kineski (Tajvan) glas"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"kineski, Yue glasovno"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"kineski, mandarinski glasovno"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu glasovno"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Način studije upotrebljivosti"</string>
 </resources>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index 8d64d243d8ab9e37902bbb0f0d53d27addb46802..a8bf98367c8cd4cb6edb9a74234ba4976aba9d17 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés billentyű megnyomása esetén"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Hangjelzés billentyű megnyomása esetén"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Legyen nagyobb billentyű lenyomásakor"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Szójavaslati beállítások"</string>
+    <string name="general_category" msgid="1859088467017573195">"Általános"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Szövegjavítás"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automatikusan nagy kezdőbetű"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Gyorsjavítások"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Kijavítja a gyakori gépelési hibákat"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Javítási ajánlások megjelenítése"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"A javasolt szavak megjelenítése gépelés közben"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mindig látszik"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Megjelenítés álló tájolásban"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Mindig rejtve"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Beállítások billentyű megjelenítése"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatikus"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mindig látszik"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Mindig rejtve"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Szójavaslatok"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Az előző szó automatikus kijavítása"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatikus javítás"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Szóköz és központozás automatikusan javítja az elgépelést"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Ki"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mérsékelt"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresszív"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram javaslatok"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Előző szó használata a javaslatok javításához"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Tovább"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Kész"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Küldés"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Egyebek"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Szün."</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Vár"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Törlés"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Vissza"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Beállítások"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Szóköz"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Szimbólumok"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Hangbevitel"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Szimbólumok be"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Szimbólumok ki"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift be"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift ki"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Hangbevitel"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A hangbevitel szolgáltatás jelenleg nem támogatja az Ön nyelvét, ám angolul működik."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A hangbevitel a Google hálózati beszédfelismerését alkalmazó kísérleti funkció."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"A hangbevitelt a billentyűzet beállításai között lehet kikapcsolni."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"A hangbevitel használatához nyomja meg a mikrofon gombját vagy húzza végig az ujját a képernyő-billentyűzeten."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A hangbevitel a Google beszédfelismerő technológiáját használja, amelyre a "<a href="http://m.google.com/privacy">"Mobil adatvédelmi irányelvek"</a>" érvényesek."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"A hangbevitelt a beviteli mód beállításai között lehet kikapcsolni."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"A hangbevitel használatához nyomja meg a mikrofon gombot."</string>
     <string name="voice_listening" msgid="467518160751321844">"Most beszéljen"</string>
     <string name="voice_working" msgid="6666937792815731889">"Feldolgozás"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Mégse"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Hangbevitel"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"A fő billentyűzeten"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Szimbólumoknál"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Ki"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr. a billentyűzeten"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr. a szimbólumoknál"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hangbevivel KI"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Beviteli mód kiválasztása"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Beviteli nyelvek"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"A nyelv módosításához húzza végig az ujját a szóköz billentyűn"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Felhasználói visszajelzés engedélyezése"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Segíthet ennek a beviteli módszernek a javításában, ha engedélyezi a használati statisztikák és a hibajelentések elküldését a Google-nak."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Javítás a szavak megérintésével"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"A beírt szavakat megérintve kijavíthatja őket"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"A beírt szavakat csak akkor javíthatja ki megérintve, ha látszanak javaslatok"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Billentyűzettéma"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Cseh billentyűzet"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Dán billentyűzet"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Német billentyűzet"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angol (brit) billentyűzet"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angol (amerikai) billentyűzet"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Német billentyűzet"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angol (UK) billentyűzet"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angol (US) billentyűzet"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spanyol billentyűzet"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spanyol (US) billentyűzet"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Francia billentyűzet"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Olasz billentyűzet"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Francia (kanadai) billentyűzet"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Francia (svájci) billentyűzet"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Olasz billentyűzet"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norvég billentyűzet"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Holland billentyűzet"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Orosz billentyűzet"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Szerb billentyűzet"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Svéd billentyűzet"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Cseh hang"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Német hang"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Angol (ausztrál) hang"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Angol (brit) hang"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Angol (indiai) hang"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Angol (új-zélandi) hang"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Angol (amerikai) hang"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaans hang"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Cseh hang"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Német hang"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Angol hang"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spanyol hang"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Francia hang"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Olasz hang"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japán hang"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Koreai hang"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Holland hang"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Lengyel hang"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugál hang"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Orosz hang"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Török hang"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Kínai (kínai) hang"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Kínai (tajvani) hang"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Kínai (jüe) hang"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Kínai (mandarin) hang"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu hang"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Használhatóság - tanulás mód"</string>
 </resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 60d50b46b58f0991b8fb157a1794a0a4514c7138..4df7f1e7f397c94af35bb965160d2b4f0d373ace 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Berbunyi jika tombol ditekan"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Muncul saat tombol ditekan"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Setelan saran kata"</string>
+    <string name="general_category" msgid="1859088467017573195">"Umum"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Koreksi teks"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Kapitalisasi otomatis"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Perbaikan cepat"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Memperbaiki kesalahan ketik umum"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Tampilkan saran koreksi"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Tampilkan kata yang disarankan ketika mengetik"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Selalu tampilkan"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Tampilkan pada mode potret"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Selalu sembunyikan"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Lihat tombol setelan"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Otomatis"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Selalu tampilkan"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Selalu sembunyikan"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Saran kata"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Perbaiki kata sebelumnya secara otomatis"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Koreksi otomatis"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Bilah spasi dan tanda baca secara otomatis dikoreksi pada kata yang salah ketik"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Mati"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Sederhana"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresif"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Saran Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Gunakan kata sebelumnya untuk meningkatkan sara"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Berikutnya"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Kirimkan"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Lainnya"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Jeda"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Tunggu"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Hapus"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Setelan"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Spasi"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simbol"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Masukan Suara"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simbol hidup"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simbol mati"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift hidup"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift mati"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Masukan suara"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Masukan suara saat ini tidak didukung untuk bahasa Anda, tetapi bekerja dalam Bahasa Inggris."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Masukan suara adalah fitur eksperimental yang menggunakan pengenal suara berjaringan Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Untuk mematikan masukan suara, buka setelan keyboard."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Untuk menggunakan masukan suara, tekan tombol mikrofon atau geser jari Anda di sepanjang keyboard pada layar."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Masukan suara menggunakan pengenalan ucapan Google. "<a href="http://m.google.com/privacy">"Kebijakan Privasi Seluler"</a>" berlaku."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Untuk mematikan masukan suara, buka setelan metode masukan."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Untuk menggunakan masukan suara, tekan tombol mikrofon."</string>
     <string name="voice_listening" msgid="467518160751321844">"Ucapkan sekarang"</string>
     <string name="voice_working" msgid="6666937792815731889">"Bekerja"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Batal"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Masukan suara"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pada keyboard utama"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Pada keyboard simbol"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Mati"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik pada keyboard utama"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik pada keyboard simbol"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Masukan suara dinonaktifkan"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Pilih metode masukan"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Bahasa masukan"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Geser jari pada bilah spasi untuk mengubah bahasa"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktifkan umpan balik pengguna"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Bantu tingkatkan metode editor masukan dengan mengirim statistik penggunaan dan laporan kerusakan ke Google secara otomatis."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Sentuh untuk memperbaiki kata"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Sentuk kata yang dimasukkan untuk memperbaikinya"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Sentuh kata yang dimasukkan untuk memperbaikinya, hanya saat saran dapat dilihat"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema Keyboard"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Keyboard Cheska"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Keyboard Denmark"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Keyboard Jerman"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Keyboard Inggris (Inggris Raya)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Keyboard Inggris (Amerika Serikat)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Keyboard Jerman"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Keyboard Inggris (Britania Raya)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Keyboard Inggris (AS)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Keyboard Spanyol"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Keyboard Spanyol (AS)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Keyboard Prancis"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Keyboard Italia"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Keyboard Prancis (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Keyboard Prancis (Swiss)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Keyboard Italia"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Keyboard Norwegia"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Keyboard Belanda"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Keyboard Rusia"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Keyboard Serbia"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Keyboard Swedia"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Suara Cheska"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Suara Jerman"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Suara Bahasa Inggris (Australia)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Suara Bahasa Inggris (Inggris Raya)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Suara Bahasa Inggris (India)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Suara Bahasa Inggris (Selandia Baru)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Suara Bahasa Inggris (Amerika Serikat)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Suara Bahasa Afrika"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Suara Bahasa Cheska"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Suara Bahasa Jerman"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Suara Bahasa Inggris"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Suara Bahasa Spanyol"</string>
-    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Suara Prancis"</string>
-    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Suara Jepang"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Suara Bahasa Prancis"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Suara Bahasa Italia"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Suara Bahasa Jepang"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Suara Bahasa Korea"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Suara Bahasa Belanda"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Suara Bahasa Polandia"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Suara Bahasa Portugis"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Suara Bahasa Rusia"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Suara Bahasa Turki"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Suara Bahasa China (China)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Suara Bahasa China (Taiwan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Suara Bahasa China, Yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Suara Bahasa China, Mandarin"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Suara Zulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Mode Studi Daya Guna"</string>
 </resources>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 45bca4db5e00162726fe093beb3999e706845277..9bf4f9e301a57aa19daac67a23353d81dbc1a2df 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opzioni inserimento"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrazione tasti"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Suono tasti"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Popup alla pressione di un tasto"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Impostazioni suggerimento parole"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Popup sui tasti"</string>
+    <string name="general_category" msgid="1859088467017573195">"Generali"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Correzione testo"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Maiuscole automatiche"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correzioni veloci"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corregge gli errori di digitazione più comuni"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
-    <string name="prefs_settings_key" msgid="4623341240804046498">"Mostra tasto impostazioni"</string>
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostra suggerimenti correzioni"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Visualizza le parole suggerite durante la digitazione"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostra sempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostra in modalità verticale"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Nascondi sempre"</string>
+    <string name="prefs_settings_key" msgid="4623341240804046498">"Mostra tasto impostaz."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatico"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostra sempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Nascondi sempre"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Suggerimenti parola"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Correggi automaticamente la parola precedente"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Correzione automatica"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Barra spaziatrice/punteggiatura correggono parole con errori"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Off"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Media"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Massima"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Suggerimenti sui bigrammi"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilizza parola precedente per migliorare il suggerimento"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Avanti"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Fine"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Invia"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Altro"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Attesa"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Cancella"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Invio"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Impostazioni"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Maiuscolo"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Spazio"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simboli"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulazione"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Input vocale"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simboli attivati"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simboli disattivati"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Maiuscole attivate"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Maiuscole disattivate"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Comandi vocali"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"I comandi vocali non sono attualmente supportati per la tua lingua ma funzionano in inglese."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"I comandi vocali sono una funzione sperimentale che utilizza il riconoscimento vocale in rete di Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per disattivare i comandi vocali, vai alle impostazioni della tastiera."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilizzare i comandi vocali, premi il pulsante del microfono o fai scorrere il dito sulla tastiera sullo schermo."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'input vocale utilizza il riconoscimento vocale di Google. Sono valide le "<a href="http://m.google.com/privacy">"norme sulla privacy di Google Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per disattivare l\'input vocale, vai alle impostazioni del metodo di input."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilizzare l\'input vocale, premi il pulsante del microfono."</string>
     <string name="voice_listening" msgid="467518160751321844">"Parla ora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Elaborazione in corso"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Annulla"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Comandi vocali"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Su tastiera principale"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Su tastiera simboli"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Non attivo"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic su tastiera princ."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic su tastiera simboli"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Comandi vocali disatt."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Seleziona metodo di inserimento"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Lingue comandi"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Scorri il dito sulla barra spaziatrice per cambiare la lingua"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Dizionario disponibile"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Attiva commenti degli utenti"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Aiuta a migliorare l\'editor del metodo di inserimento inviando automaticamente a Google statistiche sull\'utilizzo e segnalazioni sugli arresti anomali."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocca per correggere di nuovo le parole"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Puoi correggere di nuovo le parole toccando quelle che hai digitato"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocca per correggere"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tocca le parole inserite per correggerle, solo quando sono visibili i suggerimenti"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema della tastiera"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tastiera ceca"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Tastiera danese"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tastiera tedesca"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Tastiera inglese (Regno Unito)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Tastiera inglese (Stati Uniti)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Tastiera spagnola"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Tastiera spagnola (Stati Uniti)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Tastiera francese"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Tastiera francese (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Tastiera francese (Svizzera)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Tastiera italiana"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Tastiera norvegese"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Tastiera olandese"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Tastiera russa"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Tastiera serba"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Tastiera svedese"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voce afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voce ceca"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voce tedesca"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voce inglese"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voce spagnola"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voce francese"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voce italiana"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voce giapponese"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voce coreana"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voce olandese"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voce polacca"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voce portoghese"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voce russa"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voce turca"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voce cinese Yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voce cinese mandarino"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voce isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modalità studio usabilità"</string>
 </resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 12c031b9ed8abbbefa5bdf39bd51684750b50cf1..af0854c97f5beb2390db2ce67def10e7f509a782 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט עם לחיצה על מקשים"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"צלילים עם לחיצה על מקשים"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"חלון קופץ עם לחיצה על מקשים"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"הגדרות של הצעות מילים"</string>
+    <string name="general_category" msgid="1859088467017573195">"כללי"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"תיקון טקסט"</string>
     <string name="auto_cap" msgid="1719746674854628252">"הפיכה אוטומטית של אותיות לרישיות"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"תיקונים מהירים"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"מתקן שגיאות הקלדה נפוצות"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"הצג הצעות לתיקונים"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"הצג הצעות למילים בעת הקלדה"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"הצג תמיד"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"הצג בפריסה לאורך"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"הסתר תמיד"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"הצג מקש הגדרות"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"אוטומטי"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"הצג תמיד"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"הסתר תמיד"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"הצעות למילים"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"תקן באופן אוטומטי את המילה הקודמת"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"תיקון אוטומטי"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"מקש הרווח ופיסוק מתקנים אוטומטית שגיאות הקלדה"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"כבוי"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"מצומצם"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"מחמיר"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"הצעות של צמדי אותיות (Bigram)"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"השתמש במילה הקודמת כדי לשפר את ההצעה"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"הבא"</string>
     <string name="label_done_key" msgid="2441578748772529288">"בוצע"</string>
     <string name="label_send_key" msgid="2815056534433717444">"שלח"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"עוד"</string>
     <string name="label_pause_key" msgid="181098308428035340">"השהה"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"המתן"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"מחק"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"חזור"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"הגדרות"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"רווח"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"סמלים"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"כרטיסייה"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"קלט קולי"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"מצב סמלים פועל"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"מצב סמלים כבוי"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift פועל"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift כבוי"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"קלט קולי"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"קלט קולי אינו נתמך בשלב זה בשפתך, אך הוא פועל באנגלית."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"קלט קולי הוא תכונה ניסיונית של זיהוי הדיבור ברשת של Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"כדי לכבות את הקלט הקולי, עבור להגדרות מקלדת."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"כדי להשתמש בקלט הקולי, לחץ על לחצן המיקרופון או החלק את האצבע על המקלדת שבמסך."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"קלט קולי משתמש בזיהוי דיבור של Google.‏ "<a href="http://m.google.com/privacy">"מדיניות הפרטיות של \'Google לנייד\'"</a>" חלה במקרה זה."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"כדי לכבות את הקלט הקולי, עבור להגדרות שיטת קלט."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"כדי להשתמש בקלט קולי, לחץ על לחצן המיקרופון."</string>
     <string name="voice_listening" msgid="467518160751321844">"דבר כעת"</string>
     <string name="voice_working" msgid="6666937792815731889">"פועל"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"ביטול"</string>
     <string name="ok" msgid="7898366843681727667">"אישור"</string>
     <string name="voice_input" msgid="2466640768843347841">"קלט קולי"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"במקלדת הראשית"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"במקלדת הסמלים"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"כבוי"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"מיקרופון במקלדת הראשית"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"מיקרופון במקלדת הסמלים"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"הקלט הקולי מושבת"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"בחר שיטת קלט"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"שפות קלט"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"החלק את האצבע על מקש הרווח כדי לשנות שפה"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"הפוך משוב ממשתמשים לפעיל"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"עזור לשפר שיטת קלט זו על ידי שליחה אוטומטית של סטטיסטיקת שימוש ודוחות קריסת מחשב ל-Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"גע כדי לתקן מילים"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"גע במילים שהוזנו כדי לתקן אותן"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"גע במילים שהוזנו כדי לתקן אותן, רק כאשר הצעות מוצגות"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"עיצוב מקלדת"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"מקלדת צ\'כית"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"מקלדת דנית"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"מקלדת גרמנית "</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"מקלדת אנגלית (בריטניה)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"מקלדת אנגלית (ארצות הברית)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"מקלדת גרמנית "</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"מקלדת אנגלית (בריטניה)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"מקלדת אנגלית (ארה\"ב)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"מקלדת ספרדית"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"מקלדת ספרדית (ארה\"ב)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"מקלדת צרפתית"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"מקלדת איטלקית "</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"מקלדת צרפתית (קנדה)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"מקלדת צרפתית (שוויץ)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"מקלדת איטלקית"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"מקלדת נורווגית"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"מקלדת הולנדית"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"מקלדת רוסית"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"מקלדת סרבית"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"מקלדת שוודית"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Google Voice צ\'כי"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Google Voice גרמני"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Google Voice אנגלי (אוסטרליה)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Google Voice אנגלי (בריטניה)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Google Voice אנגלי (הודו)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Googel Voice אנגלי (ניו זילנד)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Google Voice אנגלי (ארצות הברית)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Google Voice באפריקאנס"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Google Voice צ\'כי"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Google Voice גרמני"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Google Voice באנגלית"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Google Voice ספרדי"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Google Voice צרפתי"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"קול באיטלקית"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Google Voice יפני"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Google Voice קוריאני"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"קול בהולנדית"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Google Voice פולני"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Google Voice פורטוגזי"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Google Voice רוסי"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Google Voice תורכי"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Google Voice סיני (סין)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Google Voice סיני (טייוואן)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Google Voice בסינית, יו"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Google Voice בסינית, מנדרינית"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Google Voice באיסיזולו"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"מצב מחקר שימושיות"</string>
 </resources>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 22bd0e448c623a58279b61bbf8dbd58136327e88..cd2cf8070de092aaf8be68d5310b25f5757db9cc 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"キー操作バイブ"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"キー操作音"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"キー押下時ポップアップ"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"入力候補の設定"</string>
+    <string name="general_category" msgid="1859088467017573195">"全般"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"テキストの修正"</string>
     <string name="auto_cap" msgid="1719746674854628252">"自動大文字変換"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"クイックフィックス"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"よくある誤字・脱字を修正します"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"修正候補を表示する"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"入力中に入力候補を表示する"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"常に表示"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"縦向きで表示"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"常に非表示"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"設定キーを表示"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自動"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"常に表示"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"常に非表示"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"入力候補表示"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"前の単語を自動修正する"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"自動修正"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"誤入力をスペースまたは句読点キーで修正する"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"OFF"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"中"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"å¼·"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"バイグラム入力候補表示"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"直前の単語から入力候補を予測します"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"次へ"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完了"</string>
     <string name="label_send_key" msgid="2815056534433717444">"送信"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Shift"</string>
     <string name="label_pause_key" msgid="181098308428035340">"停止"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"å¾…æ©Ÿ"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Del"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"設定"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Space"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"記号"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"音声入力"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"記号ON"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"記号OFF"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift ON"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift OFF"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"音声入力"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"音声入力は現在英語には対応していますが、日本語には対応していません。"</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"音声入力はGoogleのネットワーク音声認識技術を利用した試験段階の機能です。"</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"音声入力をOFFにするには、キーボードの設定を開きます。"</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"音声入力するには、マイクボタンを押すか画面キーボードをスワイプしてください。"</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"音声入力ではGoogleの音声認識技術を利用します。"<a href="http://m.google.com/privacy">"モバイルプライバシーポリシー"</a>"が適用されます。"</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"音声入力をOFFにするには、入力方法の設定を開きます。"</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"音声入力するには、マイクボタンを押してください。"</string>
     <string name="voice_listening" msgid="467518160751321844">"お話しください"</string>
     <string name="voice_working" msgid="6666937792815731889">"処理中"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"キャンセル"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"音声入力"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"メインキーボード上"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"記号キーボード上"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"OFF"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"メインキーボードのマイク"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"記号キーボードのマイク"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"音声入力は無効です"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"入力方法の選択"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"入力言語"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"スペースバーで指をスライドさせて言語を変更する"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"辞書を利用できます"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"ユーザーフィードバックを有効にする"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"IMEの機能向上のため、使用統計状況やクラッシュレポートをGoogleに自動送信します。"</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"タップして語句を再修正"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"入力した語句をタップすると語句を再修正できます"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"タップして語句を修正"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"候補が表示されているときのみ、入力した語句をタップして修正する"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"キーボードテーマ"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"チェコ語のキーボード"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"デンマーク語のキーボード"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"ドイツ語のキーボード"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"英語(英国)のキーボード"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"英語(米国)のキーボード"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"スペイン語のキーボード"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"スペイン語(米国)のキーボード"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"フランス語のキーボード"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"フランス語(カナダ)のキーボード"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"フランス語(スイス)のキーボード"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"イタリア語のキーボード"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"ノルウェー語のキーボード"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"オランダ語のキーボード"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"ロシア語のキーボード"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"セルビア語のキーボード"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"スウェーデン語のキーボード"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"アフリカーンス語の音声"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"チェコ語の音声"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"ドイツ語の音声"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"英語の音声"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"スペイン語の音声"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"フランス語の音声"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"イタリア語の音声"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"日本語の音声"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"韓国語の音声"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"オランダ語の音声"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"ポーランド語の音声"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"ポルトガル語の音声"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"ロシア語の音声"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"トルコ語の音声"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"中国語(広東語)の音声"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"中国語(標準語)の音声"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"ズールー語の音声"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"使いやすさの研究モード"</string>
 </resources>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 13bd604e1f4a4ff42f043a052291b8ed42dc34f9..7a09da880893bc13e570ad3e81da67311fcf37af 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"키를 누를 때 진동 발생"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"키를 누를 때 소리 발생"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"키를 누를 때 팝업"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"단어 추천 설정"</string>
+    <string name="general_category" msgid="1859088467017573195">"일반"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"텍스트 수정"</string>
     <string name="auto_cap" msgid="1719746674854628252">"자동 대문자화"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"빠른 수정"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"자주 발생하는 오타를 수정합니다."</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"수정 제안 표시"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"글자를 입력하는 동안 추천 단어 표시"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"항상 표시"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"세로 모드로 표시"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"항상 숨기기"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"설정 키 표시"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"자동"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"항상 표시"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"항상 숨기기"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"단어 추천"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"이전 단어를 자동으로 수정"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"자동 수정"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"스페이스바와 문장부호 키를 사용하면 오타가 자동으로 교정됩니다."</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"사용 안함"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"보통"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"적극적"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram 추천"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"이전 단어를 사용하여 추천 기능 개선"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"다음"</string>
     <string name="label_done_key" msgid="2441578748772529288">"완료"</string>
     <string name="label_send_key" msgid="2815056534433717444">"전송"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"더보기"</string>
     <string name="label_pause_key" msgid="181098308428035340">"일시 중지"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"대기"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"삭제"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"리턴"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"설정"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"시프트"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"스페이스"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"기호"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"탭"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"음성 입력"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"기호 사용"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"기호 사용 안함"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"시프트 사용"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"시프트 사용 안함"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"음성 입력"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"음성 입력은 현재 자국어로 지원되지 않으며 영어로 작동됩니다."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"음성 입력은 Google의 네트워크화된 음성 인식을 사용하는 실험적 기능입니다."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"음성 입력을 사용하지 않으려면 키보드 설정으로 이동하세요."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"음성 입력을 사용하려면 마이크 버튼을 누르거나 터치 키보드 위로 손가락을 미끄러지듯 움직이세요."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"음성 입력에서는 Google의 음성 인식 기능을 사용합니다. "<a href="http://m.google.com/privacy">"모바일 개인정보취급방침"</a>"이 적용됩니다."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"음성 입력을 사용하지 않으려면 입력 방법 설정으로 이동하세요."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"음성 입력을 사용하려면 마이크 버튼을 누르세요."</string>
     <string name="voice_listening" msgid="467518160751321844">"지금 말하세요."</string>
     <string name="voice_working" msgid="6666937792815731889">"인식 중"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"취소"</string>
     <string name="ok" msgid="7898366843681727667">"확인"</string>
     <string name="voice_input" msgid="2466640768843347841">"음성 입력"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"기본 키보드"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"기호 키보드"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"사용 안함"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"기본 키보드의 마이크"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"기호 키보드의 마이크"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"음성 입력이 사용 중지됨"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"입력 방법 선택"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"입력 언어"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"손가락을 스페이스바에서 미끄러지듯 움직여 언어 변경"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"사전 사용 가능"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"사용자 의견 사용"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"사용 통계 및 충돌 보고서를 Google에 자동으로 전송하여 입력 방법 편집기의 개선에 도움을 줍니다."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"터치하여 단어 다시 수정"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"입력한 단어를 터치하면 다시 수정할 수 있습니다."</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"터치하여 단어 수정"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"입력한 단어를 터치하여 수정(추천 단어가 표시되는 경우에만)"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"키보드 테마"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"체코어 키보드"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"덴마크어 키보드"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"독일어 키보드"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"영어(영국) 키보드"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"영어(미국) 키보드"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"스페인어 키보드"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"스페인어(미국) 키보드"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"프랑스어 키보드"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"프랑스어(캐나다) 키보드"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"프랑스어(스위스) 키보드"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"이탈리아어 키보드"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"노르웨이어 키보드"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"네덜란드어 키보드"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"러시아어 키보드"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"세르비아어 키보드"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"스웨덴어 키보드"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"아프리칸스어 음성"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"체코어 음성"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"독일어 음성"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"영어 음성"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"스페인어 음성"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"프랑스어 음성"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"이탈리아어 음성"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"일본어 키보드"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"한국어 음성"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"네덜란드어 음성"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"폴란드어 음성"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"포르투갈어 음성"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"러시아어 음성"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"터키어 음성"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"중국어, 광둥어 음성"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"중국어, 북경어 음성"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"줄루어 음성"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"가용성 연구 모드"</string>
 </resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index cc15bd6fee3c3a30562128638876d0eb508cbc7f..c12c62aaaffef2bb3fc0c387d672e88a600e5dda 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Klavišo paspaudimo garsas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Iššoka paspaudus klavišą"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Žodžių pasiūlymo nustatymai"</string>
+    <string name="general_category" msgid="1859088467017573195">"Bendra"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Teksto taisymas"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automatinis didžiųjų raidžių rašymas"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Greiti pataisymai"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Taiso dažnai padarytas rašybos klaidas"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Rodyti taisymo pasiūlymus"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Įvedant tekstą pateikti siūlomų žodžių"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Visada rodyti"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Rodyti stačiuoju režimu"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Visada slÄ—pti"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Rodyti nustatymų raktą"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatinis"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Visada rodyti"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Visada slÄ—pti"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Žodžių pasiūlymai"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automatiškai taisyti ankstesnį žodį"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatinis taisymas"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Tarpo kl. ir skyr. ženkl. aut. išt. neteis. įv. žodž."</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"IÅ¡jungta"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Vidutinis"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Atkaklus"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Digramų pasiūlymai"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Naudoti ankstesnį žodį pasiūlymui patobulinti"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Kitas"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Atlikta"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Siųsti"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Daugiau"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Prist."</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Lauk."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"IÅ¡trinti"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Grįžti"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Nustatymai"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Keitimas"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Tarpas"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simboliai"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Skirtukas"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Balso įvestis"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simboliai įjungti"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simboliai išjungti"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Keitimas įjungtas"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Keitimas išjungtas"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Balso įvestis"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Šiuo metu balso įvestis jūsų kompiuteryje nepalaikoma, bet ji veikia anglų k."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balso įvestis – tai eksperimentinė funkcija, naudojanti „Google“ tinklo kalbos atpažinimą."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Jei norite išjungti balso įvestį, eikite į klaviatūros nustatymus."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Jei norite naudoti balso įvestį, paspauskite mikrofono mygtuką arba pirštu slyskite ekranine klaviatūra."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balso įvesčiai naudojamas „Google“ kalbos atpažinimas. Taikoma "<a href="http://m.google.com/privacy">"privatumo politika mobiliesiems"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Jei norite išjungti balso įvestį, eikite į įvesties metodo nustatymus."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Jei norite naudoti balso įvestį, paspauskite mikrofono mygtuką."</string>
     <string name="voice_listening" msgid="467518160751321844">"KalbÄ—kite dabar"</string>
     <string name="voice_working" msgid="6666937792815731889">"Veikia"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Atšaukti"</string>
     <string name="ok" msgid="7898366843681727667">"Gerai"</string>
     <string name="voice_input" msgid="2466640768843347841">"Balso įvestis"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pagr. klaviatūroje"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simbolių klaviatūr."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"IÅ¡jungta"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrof. pagr. klav."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrof. simb. klav."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Balso įv. neleidž."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Pasirinkti įvesties metodą"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Įvesties kalbos"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Pirštu slyskite tarpo klavišu, kad pakeistumėte kalbą"</string>
@@ -104,45 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Žodynas galimas"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Įgalinti naudotojų atsiliepimus"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Padėkite patobulinti šią įvesties metodo redagavimo programą automatiškai „Google“ siųsdami naudojimo statistiką ir strigčių ataskaitas."</string>
-    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Jei norite ištaisyti žodžius, palieskite"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Jei norite ištaisyti įvestus žodžius, palieskite juos"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Jei norite ištais. žodž., paliesk."</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Jei norite ištaisyti įvestus žodžius, palieskite juos tik tada, kai matomi pasiūlymai"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Klaviatūros tema"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Čekiška klaviatūra"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Daniška klaviatūra"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Vokiška klaviatūra"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angliška (Didžioji Britanija) klaviatūra"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angliška (Jungtinės Amerikos Valstijos) klaviatūra"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Vokiška klaviatūra"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angliška (JK) klaviatūra"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angliška (JAV) klaviatūra"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Ispaniška klaviatūra"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Ispaniška (JAV) klaviatūra"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Prancūziška klaviatūra"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Itališka klaviatūra"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Prancūziška (Kanada) klaviatūra"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Prancūziška (Šveicarija) klaviatūra"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Itališka klaviatūra"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norvegiška klaviatūra"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Olandiška klaviatūra"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Rusiška klaviatūra"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbiška klaviatūra"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Švediška klaviatūra"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"„Voice“ čekų k."</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"„Voice“ vokiečių k."</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"„Voice“ anglų k. (Australija)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"„Voice“ anglų k. (Didžioji Britanija)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"„Voice“ anglų k. (Indija)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"„Voice“ anglų k. (Naujoji Zelandija)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"„Voice“ anglų k. (Jungtinės Amerikos Valstijos)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"„Voice“ afrikanų k."</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"„Voice“ čekų k."</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"„Voice“ vokiečių k."</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"„Voice“ anglų k."</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"„Voice“ ispanų k."</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"„Voice“ prancūzų k."</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"„Voice“ italų k."</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"„Voice“ japonų k."</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"„Voice“ korėjiečių k."</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"„Voice“ olandų k."</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"„Voice“ lenkų k."</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"„Voice“ portugalų k."</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"„Voice“ rusų k."</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"„Voice“ turkų k."</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"„Voice“ kinų k. (Kinija)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"„Voice“ kinų k. (Taivanas)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"„Voice“ kinų (dziue) k."</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"„Voice“ kinų (mandarinų) k."</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"„Voice“ zulų k."</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Tinkamumo analizės režimas"</string>
 </resources>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 550c7b284d34e0efecfacd8bd2913e451e5048ec..8b975b0331fa8493f80d6b773a2947bdb4ba1c9c 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Skaņa, nospiežot taustiņu"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Nospiežot taustiņu, parādīt uznirstošo izvēlni"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Vārdu ieteikumu iestatījumi"</string>
+    <string name="general_category" msgid="1859088467017573195">"Vispārīgi"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Teksta korekcija"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automātiska lielo burtu lietošana"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Ä€trie labojumi"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Nodrošina izplatītu drukas kļūdu labošanu."</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Rādīt labojumu ieteikumus"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Ievades laikā attēlot ieteiktos vārdus"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vienmēr rādīt"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Rādīt portreta režīmā"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Vienmēr slēpt"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Rādīt iestatījumu taustiņu"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automātiski"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vienmēr rādīt"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Vienmēr slēpt"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Vārdu ieteikumi"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automātiski labot iepriekšējo vārdu"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automāt. korekcija"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Atstarpes taustiņš un interpunkcija; automātiska kļūdainu vārdu labošana"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Izslēgta"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"MÄ“rena"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresīva"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram ieteikumi"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Ieteikuma uzlabošanai izmantot iepriekšējo vārdu"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Tālāk"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Gatavs"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Sūtīt"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Vairāk"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pauze"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Gaidīt"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Dzēšanas taustiņš"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Atgriešanās taustiņš"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Iestatījumu taustiņš"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Pārslēgšanas taustiņš"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Atstarpes taustiņš"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simbolu taustiņš"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulēšanas taustiņš"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Runas ievades taustiņš"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simbolu režīms ir ieslēgts."</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simbolu režīms ir izslēgts."</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Pārslēgšanas režīms ir ieslēgts."</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Pārslēgšanas režīms ir izslēgts."</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Balss ievade"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Balss ievade jūsu valodā pašlaik netiek atbalstīta, taču tā ir pieejama angļu valodā."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balss ievade ir izmēģinājuma funkcija, kuras pamatā ir Google tīkla runas atpazīšanas līdzeklis."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Lai izslēgtu balss ievadi, atveriet tastatūras iestatījumus."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Lai izmantotu balss ievadi, nospiediet mikrofona pogu vai slidiniet pirkstus pāri ekrāna tastatūrai."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balss ievadei tiek izmantota Google runas atpazīšanas funkcija. Uz šīs funkcijas lietošanu attiecas "<a href="http://m.google.com/privacy">"mobilo sakaru ierīču lietošanas konfidencialitātes politika"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Lai izslēgtu balss ievadi, atveriet ievades metodes iestatījumus."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Lai izmantotu balss ievadi, nospiediet mikrofona taustiņu."</string>
     <string name="voice_listening" msgid="467518160751321844">"Runājiet!"</string>
     <string name="voice_working" msgid="6666937792815731889">"Notiek apstrāde"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Atcelt"</string>
     <string name="ok" msgid="7898366843681727667">"Labi"</string>
     <string name="voice_input" msgid="2466640768843347841">"Balss ievade"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Uz galv. tastatūras"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Uz simbolu tastat."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Izslēgts"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikr.uz galv.tastat."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikr.uz simb.tastat."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Balss iev. atspējota"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Atlasīt ievades metodi"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Slidiniet pirkstu uz atstarpes taustiņa, lai mainītu valodu"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Iespējot lietotāju atsauksmes"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Palīdziet uzlabot šo ievades metodes redaktoru, automātiski nosūtot lietojuma statistiku un pārskatus par avārijām uzņēmumam Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Pieskarties, lai izlabotu vārdus"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pieskarties ievadītajiem vārdiem, lai tos labotu"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pieskarties ievadītajiem vārdiem, lai tos labotu (tikai tad, ja tiek rādīti ieteikumi)."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastatūras motīvs"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Čehu tastatūra"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Dāņu tastatūra"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Vācu tastatūra"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angļu tastatūra (Lielbritānija)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angļu tastatūra (ASV)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Vācu tastatūra"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Angļu (Lielbritānija) tastatūra"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Angļu (ASV) tastatūra"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spāņu tastatūra"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spāņu (ASV) tastatūra"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Franču tastatūra"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Itāliešu tastatūra"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Franču (Kanāda) tastatūra"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Franču (Šveices) tastatūra"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Itāļu tastatūra"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norvēģu tastatūra"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Holandiešu tastatūra"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Krievu tastatūra"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbu tastatūra"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Zviedru tastatūra"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voice čehu valodā"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voice vācu valodā"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Voice angļu valodā (Austrālija)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Voice angļu valodā (Lielbritānija)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Voice angļu valodā (Indija)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Voice angļu valodā (Jaunzēlande)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Voice angļu valodā (ASV)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Balss afrikandu valodā"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voice čehu valodā"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voice vācu valodā"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Balss angļu valodā"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voice spāņu valodā"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voice franču valodā"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Itāļu balss"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voice japāņu valodā"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voice korejiešu valodā"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Holandiešu balss"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voice poļu valodā"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voice portugāļu valodā"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voice krievu valodā"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voice turku valodā"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Voice ķīniešu valodā (Ķīna)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Voice ķīniešu valodā (Taivāna)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Balss ķīniešu val. (Kantonas dial.)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Balss ķīniešu v. (mandarīnu dial.)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Balss zulu valodā"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Lietojamības izpētes režīms"</string>
 </resources>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 9ad756af0d2b55a0472ddcb7e76d36169e08742d..0471e74c30c2103c126cb361403c1ad06dc8eba2 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrer ved tastetrykk"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Lyd ved tastetrykk"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Hurtigvindu ved tastetrykk"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Innstillinger for ordforslag"</string>
+    <string name="general_category" msgid="1859088467017573195">"Generelt"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Tekstkorrigering"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Stor forbokstav"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Autokorrektur"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Retter vanlige stavefeil"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Vis rettingsforslag"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Vis ordforslag under skriving"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vis alltid"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Vis i stående modus"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Skjul alltid"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Vis innstillingsnøkkel"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisk"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vis alltid"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Skjul alltid"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Autokorrektur"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Autokorriger forrige ord"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatisk retting"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Mellomromstast og skilletegn retter automat. feilstavede ord"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Av"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderat"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Omfattende"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram-forslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Bruk forrige ord til å forbedre forslaget"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Neste"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Utfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mer"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Innstillinger"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Mellomrom"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboler"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Taleinndata"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symboler er slått på"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symboler er slått av"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift på"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift av"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Stemmedata"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmedata håndteres foreløpig ikke på ditt språk, men fungerer på engelsk."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Talekommandoer er en eksperimentell funksjon som bruker Googles nettverksbaserte talegjenkjenning."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Gå til innstillinger for tastatur for å slå av stemmedata."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Du bruker talekommandoer ved å trykke på mikrofonknappen eller skyve fingeren over tastaturet på skjermen."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Google Voice bruker Googles talegjenkjenning. "<a href="http://m.google.com/privacy">"Personvernreglene for mobil"</a>" gjelder."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Gå til innstillinger for inndatametode for å slå av stemmedata."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Trykk på mikrofonknappen for å aktivere stemmedata."</string>
     <string name="voice_listening" msgid="467518160751321844">"Snakk nå"</string>
     <string name="voice_working" msgid="6666937792815731889">"Arbeider"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Avbryt"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Talekommando"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"PÃ¥ hovedtastatur"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"PÃ¥ talltastatur"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Av"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon på hovedtast."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon på talltastatur"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Taleinndata er deaktiv."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Velg inndatametode"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inndataspråk"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Dra fingeren på mellomromstasten for å endre språk"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbok tilgjengelig"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brukertilbakemelding"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ved å sende bruksstatistikk og programstopprapporter til Google automatisk, hjelper du oss med å gjøre redigeringsfunksjonen for denne inndatametoden enda bedre."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Trykk for å endre ord"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan endre innskrevne ord ved å trykke på dem"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Trykk for å endre ord"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Når forslag er synlige, kan du trykke på ord du har skrevet inn, for å endre dem"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturtema"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tsjekkisk tastatur"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Dansk tastatur"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tysk tastatur"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engelsk tastatur (Storbritannia)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engelsk tastatur (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spansk tastatur"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spansk tastatur (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Fransk tastatur"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Fransk tastatur (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Fransk tastatur (Sveits)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italiensk tastatur"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norsk tastatur"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Nederlandsk tastatur"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russisk tastatur"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbisk tastatur"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Svensk tastatur"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaans tale"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Tsjekkisk tale"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Tysk tale"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Engelsk tale"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spansk tale"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Fransk tale"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italiensk stemme"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japansk tale"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Koreansk tale"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Nederlandsk stemme"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Polsk tale"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugisisk tale"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russisk tale"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Tyrkisk tale"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Kinesisk (yue) tale"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Kinesisk (mandarin) tale"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu tale"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Nyttighetsmodus"</string>
 </resources>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 2203152ff6bbc860863c4ddf5ca50a0112d82b66..e5439eb386ace4d6a10548cafd9c5a8ec47beb73 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -23,35 +23,28 @@
     <string name="english_ime_name" msgid="7252517407088836577">"Android-toetsenbord"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Instellingen voor Android-toetsenbord"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"Invoeropties"</string>
-    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij druk op toets"</string>
-    <string name="sound_on_keypress" msgid="6093592297198243644">"Geluid bij druk op een toets"</string>
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Trillen bij toetsaanslag"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Geluid bij toetsaanslag"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up bij toetsaanslag"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Instellingen voor woordsuggesties"</string>
+    <string name="general_category" msgid="1859088467017573195">"Algemeen"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Tekstcorrectie"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Auto-hoofdlettergebruik"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Snelle oplossingen"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Hiermee worden veelvoorkomende typefouten gecorrigeerd"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Correctievoorstellen weergeven"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Voorgestelde woorden weergeven tijdens typen"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Altijd weergeven"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Weergeven in staande modus"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Altijd verbergen"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Instellingscode weergeven"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisch"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Altijd weergeven"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Altijd verbergen"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Woordsuggesties"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Het vorige woord automatisch corrigeren"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autocorrectie"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Met spatiebalk en interpunctie worden verkeerd gespelde woorden automatisch gecorrigeerd"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Uitgeschakeld"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Normaal"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressief"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Digram-suggesties"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Vorig woord gebruiken om suggestie te verbeteren"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Volgende"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Gereed"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Verzenden"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Meer"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Onderbr."</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Wacht"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Instellingen"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Spatie"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symbolen"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Spraakinvoer"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symbolen aan"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symbolen uit"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift aan"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift uit"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Spraakinvoer"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spraakinvoer wordt momenteel niet ondersteund in uw taal, maar is wel beschikbaar in het Engels."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Spraakinvoer is een experimentele functie met de spraakherkenning van het Google-netwerk."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Als u spraakinvoer wilt uitschakelen, gaat u naar de toetsenbordinstellingen."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Als u spraakinvoer gebruikt, drukt u op de microfoonknop of schuift u uw vinger over het schermtoetsenbord."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Spraakinvoer maakt gebruik van de spraakherkenning van Google. Het "<a href="http://m.google.com/privacy">"Privacybeleid van Google Mobile"</a>" is van toepassing."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Als u spraakinvoer wilt uitschakelen, gaat u naar de instellingen voor invoermethoden."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Druk op de microfoontoets om spraakinvoer te gebruiken."</string>
     <string name="voice_listening" msgid="467518160751321844">"Nu spreken"</string>
     <string name="voice_working" msgid="6666937792815731889">"Wordt uitgevoerd"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -79,24 +83,18 @@
     <string name="voice_server_error" msgid="7807129913977261644">"Serverfout"</string>
     <string name="voice_speech_timeout" msgid="8461817525075498795">"Geen spraak te horen"</string>
     <string name="voice_no_match" msgid="4285117547030179174">"Geen resultaten gevonden"</string>
-    <string name="voice_not_installed" msgid="5552450909753842415">"Voice Search is niet geïnstalleerd"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Spraakgestuurd zoeken is niet geïnstalleerd"</string>
     <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Hint:"</b>" schuif over het toetsenbord om te spreken"</string>
     <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Hint:"</b>" spreek de volgende keer interpunctie uit, zoals \'period\' (punt), \'comma\' (komma) of \'question mark\' (vraagteken)."</string>
     <string name="cancel" msgid="6830980399865683324">"Annuleren"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Spraakinvoer"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Op hoofdtoetsenbord"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Op symbooltoetsenb."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Uitgeschakeld"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic op hoofdtoetsb."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic op symb.toetsb."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Spraakinvoer is uit"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Invoermethode selecteren"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Invoertalen"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Schuif uw vinger over de spatiebalk om de taal te wijzigen"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Woordenboek beschikbaar"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Gebruikersfeedback inschakelen."</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Help deze invoermethode te verbeteren door automatisch gebruiksstatistieken en crashmeldingen naar Google te verzenden."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Raak aan om woorden opnieuw te corrigeren"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"U kunt woorden opnieuw corrigeren door woorden aan te raken die u heeft getypt"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Raak aan om woorden te corrigeren"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Ingevoerde woorden aanraken om ze te verbeteren, alleen mogelijk wanneer suggesties zichtbaar zijn"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Toetsenbordthema"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tsjechisch toetsenbord"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Deens toetsenbord"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Duits toetsenbord"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engels toetsenbord (VK)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engels toetsenbord (VS)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spaans toetsenbord"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spaans toetsenbord (VS)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Frans toetsenbord"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Frans toetsenbord (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Frans toetsenbord (Zwitserland)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italiaans toetsenbord"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Noors toetsenbord"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Nederlands toetsenbord"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russisch toetsenbord"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Servisch toetsenbord"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Zweeds toetsenbord"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaanse stem"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Tsjechische stem"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Duitse stem"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Engelse stem"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spaanse stem"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Franse stem"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italiaanse stem"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japanse stem"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Koreaanse stem"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Nederlandse stem"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Poolse stem"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portugese stem"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russische stem"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Turkse stem"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Chinese stem (Yue)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Chinese stem (Mandarijn)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu stem"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modus voor gebruiksvriendelijkheidsonderzoek"</string>
 </resources>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 78a35663b285a1e6d5f6a5d533cddd0086c679d4..7edd98840e79c68543d7ef96da875a079b2b38e7 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -25,50 +25,54 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opcje wprowadzania"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Wibracja przy naciśnięciu"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Dźwięk przy naciśnięciu"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Wyświetlaj po naciśnięciu klawisza"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Ustawienia propozycji słów"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Powiększ po naciśnięciu"</string>
+    <string name="general_category" msgid="1859088467017573195">"Ogólne"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Korekta tekstu"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Wstawiaj wielkie litery"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Szybkie poprawki"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Poprawia częste błędy wpisywania"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Pokazuj propozycje poprawek"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Wyświetl proponowane słowa podczas wpisywania"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Zawsze pokazuj"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Pokaż w trybie pionowym"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Zawsze ukrywaj"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Pokaż klawisz ustawień"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatycznie"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Zawsze pokazuj"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Zawsze ukrywaj"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugestie słów"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automatycznie poprawiaj poprzednie słowo"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autokorekta"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Spacja i znaki przestankowe powodują automatyczne poprawianie błędnie napisanych słów"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Wyłącz"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Umiarkowana"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresywna"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestie dla bigramów"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Używaj poprzedniego wyrazu, aby polepszyć sugestię"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
     <string name="label_next_key" msgid="362972844525672568">"Dalej"</string>
-    <string name="label_done_key" msgid="2441578748772529288">"Gotowe"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"OK"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Wyślij"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Więcej"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Czekaj"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Ustawienia"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Spacja"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symbole"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Wprowadzanie głosowe"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symbole włączone"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symbole wyłączone"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift włączony"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift wyłączony"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Wprowadzanie głosowe"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Wprowadzanie głosowe obecnie nie jest obsługiwane w Twoim języku, ale działa w języku angielskim."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Wprowadzanie głosowe to funkcja eksperymentalna wykorzystująca funkcję firmy Google umożliwiającą rozpoznawanie mowy przy użyciu sieci."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień klawiatury."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Aby skorzystać z wprowadzania głosowego, naciśnij przycisk mikrofonu lub przesuń palcem po klawiaturze ekranowej."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Funkcja wprowadzania głosowego wykorzystuje mechanizm rozpoznawania mowy. Obowiązuje "<a href="http://m.google.com/privacy">"Polityka prywatności Google Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień metody wprowadzania."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Aby użyć wprowadzania głosowego, naciśnij przycisk mikrofonu."</string>
     <string name="voice_listening" msgid="467518160751321844">"Mów teraz"</string>
     <string name="voice_working" msgid="6666937792815731889">"W toku"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Anuluj"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Wprowadzanie głosowe"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na klawiaturze głównej"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klawiaturze z symbolami"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Wyłącz"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofon na klawiaturze głównej"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofon na klawiaturze z symbolami"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Wprowadzanie głosowe jest wyłączone"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Wybierz metodÄ™ wprowadzania"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Języki wprowadzania"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Przesuń palcem po spacji, aby zmienić język"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Słownik dostępny"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Włącz przesyłanie opinii użytkownika"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Pomóż ulepszyć edytor tej metody wprowadzania, automatycznie wysyłając do Google statystyki użycia i raporty o awariach."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotknij, aby ponownie poprawić słowa"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Możesz ponownie poprawiać wprowadzone słowa, dotykając ich"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Popraw dotknięte słowo"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotykaj wprowadzonych słów, aby je poprawiać tylko wówczas, gdy widoczne są sugestie."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Motyw klawiatury"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Klawiatura czeska"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Klawiatura duńska"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Klawiatura niemiecka"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Klawiatura angielska (UK)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Klawiatura angielska (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Klawiatura hiszpańska"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Klawiatura hiszpańska (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Klawiatura francuska"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Klawiatura francuska (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Klawiatura francuska (Szwajcaria)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Klawiatura włoska"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Klawiatura norweska"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Klawiatura holenderska"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Klawiatura rosyjska"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Klawiatura serbska"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Klawiatura szwedzka"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Mowa afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Mowa czeska"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Mowa niemiecka"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Mowa angielska"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Mowa hiszpańska"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Mowa francuska"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Mowa włoska"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Mowa japońska"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Mowa koreańska"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Mowa holenderska"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Mowa polska"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Mowa portugalska"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Mowa rosyjska"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Mowa turecka"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Mowa chińska (kantoński)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Mowa chińska (mandaryński)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Mowa isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Tryb badania przydatności"</string>
 </resources>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index c9ba0e5521d5894b62ff1baea45b03fdffa78b5c..f06d64c70641c96f1e28dcdbfecc8a2133c331ce 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao primir as teclas"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao premir as teclas"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Mostrar popup ao premir tecla"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Definições de sugestão de palavras"</string>
+    <string name="general_category" msgid="1859088467017573195">"Geral"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Correcção de texto"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Letras maiúsculas automáticas"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcções rápidas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige os erros de escrita comuns"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Mostrar sugestões de correcção"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Apresentar sugestões de palavras ao escrever"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostrar sempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostrar no modo de retrato"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Ocultar sempre"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla das definições"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar sempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Ocultar sempre"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugestões de palavras"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corrigir automaticamente a palavra anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Auto correcção"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Correcção automática de palavras mal escritas c/ barra de espaços e pontuação"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desligar"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderada"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressiva"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestões Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilizar a palavra anterior para melhorar a sugestão"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Seguinte"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mais"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Definições"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espaço"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Símbolos"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Entrada de voz"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Símbolos ativados"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Símbolos desativados"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift ativado"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift desativado"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente, a entrada de voz não é suportada para o seu idioma, mas funciona em inglês."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz é uma funcionalidade experimental que utiliza o reconhecimento de voz em rede da Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar a entrada de voz, aceda às definições do teclado."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar a entrada de voz, prima o botão do microfone ou deslize o dedo no teclado do ecrã."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz utiliza o reconhecimento de voz da Google. É aplicável a "<a href="http://m.google.com/privacy">"Política de privacidade do Google Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar a entrada de voz, aceda às definições do método de entrada."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar a entrada de voz, prima o botão do microfone."</string>
     <string name="voice_listening" msgid="467518160751321844">"Falar agora"</string>
     <string name="voice_working" msgid="6666937792815731889">"A executar"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Entrada de voz"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"No teclado principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"No teclado símbolos"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Desligar"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. tecl. principal"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic. tecl. símbolos"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entr. voz desact."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Seleccionar método de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Deslize o dedo pela barra de espaço para alterar o idioma"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Activar comentários do utilizador"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Envie automaticamente estatísticas de utilização e relatórios de falhas para a Google e ajude-nos a melhor este editor de método de introdução."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para voltar a corrigir palavras"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pode voltar a corrigir palavras tocando naquelas que escreveu"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corrigir palavras"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tocar nas palavras introduzidas para as corrigir, apenas quando as sugestões estiverem visíveis"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema do teclado"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Teclado checo"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Teclado dinamarquês"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclado alemão"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclado inglês (Reino Unido)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclado inglês (EUA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Teclado espanhol"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Teclado espanhol (EUA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Teclado francês"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Teclado francês (Canadá)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Teclado francês (Suíça)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclado italiano"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Teclado norueguês"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Teclado holandês"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Teclado russo"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Teclado sérvio"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Teclado sueco"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voz em africânder"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voz checa"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voz alemã"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voz em inglês"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voz espanhola"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voz francesa"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voz italiana"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voz japonesa"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voz coreana"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voz holandesa"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voz polaca"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voz portuguesa"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voz russa"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voz turca"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voz em yue, chinês"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voz em mandarim, chinês"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voz em isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modo de estudo da capacidade de utilização"</string>
 </resources>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index bc4981734daae0f3ce583b0f154182681f039b03..9fc1a97f216707af2fc4ca5dc76cb9f78a46ad5b 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opções de entrada"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar ao tocar a tecla"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Som ao tocar a tecla"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Exibir pop-up ao tocar a tecla"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Configurações de sugestão de palavra"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Exibir pop-up ao digitar"</string>
+    <string name="general_category" msgid="1859088467017573195">"Geral"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Correção de texto"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Capitaliz. automática"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Reparos rápidos"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige erros comuns de digitação"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
-    <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de configurações"</string>
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Exibir sugestões de correção"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Exibir sugestões de palavras durante a digitação"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Mostrar sempre"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Mostrar em modo retrato"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Sempre ocultar"</string>
+    <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de config."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar sempre"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Sempre ocultar"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugestões de palavra"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corrigir automaticamente a palavra anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autocorreção"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"A barra de espaço e a pontuação corrigem automaticamente palavras com erro de digitação"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Desativado"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderado"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agressivo"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestões de bigrama"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Usar palavra anterior para melhorar a sugestão"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Avançar"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mais"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Excluir"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Voltar"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Configurações"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Espaço"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Símbolos"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Entrada de texto por voz"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Símbolos ativados"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Símbolos desativados"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift ativado"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift desativado"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A entrada de voz não é suportada no momento para o seu idioma, mas funciona em inglês."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz é um recurso experimental que usa o reconhecimento de fala de rede do Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desativar a entrada de voz, vá para as configurações do teclado."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para usar a entrada de voz, pressione o botão com o microfone ou deslize o dedo sobre o teclado na tela."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de texto por voz usa o reconhecimento de voz do Google. "<a href="http://m.google.com/privacy">"A política de privacidade para celulares"</a>" é aplicada."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desativar a entrada de texto por voz, vá para configurações do método de entrada."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para usar a entrada de texto por voz, pressione o botão do microfone."</string>
     <string name="voice_listening" msgid="467518160751321844">"Fale agora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Trabalhando"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Cancelar"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Entrada de voz"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"No teclado principal"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"No teclado de símb."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Desativado"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. no teclado"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic. no teclado"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Texto por voz desat."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Selecionar método de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Deslize o dedo na barra de espaços para alterar o idioma"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Ativar comentário do usuário"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ajude a melhorar este editor de método de entrada enviando automaticamente ao Google estatísticas de uso e relatórios de falhas."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Toque para corrigir novamente as palavras"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Você pode fazer novamente a correção tocando nas palavras digitadas"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corrigir"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toque nas palavras digitadas para corrigi-las apenas quando as sugestões estiverem visíveis"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema do teclado"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Teclado em tcheco"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Teclado para dinamarquês"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Teclado para alemão"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Teclado para inglês (Reino Unido)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Teclado para inglês (EUA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Teclado para espanhol"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Teclado para espanhol"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Teclado para francês"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Teclado para francês (Canadá)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Teclado para francês (Suíça)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Teclado para italiano"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Teclado para norueguês"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Teclado para holandês"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Teclado para russo"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Teclado para sérvio"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Teclado para sueco"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voz em africâner"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voz em tcheco"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voz em alemão"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voz em inglês"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voz em espanhol"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voz em francês"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voz italiana"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voz em japonês"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voz em coreano"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voz holandesa"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voz em polonês"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voz em português"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voz em russo"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voz em turco"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voz em chinês, cantonês"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voz em chinês, mandarim"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voz em zulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modo de estudo de utilização"</string>
 </resources>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index 4f700733290acbe43e6a3014fd1dc13c702f516f..57548b5e41dd9770d8b29306bdc86b3be8187ce5 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -27,11 +27,13 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar cun smatgar in buttun"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tun cun smatgar in buttun"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up cun smatgar ina tasta"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Parameters da las propostas per pleds"</string>
+    <!-- no translation found for general_category (1859088467017573195) -->
+    <skip />
+    <!-- outdated translation 7027100625580696660 -->     <string name="prediction_category" msgid="6361242011806282176">"Parameters da las propostas per pleds"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Maiusclas automaticas"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcturas sveltas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Curregia sbagls da tippar currents"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
     <skip />
     <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
     <skip />
@@ -50,7 +52,7 @@
     <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
     <skip />
     <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Propostas da pleds"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Curreger automaticamain il pled precedent"</string>
+    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="5625751551134658006">"Curreger automaticamain il pled precedent"</string>
     <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
     <skip />
     <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
@@ -72,6 +74,30 @@
     <skip />
     <!-- no translation found for label_wait_key (6402152600878093134) -->
     <skip />
+    <!-- no translation found for description_delete_key (5586406298531883960) -->
+    <skip />
+    <!-- no translation found for description_return_key (8750044000806461678) -->
+    <skip />
+    <!-- no translation found for description_settings_key (7484527796782969219) -->
+    <skip />
+    <!-- no translation found for description_shift_key (346906866277787836) -->
+    <skip />
+    <!-- no translation found for description_space_key (8512130111575878517) -->
+    <skip />
+    <!-- no translation found for description_switch_alpha_symbol_key (4537975384274405537) -->
+    <skip />
+    <!-- no translation found for description_tab_key (828186583738307137) -->
+    <skip />
+    <!-- no translation found for description_voice_key (3057731675774652754) -->
+    <skip />
+    <!-- no translation found for description_symbols_on (2994366855822840559) -->
+    <skip />
+    <!-- no translation found for description_symbols_off (3209578267079515136) -->
+    <skip />
+    <!-- no translation found for description_shift_on (6983188949895971587) -->
+    <skip />
+    <!-- no translation found for description_shift_off (8553265474523069034) -->
+    <skip />
     <string name="voice_warning_title" msgid="4419354150908395008">"Cumonds vocals"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"\"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais.\""</string>
     <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ils cumonds vocals èn ina funcziunalitad experimentala che utilisescha la renconuschientscha vocala da rait da Google."</string>
@@ -150,28 +176,26 @@
     <skip />
     <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
     <skip />
+    <!-- no translation found for subtype_mode_af_voice (7542487489657902699) -->
+    <skip />
     <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
     <skip />
     <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
     <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
+    <!-- no translation found for subtype_mode_en_voice (6643420989651848728) -->
     <skip />
     <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
     <skip />
     <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
     <skip />
+    <!-- no translation found for subtype_mode_it_voice (5077373057157441323) -->
+    <skip />
     <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
     <skip />
     <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
     <skip />
+    <!-- no translation found for subtype_mode_nl_voice (2603552312869575021) -->
+    <skip />
     <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
     <skip />
     <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
@@ -180,9 +204,11 @@
     <skip />
     <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
     <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
+    <!-- no translation found for subtype_mode_yue_voice (1576887891614624263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_voice (4360533229467271152) -->
     <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
+    <!-- no translation found for subtype_mode_zu_voice (1146122571698884636) -->
     <skip />
     <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
     <skip />
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 0c5d62e32b5b7e4b59eb025ce27ab0db364396d0..52bed27851cc2ea9d345dd024905fb7e3c44bda2 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Sunet la apăsarea tastei"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Fereastră pop-up la apăsarea tastei"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Setările sugestiei de cuvinte"</string>
+    <string name="general_category" msgid="1859088467017573195">"General"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Corectare text"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalizare"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Remedieri rapide"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corectează greşelile introduse frecvent"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Afişaţi sugestii de corectare"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Afişaţi sugestii de cuvinte în timpul introducerii textului"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Afişaţi întotdeauna"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Afişaţi în modul Portret"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Ascundeţi întotdeauna"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Afişaţi tasta setări"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automat"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Afişaţi întotdeauna"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Ascundeţi întotdeauna"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Sugestii de cuvinte"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Corecţie automată a cuvântului anterior"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autocorecţie"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Corectare automată cuvinte prin bară spaţiu/semne punctuaţie"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Dezactivată"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Moderată"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivă"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestii pentru cuvinte de două litere"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilizaţi cuvântul anterior pentru a îmbunătăţi sugestia"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"ÃŽnainte"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Terminat"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Trimiteţi"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mai multe"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pauză"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"AÅŸt."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Ştergeţi"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Tasta Enter"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Setări"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Tasta Space"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simboluri"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tasta Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Intrare vocală"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simbolurile sunt activate"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simbolurile sunt dezactivate"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Tasta Shift este activată"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Tasta Shift este dezactivată"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Intrare voce"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Intrarea vocală nu este acceptată în prezent pentru limba dvs., însă funcţionează în limba engleză."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Intrarea vocală este o funcţie experimentală ce utilizează recunoaşterea vocală în reţea oferită de Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pentru a dezactiva intrarea vocală, accesaţi setările tastaturii."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pentru a utiliza intrarea vocală, apăsaţi butonul de microfon sau glisaţi degetul de-a lungul tastaturii de pe ecran."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Intrarea vocală utilizează funcţia Google de recunoaştere vocală. Se aplică "<a href="http://m.google.com/privacy">"Politica de confidenţialitate Google Mobil"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pentru a dezactiva intrarea vocală, accesaţi setările metodei de intrare."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pentru a utiliza intrarea vocală, apăsaţi pe butonul Microfon."</string>
     <string name="voice_listening" msgid="467518160751321844">"Vorbiţi acum"</string>
     <string name="voice_working" msgid="6666937792815731889">"Se analizează"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Anulaţi"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Intrare voce"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Pe tastat. princip."</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Pe tastat. simbol."</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Dezactivată"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic. pe tast. princ."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micr. pe tast. simb."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Intr. vocală dezact."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Selectaţi metoda de introducere a textului"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Glisaţi degetul pe bara de spaţiu pentru a schimba limba"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Activaţi feedback de la utilizatori"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ajutaţi la îmbunătăţirea acestui instrument de editare a metodelor de introducere a textului trimiţând în mod automat la Google statistici de utilizare şi rapoarte de blocare."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Atingeţi pentru a corecta cuvintele"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Atingeţi cuvintele introduse pentru a le corecta"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Atingeţi cuvintele introduse pentru a le corecta, numai când pot fi văzute sugestii"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Temă pentru tastatură"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tastatură cehă"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Tastatură daneză"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tastatură germană"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Tastatură engleză (Marea Britanie)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Tastatură engleză (S.U.A.)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tastatură germană"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Tastatură engleză (Marea Britanie)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Tastatură engleză (S.U.A.)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Tastatură spaniolă"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Tastatură spaniolă (S.U.A.)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Tastatură franceză"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Tastatură italiană"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Tastatură franceză (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Tastatură franceză (Elveţia)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Tastatură italiană"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Tastatură norvegiană"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Tastatură olandeză"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Tastatură rusă"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Tastatură sârbă"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Tastatură suedeză"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voce cehă"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voce germană"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Voce engleză (Australia)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Voce engleză (Marea Britanie)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Voce engleză (India)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Voce engleză (Noua Zeelandă)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Voce engleză (S.U.A.)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voce afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Voce cehă"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Voce germană"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voce engleză"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Voce spaniolă"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Voce franceză"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voce italiană"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Voce japoneză"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Voce coreeană"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voce olandeză"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Voce poloneză"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Voce portugheză"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Voce rusă"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Voce turcă"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Voce chineză (China)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Voce chineză (Taiwan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voce chineză, yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voce chineză, mandarină"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voce isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Modul Studiu privind utilizarea"</string>
 </resources>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index a3fc39738044510292ea04ce5fc8967af04303d0..21fd02bd30116b2dbdfb9869d98dcfe4fe7a5a44 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -25,33 +25,26 @@
     <string name="english_ime_input_options" msgid="3909945612939668554">"Параметры ввода"</string>
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Виброотклик клавиш"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук клавиш"</string>
-    <string name="popup_on_keypress" msgid="123894815723512944">"Показывать при нажатии"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Настройки подсказок"</string>
+    <string name="popup_on_keypress" msgid="123894815723512944">"Увеличение нажатых"</string>
+    <string name="general_category" msgid="1859088467017573195">"Общие"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Коррекция текста"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Автоподст. заглавных"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Быстрое исправление"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Исправлять распространенные опечатки"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
-    <string name="prefs_settings_key" msgid="4623341240804046498">"Показывать кнопку настроек"</string>
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Показать варианты исправлений"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Предлагать варианты слов во время ввода"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Всегда показывать"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Показать вертикально"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Всегда скрывать"</string>
+    <string name="prefs_settings_key" msgid="4623341240804046498">"Кнопка настроек"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Автоматически"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Всегда показывать"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Всегда скрывать"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Предложение слов"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Автоматически исправлять предыдущее слово"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Автоисправление"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Автоматическое исправление опечаток при вводе знака препинания или пробела"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Откл."</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умеренное"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Активное"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Биграммные подсказки"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Используйте предыдущее слово, чтобы исправить подсказку"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string>
@@ -59,18 +52,29 @@
     <string name="label_next_key" msgid="362972844525672568">"Далее"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Отправить"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
-    <string name="label_more_key" msgid="3760239494604948502">"Еще"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Ещё"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Приостановить"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Подождите"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Клавиша удаления"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Клавиша \"Ввод\""</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Клавиша настроек"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Клавиша верхнего регистра"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Клавиша \"Пробел\""</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Клавиша символов"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Клавиша табуляции"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Клавиша голосового ввода"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Клавиши символов выключены"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Клавиши символов включены"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Верхний регистр включен"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Верхний регистр выключен"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Голосовой ввод"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"В настоящее время функция голосового ввода не поддерживает ваш язык, но вы можете пользоваться ей на английском."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовой ввод – экспериментальная функция на основе технологии сетевого распознавания речи от Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Функция голосового ввода отключается в настройках клавиатуры."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Чтобы использовать голосовой ввод, нажмите кнопку микрофона или проведите пальцем по экранной клавиатуре."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовой ввод использует алгоритмы распознавания речи Google. Действует "<a href="http://m.google.com/privacy">"политика конфиденциальности для мобильных устройств"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Функция голосового ввода отключается в настройках способа ввода."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Чтобы использовать голосовой ввод, нажмите кнопку микрофона."</string>
     <string name="voice_listening" msgid="467518160751321844">"Говорите"</string>
-    <string name="voice_working" msgid="6666937792815731889">"Выполняется обработка"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Обработка запроса"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
     <string name="voice_error" msgid="5140896300312186162">"Ошибка. Повторите попытку."</string>
     <string name="voice_network_error" msgid="6649556447401862563">"Ошибка подключения"</string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Отмена"</string>
     <string name="ok" msgid="7898366843681727667">"ОК"</string>
     <string name="voice_input" msgid="2466640768843347841">"Голосовой ввод"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Значок на основной клавиатуре"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Значок на клавиатуре символов"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Выкл."</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Значок на основной клавиатуре"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Значок на клавиатуре символов"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Голосовой ввод отключен"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Выбрать способ ввода"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Языки ввода"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Для изменения языка проведите пальцем по пробелу"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Доступен словарь"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Включить отправку сведений"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Помогите усовершенствовать редактор способа ввода, разрешив отправку статистики и отчетов о сбоях в Google."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Исправление нажатием"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Нажмите на слово, чтобы исправить его"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Исправление нажатием"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Нажмите на слово, чтобы исправить его (при наличии подсказок)"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Вид клавиатуры"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Клавиатура: чешская"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Клавиатура: датская"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Клавиатура: немецкая"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Клавиатура: английская (Великобритания)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Клавиатура: английская (США)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Клавиатура: испанская"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Клавиатура: испанская (США)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Клавиатура: французская"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Клавиатура: французская"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Клавиатура: французская (Швейцария)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Клавиатура: итальянская"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Клавиатура: норвежская"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Клавиатура: голландская"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Клавиатура: русская"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Клавиатура: сербская"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Голос: шведский"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Голосовой ввод на африкаанс"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Голос: чешский"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Голос: немецкий"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Голосовой ввод на английском"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Голос: испанский"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Голос: французский"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Голосовой ввод на итальянском"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Голос: японский"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Голос: корейский"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Голосовой ввод на голландском"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Голос: польский"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Голос: португальский"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Голос: русский"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Голос: турецкий"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Голосовой ввод на китайском (диалект юэ)"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Голосовой ввод на китайском (мандаринский диалект)"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Голосовой ввод на зулу"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Режим проверки удобства использования"</string>
 </resources>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 9fc89945b1f611b25e3661aafd05ccfdcde1332b..569f273a41ea0c96c32be01fc92d980ad7f1e2df 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri stlačení klávesu"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Zobraziť znaky pri stlačení klávesu"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Nastavenia návrhov slov"</string>
+    <string name="general_category" msgid="1859088467017573195">"Všeobecné"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Oprava textu"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Veľké písmená automaticky"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Rýchle opravy"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Opravuje najčastejšie chyby pri písaní"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Zobraziť návrhy opráv"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Zobrazovať navrhované slová počas písania"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vždy zobrazovať"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Zobraziť v režime na výšku"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Vždy skrývať"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Zobraziť kláves Nastavenia"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automaticky"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vždy zobrazovať"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Vždy skrývať"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Návrhy slov"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Automaticky opraviť predchádzajúce slovo"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Automatické opravy"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Stlačením medzerníka a interpunkcie sa aut. opravia chybné slová"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Vypnuté"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Mierne"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresívne"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Návrh Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Na zlepšenie návrhu použiť predchádzajúce slovo"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"ÄŽalej"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Odoslať"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Viac"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pozastaviť"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"ÄŒakajte"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Nastavenia"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Medzera"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboly"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Hlasový vstup"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Symboly zapnuté"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Symboly vypnuté"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift zapnutý"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift vypnutý"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pre váš jazyk aktuálne nie je hlasový vstup podporovaný, ale funguje v angličtine."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup je experimentálna funkcia, ktorá využíva sieťové rozpoznanie reči spoločnosti Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ak chcete vypnúť hlasový vstup, prejdite na nastavenia klávesnice."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ak chcete použiť hlasový vstup, stlačte tlačidlo mikrofónu alebo prejdite prstom po klávesnici na obrazovke."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup používa rozpoznávanie hlasu Google. Na používanie hlasového vstupu sa vzťahujú "<a href="http://m.google.com/privacy">"Pravidlá ochrany osobných údajov pre mobilné služby"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ak chcete vypnúť hlasový vstup, prejdite na nastavenia metódy vstupu."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ak chcete použiť hlasový vstup, stlačte tlačidlo mikrofón."</string>
     <string name="voice_listening" msgid="467518160751321844">"Hovorte"</string>
     <string name="voice_working" msgid="6666937792815731889">"Prebieha spracovanie"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Zrušiť"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Hlasový vstup"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na hlavnej klávesnici"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na klávesnici so symbolmi"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Vypnuté"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mikrofón na hlavnej klávesnici"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mikrofón na klávesnici so symbolmi"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hlasový vstup je zakázaný"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Výber metódy vstupu"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Jazyk môžete zmeniť posunutím prsta po medzerníku."</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Povoliť spätnú väzbu od používateľov"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Automatickým zasielaním štatistík o využívaní editora metódy vstupu a správ o jeho zlyhaní do služby Google môžete prispieť k vylepšeniu tohto nástroja."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotykom opravíte slová"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotykom zadaným slov ich opravíte"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotykom zadaných slov tieto slová opravíte, musia však byť viditeľné návrhy"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Motív klávesnice"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"klávesnica – čeština"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"klávesnica – dánčina"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"klávesnica – nemčina"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"hlas – angličtina (Veľká Británia)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"klávesnica – angličtina (Spojené štáty)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"klávesnica – nemčina"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"klávesnica – angličtina (br.)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"klávesnica – angličtina (am.)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"klávesnica – španielčina"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"klávesnica – španielčina (am.)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"klávesnica – francúzština"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"klávesnica – taliančina"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"klávesnica – francúzština (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"klávesnica – francúzština (Švajč.)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"klávesnica – taliančina"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"klávesnica – nórčina"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"klávesnica – holandčina"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"klávesnica – ruština"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"hlas – srbčina"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"klávesnica – švédčina"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"hlas – čeština"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"hlas – nemčina"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"hlas – angličtina (Austrália)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"hlas – angličtina (Veľká Británia)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"hlas – angličtina (India)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"hlas – angličtina (Nový Zéland)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"klávesnica – angličtina (Spojené štáty)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Hlas – afrikánčina"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"hlas – čeština"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"hlas – nemčina"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Hlas – angličtina"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"hlas – španielčina"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"hlas – francúzština"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"hlas – taliančina"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"hlas – japončina"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"hlas – kórejčina"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"hlas – holandčina"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"hlas – poľština"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"hlas – portugalčina"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"hlas – ruština"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"hlas – turečtina"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"hlas – čínština (Čína)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"hlas – čínština (Taiwan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Hlas – čínština, kantónčina"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Hlas – čínština, mandarínska"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Hlas – Zulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Režim Štúdia vhodnosti použitia"</string>
 </resources>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 4a409315229326d1c4b6d12a1c0d2cd07bf3be20..715e6c567d1e5905e7bf8423b5384b6b568d2867 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Zvok ob pritisku tipke"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Pojavno okno ob pritisku tipke"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Nastavitve za predlaganje besede"</string>
+    <string name="general_category" msgid="1859088467017573195">"Splošno"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Popravek besedila"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Samodejne velike začetnice"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Hitri popravki"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Popravi pogoste tipkarske napake"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Pokaži predloge popravkov"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Pokaži predlagane besede med tipkanjem"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Vedno pokaži"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Pokaži v pokončnem načinu"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Vedno skrij"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Pokaži tipko za nastavitve"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Samodejno"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vedno pokaži"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Vedno skrij"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Predlogi besed"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Samodejno popravi prejšnjo besedo"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Samodejni popravek"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Preslednica in ločila samodejno popravijo napačno vtipkane besede"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Izklopljeno"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Zmerno"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresivno"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigramni predlogi"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Predlog izboljšaj s prejšnjo besedo"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Naprej"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Dokončano"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Pošlji"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Več"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Premor"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"ÄŒakaj"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Izbriši"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Vračalka"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Nastavitve"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Dvigalka"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Preslednica"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Znaki"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabulatorka"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Glasovni vnos"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Znaki vklopljeni"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Znaki izklopljeni"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Dvigalka vklopljena"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Dvigalka izklopljena"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni vnos"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Glasovni vnos trenutno ni podprt v vašem jeziku, deluje pa v angleščini."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni vnos je poskusna funkcija, ki uporablja Googlovo omrežno prepoznavanje govora."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Če želite izklopiti glasovni vnos, pojdite na nastavitve tipkovnice."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Če želite uporabiti glasovni vnos, pritisnite gumb z mikrofonom ali podrsajte s prstom po zaslonski tipkovnici."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni vnos uporablja Googlovo prepoznavanje govora. Zanj velja "<a href="http://m.google.com/privacy">"pravilnik o zasebnosti za mobilne naprave"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Glasovni vnos izklopite v nastavitvah načina vnosa."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Če želite uporabljati glasovni vnos, pritisnite gumb z mikrofonom."</string>
     <string name="voice_listening" msgid="467518160751321844">"Začnite govoriti"</string>
     <string name="voice_working" msgid="6666937792815731889">"Obdelava"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Prekliči"</string>
     <string name="ok" msgid="7898366843681727667">"V redu"</string>
     <string name="voice_input" msgid="2466640768843347841">"Glasovni vnos"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Na glavni tipkovnici"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Na tipk. s simboli"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Izklopljeno"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mik. na glavni tipk."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mik. na tipk. s sim."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Glas. vnos je onem."</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Izberite način vnosa"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jeziki vnosa"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Podrsajte s prstom po preslednici, da zamenjate jezik"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Omogoči povratne informacije uporabnikov"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"S samodejnim pošiljanjem statističnih podatkov o uporabi in poročil o zrušitvah Googlu nam lahko pomagate izboljšati urejevalnik načina vnosa."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotaknite se besed in jih popravite"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotaknite se vnesenih besed in jih popravite"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotaknite se vnesenih besed in jih popravite, samo ko so predlogi vidni"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema tipkovnice"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Češka tipkovnica"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danska tipkovnica"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Nemška tipkovnica"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Tipkovnica za britansko angleščino"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Tipkovnica za ameriško angleščino"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Nemška tipkovnica"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Tipkovnica za britansko angleščino"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Tipkovnica za ameriško angleščino"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Å panska tipkovnica"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Tipkovnica za ameriško španščino"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Francoska tipkovnica"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italijanska tipkovnica"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Tipkovnica za kanadsko francoščino"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Tipkovnica za švicarsko francoščino"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italijanska tipkovnica"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norveška tipkovnica"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Nizozemska tipkovnica"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Ruska tipkovnica"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Srbska tipkovnica"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Å vedska tipkovnica"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Govor v češčini"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Govor v nemščini"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Govor v avstralski angleščini"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Govor v britanski angleščini"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Govor v indijski angleščini"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Govor v novozelandski angleščini"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Govor v ameriški angleščini"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Govor v afrikanščini"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Govor v češčini"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Govor v nemščini"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Govor v angleščini"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Govor v španščini"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Govor v francoščini"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Govor v italijanščini"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Govor v japonščini"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Govor v korejščini"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Govor v nizozemščini"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Govor v poljščini"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Govor v portugalščini"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Govor v ruščini"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Govor v turščini"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Govor v kitajščini"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Govor v tajvanski kitajščini"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Govor v kitajščini, jue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Govor v kitajščini, mandarinščini"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Govor v zulujščini"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Način za preučevanje uporabnosti"</string>
 </resources>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 952192996b0983ddb79cbd1dc846dfeea6105a65..115732779c9161d70580cb6805d115c6d46666aa 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук на притисак тастера"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Искачући прозор приликом притиска тастера"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Подешавања за предлагање речи"</string>
+    <string name="general_category" msgid="1859088467017573195">"Опште"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Исправљање текста"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Аутоматски унос великих слова"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Брзе исправке"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Исправља честе грешке у куцању"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Прикажи предлоге за исправку"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Приказивање предложених речи током уноса текста"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Увек прикажи"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Прикажи у усправном режиму"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Увек сакриј"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Прикажи тастер за подешавања"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Аутоматски"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Увек прикажи"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Увек сакриј"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Предлагање речи"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Аутоматско исправљање претходне речи"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Аутоматско исправљање"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Размак и интерпункција аутоматски исправљају грешке у куцању"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Искључи"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Умерено"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Агресивно"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram предлози"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Користи претходну реч за побољшање предлога"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Следеће"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Пошаљи"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Још"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Паузирај"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Сачекајте"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Подешавања"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Размак"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Симболи"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Гласовни унос"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Симболи су укључени"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Симболи су искључени"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift је укључен"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift је искључен"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Гласовни унос"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Гласовни унос тренутно није подржан за ваш језик, али функционише на енглеском."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовни унос је експериментална функција која користи Google-ово мрежно препознавање гласа."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Да бисте искључили гласовни унос, идите на подешавања тастатуре."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Да бисте користили гласовни унос, притисните дугме за микрофон или превуците прст преко тастатуре на екрану."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовни унос користи Google-ову функцију за препознавање гласа. Примењује се "<a href="http://m.google.com/privacy">"политика приватности за мобилне уређаје"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Да бисте искључили гласовни унос, идите на подешавања за начин уноса."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Да бисте користили гласовни унос, притисните дугме за микрофон."</string>
     <string name="voice_listening" msgid="467518160751321844">"Говорите сада"</string>
     <string name="voice_working" msgid="6666937792815731889">"Обрада"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Откажи"</string>
     <string name="ok" msgid="7898366843681727667">"Потврди"</string>
     <string name="voice_input" msgid="2466640768843347841">"Гласовни унос"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На главној тастатури"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"На тастатури са симболима"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Искључи"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Микрофон на главној тастатури"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Микрофон на тастатури са симболима"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Гласовни унос је онемогућен"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Изаберите метод уноса"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Језици за унос"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Превуците прст преко тастера за размак да бисте променили језик"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Омогући повратну информацију корисника"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Помозите да се побољша овај уређивач режима уноса тако што ће се аутоматски послати статистика о коришћењу и извештаји о грешкама компанији Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Додирните да бисте исправили речи"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Додирните унете речи да бисте их исправили"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Додирните унете речи да бисте их исправили само када су предлози видљиви"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Тема тастатуре"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Језик тастатуре: чешки"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Језик тастатуре: дански"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Језик тастатуре: немачки"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Језик тастатуре: енглески (Велика Британија)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Језик тастатуре: енглески (САД)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Језик тастатуре: немачки"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Језик тастатуре: енглески (УК)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Језик тастатуре: енглески (САД)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Језик тастатуре: шпански"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Језик тастатуре: шпански (САД)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Језик тастатуре: француски"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Језик тастатуре: италијански"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Језик тастатуре: француски (Канада)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Језик тастатуре: француски (Швајц.)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Језик тастатуре: италијански"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Језик тастатуре: норвешки"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Језик тастатуре: холандски"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Језик тастатуре: руски"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Језик тастатуре: српски"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Језик тастатуре: шведски"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"глас на чешком"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"глас на немачком"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"глас на енглеском (Аустралија)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"глас на енглеском (Велика Британија)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"глас на енглеском (Индија)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"енглески (Нови Зеланд) аудио"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"глас на енглеском (САД)"</string>
-    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"глас на шпанском"</string>
-    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"глас на француском"</string>
-    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"глас на јапанском"</string>
-    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"глас на корејском"</string>
-    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"глас на пољском"</string>
-    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"глас на португалском"</string>
-    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"глас на руском"</string>
-    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"глас на турском"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"глас на кинеском (Кина)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"глас на кинеском (Тајван)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Глас на африкансу"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Глас на чешком"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Глас на немачком"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Глас на енглеском"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Глас на шпанском"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Глас на француском"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Глас на италијанском"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Глас на јапанском"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Глас на корејском"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Глас на холандском"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Глас на пољском"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Глас на португалском"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Глас на руском"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Глас на турском"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Глас на јуе кинеском"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Глас на мандаринском кинеском"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Глас на језику исизулу"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Режим за студију могућности коришћења"</string>
 </resources>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 5666a2526b249f1085ac04ab618814ab5aa79117..b8c62f46ed27a78d9bcf715a1381bd82cba57892 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrera vid tangenttryck"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Knappljud"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Popup vid knapptryck"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Inställningar för ordförslag"</string>
+    <string name="general_category" msgid="1859088467017573195">"Allmänt"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Textkorrigering"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Automatiska versaler"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Snabba lösningar"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Åtgärdar automatiskt vanliga misstag"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Visa rättningsförslag"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Visar ordförslag när du skriver"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Visa alltid"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Visa stående"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Dölj alltid"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Visa inställningsknapp"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatiskt"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Visa alltid"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Dölj alltid"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Ordförslag"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Rätta automatiskt föregående ord"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Autokorrigering"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Blanksteg/skiljetecken rättar felstavning"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Av"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"MÃ¥ttlig"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Aggressiv"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigramförslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Förbättra förslaget med föregående ord"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Nästa"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Färdig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Skicka"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Mer"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Vänta"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Ta bort"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Retur"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Inställningar"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Skift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Blanksteg"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Symboler"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tabb"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Röstinmatning"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Aktivera symboler"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Inaktivera symboler"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Aktivera Skift"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Inaktivera Skift"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Röstindata"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Röstindata stöds inte på ditt språk än, men tjänsten fungerar på engelska."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Röstinmatning är en funktion på experimentstadiet som använder Googles nätverks taligenkänning."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Om du vill stänga av röstindata öppnar du inställningarna för tangentbordet."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Om du vill använda röstinmatning trycker du på mikrofonknappen eller drar fingret över tangentbordet på skärmen."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Röstinmatning använder sig av Googles tjänst för taligenkänning. "<a href="http://m.google.com/privacy">"Sekretesspolicyn för mobila enheter"</a>" gäller."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Om du vill stänga av röstinmatning öppnar du inställningarna för inmatningsmetod."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Om du vill använda röstinmatning trycker du på mikrofonknappen."</string>
     <string name="voice_listening" msgid="467518160751321844">"Tala nu"</string>
     <string name="voice_working" msgid="6666937792815731889">"Fungerar"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Avbryt"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Röstindata"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"PÃ¥ huvudtangentbord"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"PÃ¥ symboltangentbord"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Av"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mick huvudtangentbord"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mick bland symboler"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Röstinmatning inaktiv"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Välj inmatningsmetod"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inmatningsspråk"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Dra med fingret på blanksteg om du vill ändra språk"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"En ordlista är tillgänglig"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivera synpunkter från användare"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Du kan hjälpa till att förbättra inmatningsmetoden genom att automatiskt skicka användningsstatistik och felrapporter till Google."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryck om du vill korrigera om ord"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan korrigera om ord genom att trycka på ord som du har skrivit"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryck om du vill korrigera ord"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tryck på skrivna ord om du vill korrigera dem, endast när förslag visas"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tangentbordstema"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Tjeckiskt tangentbord"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danskt tangentbord"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Tyskt tangentbord"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Engelskt tangentbord (Storbrit.)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Engelskt tangentbord (USA)"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spanskt tangentbord"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spanskt tangentbord (USA)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Franskt tangentbord"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Franskt tangentbord (Kanada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Franskt tangentbord (Schweiz)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italienskt tangentbord"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norskt tangentbord"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Holländskt tangentbord"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Ryskt tangentbord"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbiskt tangentbord"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Svenskt tangentbord"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Röst, afrikaans"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Röst på tjeckiska"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Röst på tyska"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Röst, engelska"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Röst på spanska"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Röst på franska"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Röst på italienska"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Röst på japanska"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Röst på koreanska"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Röst på holländska"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Röst på polska"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Röst på portugisiska"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Röst på ryska"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Röst på turkiska"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Röst, kinesiska, yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Röst, kinesiska, mandarin"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Röst, isiZulusk"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Läge för användbarhetsstudie"</string>
 </resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 44f6ba8a9a9288dc541eafffc70bdd3457c308a6..836b987245de17af4d7abba5e77772971fba93c7 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"ส่งเสียงเมื่อกดปุ่ม"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"ป๊อปอัปเมื่อกดแป้น"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"การตั้งค่าการแนะนำคำ"</string>
+    <string name="general_category" msgid="1859088467017573195">"ทั่วไป"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"การแก้ไขข้อความ"</string>
     <string name="auto_cap" msgid="1719746674854628252">"ปรับเป็นตัวพิมพ์ใหญ่อัตโนมัติ"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"แก้ไขด่วน"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"แก้ไขข้อผิดพลาดในการพิมพ์ที่พบบ่อย"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"แสดงคำแนะนำการแก้ไข"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"แสดงคำที่แนะนำขณะพิมพ์"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"แสดงทุกครั้ง"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"แสดงในโหมดแนวตั้ง"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"ซ่อนทุกครั้ง"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"แสดงแป้นการตั้งค่า"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"อัตโนมัติ"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"แสดงตลอดเวลา"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"ซ่อนตลอดเวลา"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"การแนะนำคำ"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"แก้ไขคำก่อนหน้าอัตโนมัติ"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"การแก้ไขอัตโนมัติ"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"กดเว้นวรรคและเครื่องหมายจะแก้คำผิดอัตโนมัติ"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"ปิด"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"ปานกลาง"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"เข้มงวด"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"คำแนะนำ Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"ใช้คำก่อนหน้านี้เพื่อปรับปรุงคำแนะนำ"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"ถัดไป"</string>
     <string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string>
     <string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"เพิ่มเติม"</string>
     <string name="label_pause_key" msgid="181098308428035340">"หยุดชั่วคราว"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"รอ"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"ลบ"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"การตั้งค่า"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Space"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"สัญลักษณ์"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"ป้อนข้อมูลด้วยเสียง"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"สัญลักษณ์เปิดอยู่"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"สัญลักษณ์ปิดอยู่"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift เปิดอยู่"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift ปิดอยู่"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"การป้อนข้อมูลด้วยเสียง"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ขณะนี้การป้อนข้อมูลด้วยเสียงยังไม่ได้รับการสนับสนุนในภาษาของคุณ แต่ใช้ได้ในภาษาอังกฤษ"</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"การป้อนข้อมูลด้วยเสียงเป็นคุณลักษณะทดลองที่ใช้การจดจำเสียงที่มีการสร้างเครือข่ายไว้ของ Google"</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"หากต้องการปิดการป้อนข้อมูลด้วยเสียง ไปที่การตั้งค่าแป้นพิมพ์"</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"หากต้องการใช้การป้อนข้อมูลด้วยเสียง กดปุ่มไมโครโฟนหรือเลื่อนนิ้วผ่านแป้นพิมพ์บนหน้าจอ"</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ป้อนข้อมูลด้วยเสียงใช้การจดจำคำพูดของ Google "<a href="http://m.google.com/privacy">" นโยบายส่วนบุคคลของมือถือ"</a>"มีผลบังคับใช้"</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"หากต้องการปิดการป้อนข้อมูลด้วยเสียง ไปที่การตั้งค่าวิธีการป้อนข้อมูล"</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"หากต้องการใช้การป้อนข้อมูลด้วยเสียง ให้กดปุ่มไมโครโฟน"</string>
     <string name="voice_listening" msgid="467518160751321844">"พูดได้เลย"</string>
     <string name="voice_working" msgid="6666937792815731889">"กำลังทำงาน"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"ยกเลิก"</string>
     <string name="ok" msgid="7898366843681727667">"ตกลง"</string>
     <string name="voice_input" msgid="2466640768843347841">"การป้อนข้อมูลด้วยเสียง"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"บนแป้นพิมพ์หลัก"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"บนแป้นพิมพ์สัญลักษณ์"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"ปิด"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"ไมค์บนแป้นพิมพ์หลัก"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"ไมค์บนแป้นพิมพ์สัญลักษณ์"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"ปิดใช้งานป้อนข้อมูลด้วยเสียง"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"เลือกวิธีการป้อนข้อมูล"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ภาษาในการป้อนข้อมูล"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"เลื่อนนิ้วไปบนแป้นเคาะวรรคเพื่อเปลี่ยนภาษา"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"เปิดใช้งานการแสดงความคิดเห็นจากผู้ใช้"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"ช่วยปรับปรุงตัวแก้ไขวิธีการป้อนข้อมูลนี้โดยการส่งสถิติการใช้งานและรายงานการขัดข้องถึง Google โดยอัตโนมัติ"</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"แตะเพื่อแก้ไขคำ"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"แตะคำที่ป้อนไว้เพื่อแก้ไข"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"แตะคำที่ป้อนไว้เพื่อแก้ไข เฉพาะเมื่อเห็นข้อเสนอแนะเท่านั้น"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"ชุดรูปแบบแป้นพิมพ์"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"แป้นพิมพ์ภาษาเช็ก"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"แป้นพิมพ์ภาษาเดนมาร์ก"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"แป้นพิมพ์ภาษาเยอรมัน"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"แป้นพิมพ์ภาษาอังกฤษ (สหราชอาณาจักร)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"แป้นพิมพ์ภาษาอังกฤษ (สหรัฐอเมริกา)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"แป้นพิมพ์ภาษาเยอรมัน"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"แป้นพิมพ์ภาษาอังกฤษ (สหราชอาณาจักร)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"แป้นพิมพ์ภาษาอังกฤษ (สหรัฐอเมริกา)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"แปันพิมพ์ภาษาสเปน"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"แป้นพิมพ์ภาษาสเปน (สหรัฐอเมริกา)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"แป้นพิมพ์ภาษาฝรั่งเศส"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"แป้นพิมพ์ภาษาอิตาลี"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"แป้นพิมพ์ภาษาฝรั่งเศส (แคนาดา)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"แป้นพิมพ์ภาษาฝรั่งเศส (สวิตเซอร์แลนด์)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"แป้นพิมพ์ภาษาอิตาลี"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"แป้นพิมพ์ภาษานอร์เวย์"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"แป้นพิมพ์ภาษาดัตช์"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"แป้นพิมพ์ภาษารัสเซีย"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"แป้นพิมพ์ภาษาเซอร์เบีย"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"แป้นพิมพ์ภาษาสวีเดน"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"เสียงภาษาเช็ก"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"เสียงภาษาเยอรมัน"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"เสียงภาษาอังกฤษ (ออสเตรเลีย)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"เสียงภาษาอังกฤษ (สหราชอาณาจักร)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"เสียงภาษาอังกฤษ (อินเดีย)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"เสียงภาษาอังกฤษ (นิวซีแลนด์)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"เสียงภาษาอังกฤษ (สหรัฐอเมริกา)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"เสียงภาษาแอฟริกัน"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"เสียงภาษาเช็ก"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"เสียงภาษาเยอรมัน"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"เสียงภาษาอังกฤษ"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"เสียงภาษาสเปน"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"เสียงภาษาฝรั่งเศส"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"เสียงภาษาอิตาลี"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"เสียงภาษาญี่ปุ่น"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"เสียงภาษาเกาหลี"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"เสียงภาษาดัตช์"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"เสียงภาษาโปแลนด์"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"เสียงภาษาโปรตุเกส"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"เสียงภาษารัสเซีย"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"เสียงภาษาตุรกี"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"เสียงภาษาจีน (จีน)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"เสียงภาษาจีน (ไต้หวัน)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"เสียงภาษาจีนกวางตุ้ง"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"เสียงภาษาจีนกลาง"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"เสียงภาษาซูลู"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"โหมดศึกษาประโยชน์ในการใช้งาน"</string>
 </resources>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 1441480b56080c7730401b68d9e1a7ecb33050b8..55f98de10d82e4f0136c115e1eda722c4772b137 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tunog sa keypress"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Popup sa keypress"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Mga setting ng suhestiyon ng salita"</string>
+    <string name="general_category" msgid="1859088467017573195">"Pangkalahatan"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Pagwawasto ng teksto"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalization"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Mga mabilisang pagsasaayos"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Itinatama ang mga karaniwang na-type na mali"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Magpakita ng mga suhestiyon ng pagwawasto"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Ipakita ang mga iminumungkahing salita habang nagta-type"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Palaging ipakita"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Ipakita sa portrait mode"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Palaging itago"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Ipakita ang key ng mga setting"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Awtomatiko"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Palaging ipakita"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Palaging itago"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Mga suhestiyon ng salita"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Awtomatikong itama ang nakaraang salita"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Awtomatikong pagwasto"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Awto tinatama ng spacebar at bantas ang maling na-type"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Naka-off"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Modest"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresibo"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Mga Suhestiyon na Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Gamitin ang nakaraang salita upang pahusayin ang suhestiyon"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Susunod"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Tapos na"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Ipadala"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Higit pa"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Intay"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Tanggalin"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Bumalik"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Mga Setting"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Puwang"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Mga Simbolo"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Input ng Boses"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Naka-on ang mga simbolo"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Naka-off ang mga simbolo"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Naka-on ang shift"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Naka-off ang shift"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Pag-input ng boses"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Hindi kasalukuyang suportado ang pag-input ng boses para sa iyong wika, ngunit gumagana sa Ingles."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ang pag-input ng boses ay isang tampok na pang-eksperimento na gumagamit ng naka-network na pagkilala sa pananalita ng Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Upang i-off ang pag-input ng boses, pumunta sa mga setting ng keyboard."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Upang gumamit ng pag-input ng boses, pindutin ang pindutang microphone o i-slide ang iyong daliri sa screen keyboard."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Gumagamit ang pag-input ng boses ng speech recognition ng Google. Nalalapat "<a href="http://m.google.com/privacy">"Ang Patakaran sa Privacy ng Mobile"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Upang i-off ang pag-input ng boses, pumunta sa mga setting ng pamamaraan ng pag-input."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Upang gamitin ang pag-input ng boses, pindutin ang pindutan na mikropono."</string>
     <string name="voice_listening" msgid="467518160751321844">"Magsalita ngayon"</string>
     <string name="voice_working" msgid="6666937792815731889">"Nagtatrabaho"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Kanselahin"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Pag-input ng boses"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Sa pangunahing keyboard"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Sa keyboard ng mga simbolo"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Naka-off"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Mic sa pangunahing keyboard"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Mic sa keyboard ng mga simbolo"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Hindi pinagana ang voice input"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Pumili ng paraan ng pag-input"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Mag-input ng mga wika"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"I-slide ang daliri sa spacebar upang palitan ang wika"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Paganahin ang feedback ng user"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Tumulong na pahusayin ang editor ng paraan ng pag-input na ito sa pamamagitan ng awtomatikong pagpapadala ng mga istatistika ng paggamit at mga ulat ng crash sa Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Pindutin upang itama ang mga salita"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pindutin ang mga ipinasok na salita upang itama ang mga ito"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pindutin ang mga inilagay na salita upang iwasto ang mga ito, kapag nakikita lang ang mga suhestiyon"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema ng Keyboard"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Czech na Keyboard"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danish na Keyboard"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"German Keyboard"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Ingles (Great Britain) na Keyboard"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Ingles (Estados Unidos) na Keyboard"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"German na Keyboard"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Ingles (UK) na Keyboard"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Ingles (US) na Keyboard"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Spanish na Keyboard"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Spanish (US) na Keyboard"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"French na Keyboard"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italian Keyboard"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"French (Canada) na Keyboard"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"French (Switzerland) na Keyboard"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Italian na Keyboard"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norwegian na Keyboard"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Dutch na Keyboard"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Russian na Keyboard"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Serbian na Keyboard"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Swedish na Keyboard"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Czech na Boses"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"German Boses"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Ingles (Australia) na Boses"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Ingles (Great Britain) na Boses"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Ingles (India) na Boses"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Ingles (New Zealand) na Boses"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Ingles (Estados Unidos) na Boses"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikaans na Boses"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Czech na Boses"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"German na Boses"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Ingles na Boses"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Spanish na Boses"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"French na Boses"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Italian na Boses"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japanese na Boses"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Korean na Boses"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Dutch na Boses"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Polish na Boses"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portuguese na Boses"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Russian na Boses"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Turkish na Boses"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Chinese (China) na Boses"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Chinese (Taiwan) na Boses"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Chinese, Yue na Boses"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Chinese, Mandarin na Boses"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"isiZulu na Boses"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Usability Study Mode"</string>
 </resources>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 69e5642c7d17c7b909de7bb99de94b580a59eba9..1baed4de67975be66571fc51a4cbdb1e02bef1d4 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Tuşa basıldığında titret"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tuşa basıldığında ses çıkar"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Tuşa basıldığında pop-up aç"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Kelime önerme ayarları"</string>
+    <string name="general_category" msgid="1859088467017573195">"Genel"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Metin düzeltme"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Otomatik olarak büyük harf yap"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Hızlı onarımlar"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Yaygın olarak yapılan yazım hatalarını düzeltir"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Düzeltme önerilerini göster"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Yazarken, önerilen kelimeleri görüntüle"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Her zaman göster"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Dikey modda göster"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Her zaman gizle"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Ayarları göster tuşu"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Otomatik"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Her zaman göster"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Her zaman gizle"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Kelime önerileri"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Önceki kelimeyi otomatik olarak düzelt"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Otomatik düzeltme"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Boşluk çbğ ve nokt işr yanlış yazılan kelimeleri oto düzeltir"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Kapalı"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Ölçülü"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Agresif"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram Önerileri"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Öneriyi geliştirmek için önceki kelimeyi kullanın"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Ä°leri"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Bitti"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Gönder"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"DiÄŸer"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Durkl"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Bekle"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Sil"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Ayarlar"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Ãœst Karakter"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"BoÅŸluk"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Simgeler"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Sekme"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Ses GiriÅŸi"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Simgeler açık"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Simgeler kapalı"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Üst Karakter açık"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Üst Karakter kapalı"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Ses giriÅŸi"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Ses girişi, şu anda sizin diliniz için desteklenmiyor ama İngilizce dilinde kullanılabilir."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ses girişi, Google\'ın ağ bağlantılı ses tanıma işlevini kullanan deneysel bir özelliktir."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ses girişini kapatmak için klavye ayarlarına gidin."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ses girişini kullanmak için mikrofon düğmesine basın veya parmağınızı dokunmatik klavye üzerinde kaydırın."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ses girişi Google\'ın konuşma tanıma işlevini kullanır. "<a href="http://m.google.com/privacy">" Mobil Gizlilik Politikası"</a>" geçerlidir."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ses girişini kapatmak için giriş yöntemi ayarlarına gidin."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ses girişini kullanmak için mikrofon düğmesine basın."</string>
     <string name="voice_listening" msgid="467518160751321844">"Åžimdi konuÅŸun"</string>
     <string name="voice_working" msgid="6666937792815731889">"Çalışıyor"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Ä°ptal"</string>
     <string name="ok" msgid="7898366843681727667">"Tamam"</string>
     <string name="voice_input" msgid="2466640768843347841">"Ses giriÅŸi"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Ana klavyede"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Simge klavyesinde"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Kapalı"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Ana klavyede mikrfn"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Simge klavysnd mikrf"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Sesle giriş devr dşı"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Giriş yöntemini seç"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"GiriÅŸ dilleri"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Dili değiştirmek için parmağınızı boşluk çubuğu üzerinde kaydırın"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"Sözlük kullanılabilir"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"Kullanıcı geri bildirimini etkinleştir"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Kullanım istatistiklerini ve kilitlenme raporlarını Google\'a otomatik olarak göndererek bu giriş yöntemi düzenleyicisinin iyileştirilmesine yardımcı olun."</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Kelimeleri düzeltmek için dokunun"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Yazdığınız kelimelere dokunarak kelimelerde düzeltme yapabilirsiniz"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Kelimeleri düzeltmek için dokunun"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Yalnızca öneriler görünür olduğunda, düzeltmek için girilen kelimelere dokunun"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Klavye Teması"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Çekçe Klavye"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Danca Klavye"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Almanca Klavye"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Ä°ngilizce (Ä°ngiltere) Klavye"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Ä°ngilizce (ABD) Klavye"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Ä°spanyolca Klavye"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Ä°spanyolca (ABD) Klavye"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Fransızca Klavye"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Fransızca (Kanada) Klavye"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Fransızca (İsviçre) Klavye"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Ä°talyanca Klavye"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Norveççe Klavye"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Felemenkçe Klavye"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Rusça Klavye"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Sırpça Klavye"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"İsveççe Klavye"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Afrikanca Ses"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Çekçe Ses"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Almanca Ses"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Ä°ngilizce Ses"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Ä°spanyolca Ses"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Fransızca Ses"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Ä°talyanca Ses"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Japonca Ses"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Korece Ses"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Felemenkçe Ses"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Lehçe Ses"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Portekizce Ses"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Rusça Ses"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Türkçe Ses"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Çince, Yue Ses"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Çince, Mandarin Ses"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Zuluca Ses"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Kullanılabilirlik Çalışması Modu"</string>
 </resources>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 4dc591b13c3e3e995330388c961ae158370cbfc6..26906329aa6806608cacafc54317d08cf8e72bda 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр при натиску клав."</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натиску клав."</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Сплив. при нат.клав."</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Налашт-ня пропозицій слів"</string>
+    <string name="general_category" msgid="1859088467017573195">"Загальні"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Виправлення тексту"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Авто викор. вел. літер"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Шв. виправлення"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Виправляє поширені помилки"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Показувати пропозиції виправлень"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Відображати пропоновані слова під час вводу"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Завжди показувати"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Показувати в книжковому режимі"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Завжди ховати"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Показ. клав. налашт."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Автоматично"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Завжди показ."</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Завжди ховати"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Пропозиції слів"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Автоматично виправляти попереднє слово"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Автомат. виправлення"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Пробіл і пунктуація автоматично виправляють слова з помилками"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Вимк."</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Середнє"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Повне"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Двобуквені пропозиції"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Викор. попер. слово для покращ. пропозиції"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Далі"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Надісл."</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"Алфавіт"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Більше"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Пауза"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Чек."</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Клавіша Delete"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Клавіша Return"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Клавіша Settings"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Клавіша Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Клавіша Space"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Клавіша Symbols"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Клавіша Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Клавіша Voice Input"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Символи ввімкнено"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Символи вимкнено"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift увімкнено"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift вимкнено"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Голос. ввід"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Голос. ввід наразі не підтрим. для вашої мови, але можна користуватися англійською."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голос. ввід є експеремент. ф-цією, яка викор. мережеве розпізнавання голосу Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Щоб вимкн. голос ввід, йдіть до налашт-нь клавіатури."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Щоб викор. голос. ввід, натисніть кнопку мікрофона або пересуньте палець на екранній клавіатурі."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовий ввід використовує розпізнавання мовлення Google. Застосовується "<a href="http://m.google.com/privacy">"Політика конфіденційності для мобільних пристроїв"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Щоб вимкнути голосовий ввід, перейдіть до налаштувань методів введення."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Щоб використовувати голосовий ввід, натисніть кнопку мікрофона."</string>
     <string name="voice_listening" msgid="467518160751321844">"Диктуйте"</string>
     <string name="voice_working" msgid="6666937792815731889">"Працює"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Скасувати"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Голос. ввід"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"На основ. клавіатурі"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Символьна клавіатура"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Вимк."</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Miкр. на осн. клав."</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Miкр. на симв. клавіат."</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Голос. ввід вимкнено"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Вибрати метод введення"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Переміст. палець на пробіл, щоб змін. мову"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Увімк. відгуки корист."</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Допоможіть покращ. редактор методу введ., автомат. надсилаючи в Google статистику використ. та звіти про збої."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Торкн., щоб виправ. слова"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Торкн. введених слів, щоб виправити їх"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Торкніться введених слів, щоб виправити їх, лише коли ввімкнено пропозиції"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Тема клавіатури"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Чеська розкладка"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Данська розкладка"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Німецька розкладка"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Англ. розкладка (Великобританія)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Англійська розкладка (США)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Німецька розкладка"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Англ. розкладка (Великобританія)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Англійська розкладка (США)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Іспанська розкладка"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Франц. розкладка"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Італ. розкладка"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Іспанська розкладка (США)"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Французька розкладка"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Французька розкладка (Канада)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Французька розкладка (Швейцарія)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Італійська розкладка"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Норвезька розкладка"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Голланд. розклад."</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Російська розкладка"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Сербська розкладка"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Шведська розкладка"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Чеський голос"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Німецький голос"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Англ. голос (Австралія)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Англ. голос (Великобританія)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Англ. голос (Індія)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Англ. голос (Нова Зеландія)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Англійський голос (США)"</string>
-    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Іспанський голос"</string>
-    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Франц. голос"</string>
-    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Японський голос"</string>
-    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Корейськ. голос"</string>
-    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Польський голос"</string>
-    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Португал. голос"</string>
-    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Російський голос"</string>
-    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Турецький голос"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Китайський голос (Китай)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Китайськ. голос (Тайвань)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Voice мовою африкаанс"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Голос чеською"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Голос німецькою"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Voice англійською мовою"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Голос іспанською"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Голос французькою"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Voice італійською мовою"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Голос японською"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Голос корейською"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Voice голландською мовою"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Голос польською"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Голос португальською"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Голос російською"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Голос турецькою"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Voice китайською, юеською мовою"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Voice китайською, мандарин. мовою"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Voice мовою ісізулу"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Режим вивчення зручності у використанні"</string>
 </resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index e03fb3706e9b14dc13f477bfd915a1a5a07d3890..70defe3b7df129ef296e45da6ae6493a8c7b7945 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Âm thanh khi nhấn phím"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"Cửa sổ bật lên khi nhấn phím"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"Cài đặt đề xuất từ"</string>
+    <string name="general_category" msgid="1859088467017573195">"Chung"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"Sửa văn bản"</string>
     <string name="auto_cap" msgid="1719746674854628252">"Tự động viết hoa"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"Sá»­a nhanh"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Sửa lỗi nhập thông thường"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"Hiển thị gợi ý sửa"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"Hiển thị từ được đề xuất khi nhập"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"Luôn hiển thị"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"Hiển thị trên chế độ khổ đứng"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"Luôn ẩn"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"Hiển thị phím cài đặt"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Tá»± Ä‘á»™ng"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Luôn hiển thị"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"Luôn ẩn"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"Đề xuất từ"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"Tự động sửa từ trước đó"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"Tá»± Ä‘á»™ng sá»­a"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"Phím cách và dấu câu tự động sửa từ nhập sai"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"Tắt"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"Đơn giản"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"Linh hoạt"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"Đề xuất Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Sử dụng từ trước đó để cải tiến đề xuất"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"Tiếp theo"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Xong"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Gửi"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"Khác"</string>
     <string name="label_pause_key" msgid="181098308428035340">"Tạm dừng"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"Đợi"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"Xóa"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"Quay lại"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"Cài đặt"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"Dấu cách"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"Biểu tượng"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"Nhập liệu bằng giọng nói"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"Bật biểu tượng"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"Tắt biểu tượng"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Bật Shift"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Tắt Shift"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Nhập liệu bằng giọng nói"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Nhập liệu bằng giọng nói hiện không được hỗ trợ cho ngôn ngữ của bạn nhưng hoạt động với ngôn ngữ tiếng Anh."</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Nhập liệu bằng giọng nói là tính năng thử nghiệm sử dụng nhận dạng tiếng nói được kết nối mạng của Google."</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Để tắt nhập liệu bằng giọng nói, đi tới cài đặt bàn phím."</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Để sử dụng nhập liệu bằng giọng nói, hãy nhấn nút micrô hoặc trượt ngón tay trên bàn phím ảo."</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Nhập liệu bằng giọng nói sử dụng nhận dạng giọng nói của Google. Áp dụng "<a href="http://m.google.com/privacy">"Chính sách bảo mật dành cho điện thoại di động"</a>"."</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Để tắt nhập liệu bằng giọng nói, đi tới cài đặt phương pháp nhập liệu."</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Để sử dụng nhập liệu bằng giọng nói, hãy nhấn nút micrô."</string>
     <string name="voice_listening" msgid="467518160751321844">"Xin mời nói"</string>
     <string name="voice_working" msgid="6666937792815731889">"Đang hoạt động"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"Huá»·"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Nhập liệu bằng giọng nói"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"Trên bàn phím chính"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"Trên bàn phím biểu tượng"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"Tắt"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"Micrô trên bàn phím chính"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"Micrô trên bàn phím biểu tượng"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Nhập liệu bằng giọng nói đã bị vô hiệu hóa"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"Chọn phương thức nhập"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Ngôn ngữ nhập"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Trượt ngón tay trên phím cách để thay đổi ngôn ngữ"</string>
@@ -105,44 +103,40 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Bật phản hồi của người dùng"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Giúp nâng cao trình chỉnh sửa phương thức nhập này bằng cách tự động gửi thống kê sử dụng và báo cáo sự cố cho Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Chạm để sửa từ"</string>
-    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Chạm các từ đã nhập để sửa"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Chạm các từ đã nhập để sửa, chỉ khi các đề xuất hiển thị"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Chủ đề bàn phím"</string>
     <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"Bàn phím tiếng Séc"</string>
     <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"Bàn phím tiếng Đan Mạch"</string>
-    <!-- outdated translation 5111274665584117449 -->     <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Bàn phím tiếng Đức"</string>
-    <!-- outdated translation 2339748210942078577 -->     <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Bàn phím tiếng Anh (Anh)"</string>
-    <!-- outdated translation 2979257184475020604 -->     <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Bàn phím tiếng Anh (Mỹ)"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"Bàn phím tiếng Đức"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"Bàn phím tiếng Anh (Anh)"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"Bàn phím tiếng Anh (Mỹ)"</string>
     <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"Bàn phím tiếng Tây Ban Nha"</string>
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"Bàn phím tiếng Tây Ban Nha (Mỹ)"</string>
     <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"Bàn phím tiếng Pháp"</string>
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- outdated translation 2281078537437195027 -->     <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Bàn phím tiếng Ý"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"Bàn phím tiếng Pháp (Canada)"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"Bàn phím tiếng Pháp (Thụy Sĩ)"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"Bàn phím tiếng Ý"</string>
     <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"Bàn phím tiếng Na Uy"</string>
     <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"Bàn phím tiếng Hà Lan"</string>
     <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"Bàn phím tiếng Nga"</string>
     <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"Bàn phím tiếng Serbia"</string>
     <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"Bàn phím tiếng Thụy Điển"</string>
-    <!-- outdated translation 157536957128878726 -->     <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Giọng nói tiếng Séc"</string>
-    <!-- outdated translation 309350321180102217 -->     <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Giọng nói tiếng Đức"</string>
-    <string name="subtype_mode_en_AU_voice" msgid="1103892562629586486">"Giọng nói tiếng Anh (Úc)"</string>
-    <!-- outdated translation 3773764031764533262 -->     <string name="subtype_mode_en_GB_voice" msgid="7868802451720612888">"Giọng nói tiếng Anh (Anh)"</string>
-    <string name="subtype_mode_en_IN_voice" msgid="4834879535045820293">"Giọng nói tiếng Anh (Ấn Độ)"</string>
-    <string name="subtype_mode_en_NZ_voice" msgid="2739391364469645636">"Giọng nói tiếng Anh (New Zealand)"</string>
-    <!-- outdated translation 1582519352222847297 -->     <string name="subtype_mode_en_US_voice" msgid="2300580846081472319">"Giọng nói tiếng Anh (Mỹ)"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"Giọng tiếng Hà Lan ở Nam Phi"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"Giọng nói tiếng Séc"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"Giọng nói tiếng Đức"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"Giọng tiếng Anh"</string>
     <string name="subtype_mode_es_voice" msgid="1323473601346507487">"Giọng nói tiếng Tây Ban Nha"</string>
     <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"Giọng nói tiếng Pháp"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"Giọng nói tiếng Ý"</string>
     <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"Giọng nói tiếng Nhật"</string>
     <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"Giọng nói tiếng Hàn"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"Giọng nói tiếng Hà Lan"</string>
     <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"Giọng nói tiếng Ba Lan"</string>
     <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"Giọng nói tiếng Bồ Đào Nha"</string>
     <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"Giọng nói tiếng Nga"</string>
     <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"Giọng nói tiếng Thổ Nhĩ Kỳ"</string>
-    <!-- outdated translation 3154514897179707124 -->     <string name="subtype_mode_zh_CN_voice" msgid="6452442204238513331">"Giọng nói tiếng Trung (Trung Quốc)"</string>
-    <!-- outdated translation 1524137359275360490 -->     <string name="subtype_mode_zh_TW_voice" msgid="3640444875378221940">"Giọng nói tiếng Trung (Đài Loan)"</string>
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"Giọng tiếng Trung, Yue"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"Giọng tiếng Trung, tiếng Quan thoại"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"Giọng isiZulu"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"Chế độ nghiên cứu tính khả dụng"</string>
 </resources>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 2ef0c9c55a72ad7c2254afb63cbc502373b3efff..3b092bfcc2b1a6bf1f6ebb0fcf3c4dcfbdefc1a8 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"按键时振动"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"按键时播放音效"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"按键时显示弹出窗口"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"字词建议设置"</string>
+    <string name="general_category" msgid="1859088467017573195">"常规"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"文本更正"</string>
     <string name="auto_cap" msgid="1719746674854628252">"自动大写"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"快速纠正"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"纠正常见的输入错误"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"显示更正建议"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"键入时显示建议的字词"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"始终显示"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"以纵向模式显示"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"始终隐藏"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"显示设置键"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自动"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"始终显示"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"始终隐藏"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"字词建议"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"自动纠正前面的字词"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"自动更正"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"空格键或标点自动更正拼写错误的字词"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"关闭"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"部分"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"全部"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"双连词建议"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"使用以前的字词改进建议"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"下一步"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"发送"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"更多"</string>
     <string name="label_pause_key" msgid="181098308428035340">"暂停"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"等待"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"删除"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"回车"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"设置"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"空格"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"符号"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"语音输入"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"符号模式已打开"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"符号模式已关闭"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"Shift 模式已打开"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"Shift 模式已关闭"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"语音输入"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"语音输入功能当前还不支持您的语言,您只能输入英语语音。"</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"语音输入是一项试验性的功能,它采用了 Google 的网络语音识别功能。"</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"要关闭语音输入功能,请转至键盘设置。"</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"要使用语音输入,请按麦克风按钮或者在屏幕键盘上滑动手指。"</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"语音输入采用了 Google 的语音识别技术,因此请遵守"<a href="http://m.google.com/privacy">"“Google 移动”隐私权政策"</a>"。"</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"要关闭语音输入功能,请转至输入法设置。"</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"要使用语音输入功能,请按“麦克风”按钮。"</string>
     <string name="voice_listening" msgid="467518160751321844">"请开始说话"</string>
     <string name="voice_working" msgid="6666937792815731889">"正在处理"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"取消"</string>
     <string name="ok" msgid="7898366843681727667">"确定"</string>
     <string name="voice_input" msgid="2466640768843347841">"语音输入"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"主键盘上"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"符号键盘上"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"关闭"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"主键盘上的麦克风"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"符号键盘上的麦克风"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"语音输入功能已停用"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"选择输入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"在空格键上滑动手指可更改语言"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"提供字典"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"启用用户反馈"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"自动向 Google 发送使用情况统计信息和崩溃报告,帮助改进该输入法编辑器。"</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"触摸即可更正字词"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"您可以触摸已键入的字词,对其进行更正"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"触摸以更正字词"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"仅在系统显示建议后,才触摸输入的字词进行更正"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"键盘主题"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"捷克语键盘"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"丹麦语键盘"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"德语键盘"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"英语(英国)键盘"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"英语(美国)键盘"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"西班牙语键盘"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"西班牙语(美国)键盘"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"法语键盘"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"法语(加拿大)键盘"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"法语(瑞士)键盘"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"意大利语键盘"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"挪威语键盘"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"荷兰语键盘"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"俄语键盘"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"塞尔维亚语键盘"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"瑞典语键盘"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"南非荷兰语语音"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"捷克语语音"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"德语语音"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"英语语音"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"西班牙语语音"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"法语语音"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"意大利语语音"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"日语语音"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"韩语语音"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"荷兰语语音"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"波兰语语音"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"葡萄牙语语音"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"俄语语音"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"土耳其语语音"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"中文,粤语语音"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"中文,普通话语音"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"祖鲁语语音"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"可用性研究模式"</string>
 </resources>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 0f127aec3ab0d4c5b0dce5278441ee2d26baee00..c9c7ae88a0832536c45c8a600bfde7c03d0e8ea5 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -26,32 +26,25 @@
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"按鍵時震動"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"按鍵時播放音效"</string>
     <string name="popup_on_keypress" msgid="123894815723512944">"按鍵時顯示彈出式視窗"</string>
-    <string name="prediction_category" msgid="7027100625580696660">"字詞建議設定"</string>
+    <string name="general_category" msgid="1859088467017573195">"一般設定"</string>
+    <string name="prediction_category" msgid="6361242011806282176">"文字修正"</string>
     <string name="auto_cap" msgid="1719746674854628252">"自動大寫"</string>
     <string name="quick_fixes" msgid="5353213327680897927">"快速修正"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"修正一般打字錯誤"</string>
-    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
-    <skip />
-    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
-    <skip />
-    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
-    <skip />
+    <string name="prefs_show_suggestions" msgid="8026799663445531637">"顯示修正建議"</string>
+    <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"輸入時顯示建議字詞"</string>
+    <string name="prefs_suggestion_visibility_show_name" msgid="3219916594067551303">"永遠顯示"</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3551821800439659812">"以垂直模式顯示"</string>
+    <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"永遠隱藏"</string>
     <string name="prefs_settings_key" msgid="4623341240804046498">"顯示設定金鑰"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自動"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"永遠顯示"</string>
     <string name="settings_key_mode_always_hide_name" msgid="7833948046716923994">"永遠隱藏"</string>
-    <!-- outdated translation 7911639788808958255 -->     <string name="auto_correction" msgid="4979925752001319458">"字詞建議"</string>
-    <!-- outdated translation 6881047311475758267 -->     <string name="auto_correction_summary" msgid="2591572172085659910">"自動修正前一個字詞"</string>
-    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
-    <skip />
-    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
-    <skip />
+    <string name="auto_correction" msgid="4979925752001319458">"自動修正"</string>
+    <string name="auto_correction_summary" msgid="5625751551134658006">"自動插入空白鍵和標點符號鍵盤,以修正拼字錯誤"</string>
+    <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"關閉"</string>
+    <string name="auto_correction_threshold_mode_modest" msgid="8788366690620799097">"部分"</string>
+    <string name="auto_correction_threshold_mode_aggeressive" msgid="3524029103734923819">"全部"</string>
     <string name="bigram_suggestion" msgid="1323347224043514969">"雙連詞建議"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"根據前一個字詞自動找出更適合的建議"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string>
@@ -59,16 +52,27 @@
     <string name="label_next_key" msgid="362972844525672568">"繼續"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"傳送"</string>
-    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
-    <skip />
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
     <string name="label_more_key" msgid="3760239494604948502">"更多"</string>
     <string name="label_pause_key" msgid="181098308428035340">"暫停"</string>
     <string name="label_wait_key" msgid="6402152600878093134">"等候"</string>
+    <string name="description_delete_key" msgid="5586406298531883960">"刪除"</string>
+    <string name="description_return_key" msgid="8750044000806461678">"返回"</string>
+    <string name="description_settings_key" msgid="7484527796782969219">"設定"</string>
+    <string name="description_shift_key" msgid="346906866277787836">"Shift 鍵"</string>
+    <string name="description_space_key" msgid="8512130111575878517">"空白鍵"</string>
+    <string name="description_switch_alpha_symbol_key" msgid="4537975384274405537">"符號"</string>
+    <string name="description_tab_key" msgid="828186583738307137">"Tab 鍵"</string>
+    <string name="description_voice_key" msgid="3057731675774652754">"語音輸入"</string>
+    <string name="description_symbols_on" msgid="2994366855822840559">"開啟符號"</string>
+    <string name="description_symbols_off" msgid="3209578267079515136">"關閉符號"</string>
+    <string name="description_shift_on" msgid="6983188949895971587">"開啟位移"</string>
+    <string name="description_shift_off" msgid="8553265474523069034">"關閉位移"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"語音輸入"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"語音輸入目前不支援您的語言,但是可以辨識英文。"</string>
-    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"語音輸入這項實驗功能運用了 Google 的網路語音辨識系統。"</string>
-    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"請前往鍵盤設定來關閉語音輸入。"</string>
-    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"如要使用語音輸入,按下 [麥克風] 按鈕,或將手指滑過螢幕小鍵盤即可。"</string>
+    <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"語音輸入使用 Google 的語音辨識功能,並遵循《"<a href="http://m.google.com/privacy">"行動服務隱私權政策"</a>"》。"</string>
+    <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"如要關閉語音輸入,請前往輸入方式設定。"</string>
+    <string name="voice_hint_dialog_message" msgid="1420686286820661548">"如要使用語音輸入,請按下麥克風按鈕。"</string>
     <string name="voice_listening" msgid="467518160751321844">"請說話"</string>
     <string name="voice_working" msgid="6666937792815731889">"辨識中"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -85,18 +89,12 @@
     <string name="cancel" msgid="6830980399865683324">"取消"</string>
     <string name="ok" msgid="7898366843681727667">"確定"</string>
     <string name="voice_input" msgid="2466640768843347841">"語音輸入"</string>
-    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
-    <skip />
-    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
-    <skip />
+    <string name="voice_input_modes_main_keyboard" msgid="3360660341121083174">"主鍵盤上"</string>
+    <string name="voice_input_modes_symbols_keyboard" msgid="7203213240786084067">"符號鍵盤上"</string>
+    <string name="voice_input_modes_off" msgid="3745699748218082014">"關閉"</string>
+    <string name="voice_input_modes_summary_main_keyboard" msgid="6586544292900314339">"主鍵盤上的麥克風"</string>
+    <string name="voice_input_modes_summary_symbols_keyboard" msgid="5233725927281932391">"符號鍵盤上的麥克風"</string>
+    <string name="voice_input_modes_summary_off" msgid="63875609591897607">"語音輸入已停用"</string>
     <string name="selectInputMethod" msgid="315076553378705821">"選取輸入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"以手指在空白鍵上滑動可變更語言"</string>
@@ -104,75 +102,41 @@
     <string name="has_dictionary" msgid="6071847973466625007">"可使用字典"</string>
     <string name="prefs_enable_log" msgid="6620424505072963557">"啟用使用者意見回饋"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"自動將使用統計資料和當機報告傳送給 Google,協助改善這個輸入法編輯器。"</string>
-    <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"輕觸即可重新修正字詞"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"只要輕觸您所輸入的字詞,即可重新予以修正"</string>
+    <string name="prefs_enable_recorrection" msgid="4588408906649533582">"輕觸此處可修正字詞"</string>
+    <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"輕觸輸入的字詞即可加以修正 (出現建議時才適用)"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"鍵盤主題"</string>
-    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
-    <skip />
-    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_keyboard (1990979135959462145) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_keyboard (7945856548410373708) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_keyboard (3708655163769735410) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_US_keyboard (3702125193532262008) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
-    <skip />
-    <!-- no translation found for subtype_mode_it_keyboard (4934199655425394484) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
-    <skip />
-    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
-    <skip />
-    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
-    <skip />
-    <!-- no translation found for subtype_mode_cs_voice (1136386688120958641) -->
-    <skip />
-    <!-- no translation found for subtype_mode_de_voice (8378803143958089866) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_GB_voice (7868802451720612888) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
-    <skip />
-    <!-- no translation found for subtype_mode_en_US_voice (2300580846081472319) -->
-    <skip />
-    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
-    <skip />
-    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
-    <skip />
-    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
-    <skip />
-    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_CN_voice (6452442204238513331) -->
-    <skip />
-    <!-- no translation found for subtype_mode_zh_TW_voice (3640444875378221940) -->
-    <skip />
-    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
-    <skip />
+    <string name="subtype_mode_cs_keyboard" msgid="1141718931112377586">"捷克文鍵盤"</string>
+    <string name="subtype_mode_da_keyboard" msgid="1243570804427922104">"丹麥文鍵盤"</string>
+    <string name="subtype_mode_de_keyboard" msgid="1990979135959462145">"德文鍵盤"</string>
+    <string name="subtype_mode_en_GB_keyboard" msgid="7945856548410373708">"英文 (英國) 鍵盤"</string>
+    <string name="subtype_mode_en_US_keyboard" msgid="3708655163769735410">"英文 (美國) 鍵盤"</string>
+    <string name="subtype_mode_es_keyboard" msgid="1775125478866113148">"西班牙文鍵盤"</string>
+    <string name="subtype_mode_es_US_keyboard" msgid="3702125193532262008">"西班牙文 (美國) 鍵盤"</string>
+    <string name="subtype_mode_fr_keyboard" msgid="8016515336759761014">"法文鍵盤"</string>
+    <string name="subtype_mode_fr_CA_keyboard" msgid="2628517247158376263">"法文 (加拿大) 鍵盤"</string>
+    <string name="subtype_mode_fr_CH_keyboard" msgid="6742806653181621228">"法文 (瑞士) 鍵盤"</string>
+    <string name="subtype_mode_it_keyboard" msgid="4934199655425394484">"義大利文鍵盤"</string>
+    <string name="subtype_mode_nb_keyboard" msgid="1175783216100212360">"挪威文鍵盤"</string>
+    <string name="subtype_mode_nl_keyboard" msgid="5090278083256037936">"荷蘭文鍵盤"</string>
+    <string name="subtype_mode_ru_keyboard" msgid="1383995915064277943">"俄文鍵盤"</string>
+    <string name="subtype_mode_sr_keyboard" msgid="5019440799612208168">"塞爾維亞文鍵盤"</string>
+    <string name="subtype_mode_sv_keyboard" msgid="4933838139861753401">"瑞典文語音"</string>
+    <string name="subtype_mode_af_voice" msgid="7542487489657902699">"南非荷蘭文語音"</string>
+    <string name="subtype_mode_cs_voice" msgid="1136386688120958641">"捷克文語音"</string>
+    <string name="subtype_mode_de_voice" msgid="8378803143958089866">"德文語音"</string>
+    <string name="subtype_mode_en_voice" msgid="6643420989651848728">"英文語音"</string>
+    <string name="subtype_mode_es_voice" msgid="1323473601346507487">"西班牙文語音"</string>
+    <string name="subtype_mode_fr_voice" msgid="4675914209337824269">"法文語音"</string>
+    <string name="subtype_mode_it_voice" msgid="5077373057157441323">"義大利文語音"</string>
+    <string name="subtype_mode_ja_voice" msgid="6604859132669646367">"日文語音"</string>
+    <string name="subtype_mode_ko_voice" msgid="4890391190762324561">"韓文語音"</string>
+    <string name="subtype_mode_nl_voice" msgid="2603552312869575021">"荷蘭文語音"</string>
+    <string name="subtype_mode_pl_voice" msgid="2076196021014840487">"波蘭文語音"</string>
+    <string name="subtype_mode_pt_voice" msgid="8036522712795994397">"葡萄牙文語音"</string>
+    <string name="subtype_mode_ru_voice" msgid="8034596947963787529">"俄文語音"</string>
+    <string name="subtype_mode_tr_voice" msgid="3402067436761140005">"土耳其文語音"</string>
+    <string name="subtype_mode_yue_voice" msgid="1576887891614624263">"中文 (粵語) 語音"</string>
+    <string name="subtype_mode_zh_voice" msgid="4360533229467271152">"中文 (華語) 語音"</string>
+    <string name="subtype_mode_zu_voice" msgid="1146122571698884636">"祖魯文語音"</string>
+    <string name="prefs_usability_study_mode" msgid="6937813623647419810">"使用習慣學習模式"</string>
 </resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 9759e0eb64c727cd89e18364c650b3338fb4c8dc..f0da2744bed76eed006991fb528619d5be9e4a7f 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -140,6 +140,8 @@
         <attr name="keyStyle" format="string" />
         <!-- Shift key icon for shifted state -->
         <attr name="shiftedIcon" format="reference" />
+        <!-- The key is enabled and responds on press. -->
+        <attr name="enabled" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="Keyboard_Row">
@@ -166,10 +168,11 @@
             <enum name="web" value="4" />
             <enum name="phone" value="5" />
         </attr>
+        <attr name="passwordInput" format="boolean" />
         <attr name="hasSettingsKey" format="string" />
         <attr name="voiceKeyEnabled" format="string" />
         <attr name="hasVoiceKey" format="string" />
-        <attr name="imeOptions">
+        <attr name="imeAction">
             <!-- This should be aligned with EditorInfo.IME_ACTION_* -->
             <flag name="actionUnspecified" value="0" />
             <flag name="actionNone" value="1" />
@@ -180,6 +183,8 @@
             <flag name="actionDone" value="6" />
             <flag name="actionPrevious" value="7" />
         </attr>
+        <attr name="languageCode" format="string" />
+        <attr name="countryCode" format="string" />
     </declare-styleable>
 
     <declare-styleable name="Keyboard_KeyStyle">
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index bf42589ea636f42dc1d6a9af401b58b06a576881..bdb4409f0b522add7fe65ec4dfc054389cc438f0 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -60,6 +60,7 @@
     <integer name="config_long_press_key_timeout">400</integer>
     <integer name="config_long_press_shift_key_timeout">1200</integer>
     <integer name="config_touch_noise_threshold_millis">40</integer>
+    <integer name="config_double_spaces_turn_into_period_timeout">1100</integer>
     <dimen name="config_touch_noise_threshold_distance">2.0mm</dimen>
     <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
     <string name="config_default_keyboard_theme_id" translatable="false">4</string>
diff --git a/java/res/values/donottranslate-altchars.xml b/java/res/values/donottranslate-altchars.xml
index 4b1a6ae6dbddc4c27729504964e7607668e1182c..518e74af1302990ae9373b35556eccecc04e2219 100644
--- a/java/res/values/donottranslate-altchars.xml
+++ b/java/res/values/donottranslate-altchars.xml
@@ -44,6 +44,9 @@
     <string name="alternates_for_scandinavia_row2_11"></string>
     <string name="alternates_for_cyrillic_e"></string>
     <string name="alternates_for_cyrillic_soft_sign"></string>
+    <string name="alternates_for_currency_dollar">¢,£,€,¥,₱</string>
+    <string name="alternates_for_currency_euro">¢,£,$,¥,₱</string>
+    <string name="alternates_for_currency_pound">¢,$,€,¥,₱</string>
     <string name="alternates_for_mic">"\@drawable/sym_keyboard_settings|\@integer/key_settings,\@drawable/sym_keyboard_mic|\@integer/key_voice"</string>
     <string name="alternates_for_smiley">":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\\\\\|:-\\\\\\\\ ,:\'(|:\'( ,:-D|:-D "</string>
     <string name="alternates_for_settings_slash">"\@drawable/sym_keyboard_settings|\@integer/key_settings,/"</string>
diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml
index 6c18cb42a12a5782aef5606cc2a0778b80bcc259..d6f9bfc28b95e2a7d775946177c851e296dd0e73 100644
--- a/java/res/values/keycodes.xml
+++ b/java/res/values/keycodes.xml
@@ -28,4 +28,24 @@
     <integer name="key_delete">-5</integer>
     <integer name="key_settings">-100</integer>
     <integer name="key_voice">-102</integer>
+
+    <!-- Array used for mapping key codes to description strings. -->
+    <array name="key_descriptions">
+        <item>@integer/key_tab</item>
+        <item>@string/description_tab_key</item>
+        <item>@integer/key_return</item>
+        <item>@string/description_return_key</item>
+        <item>@integer/key_space</item>
+        <item>@string/description_space_key</item>
+        <item>@integer/key_shift</item>
+        <item>@string/description_shift_key</item>
+        <item>@integer/key_switch_alpha_symbol</item>
+        <item>@string/description_switch_alpha_symbol_key</item>
+        <item>@integer/key_delete</item>
+        <item>@string/description_delete_key</item>
+        <item>@integer/key_settings</item>
+        <item>@string/description_settings_key</item>
+        <item>@integer/key_voice</item>
+        <item>@string/description_voice_key</item>
+    </array>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 72601c37ff4f5303684f9cadf0bc53198abe50b9..e19203e6cae966201ee65a50cd43634d37466a3d 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -102,6 +102,31 @@
     <!-- Label for "Wait" key of phone number keyboard.  Must be short to fit on key! [CHAR LIMIT=5]-->
     <string name="label_wait_key">Wait</string>
 
+    <!-- Spoken text description for delete key. -->
+    <string name="description_delete_key">Delete</string>
+    <!-- Spoken text description for return key. -->
+    <string name="description_return_key">Return</string>
+    <!-- Spoken text description for settings key. -->
+    <string name="description_settings_key">Settings</string>
+    <!-- Spoken text description for shift key. -->
+    <string name="description_shift_key">Shift</string>
+    <!-- Spoken text description for space key. -->
+    <string name="description_space_key">Space</string>
+    <!-- Spoken text description for symbols key. -->
+    <string name="description_switch_alpha_symbol_key">Symbols</string>
+    <!-- Spoken text description for tab key. -->
+    <string name="description_tab_key">Tab</string>
+    <!-- Spoken text description for voice input key. -->
+    <string name="description_voice_key">Voice Input</string>
+    <!-- Spoken text description for symbols mode on. -->
+    <string name="description_symbols_on">Symbols on</string>
+    <!-- Spoken text description for symbols mode off. -->
+    <string name="description_symbols_off">Symbols off</string>
+    <!-- Spoken text description for shift mode on. -->
+    <string name="description_shift_on">Shift on</string>
+    <!-- Spoken text description for shift mode off. -->
+    <string name="description_shift_off">Shift off</string>
+
     <!-- Voice related labels -->
 
     <!-- Title of the warning dialog that shows when a user initiates voice input for
@@ -217,6 +242,8 @@
 
     <!-- Description for Czech keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_cs_keyboard">Czech Keyboard</string>
+    <!-- Description for Arabic keyboard subtype [CHAR LIMIT=35] -->
+    <string name="subtype_mode_ar_keyboard">Arabic Keyboard</string>
     <!-- Description for Danish keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_da_keyboard">Danish Keyboard</string>
     <!-- Description for German keyboard subtype [CHAR LIMIT=35] -->
@@ -235,6 +262,9 @@
     <string name="subtype_mode_fr_CA_keyboard">French (Canada) Keyboard</string>
     <!-- Description for French (Switzerland) keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_fr_CH_keyboard">French (Switzerland) Keyboard</string>
+    <!-- Description for Hebrew keyboard subtype [CHAR LIMIT=35] -->
+    <!-- Java uses the deprecated "iw" code instead of the standard "he" code -->
+    <string name="subtype_mode_iw_keyboard">Hebrew Keyboard</string>
     <!-- Description for Italian keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_it_keyboard">Italian Keyboard</string>
     <!-- Description for Norwegian keyboard subtype [CHAR LIMIT=35] -->
diff --git a/java/res/values/whitelist.xml b/java/res/values/whitelist.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ced52e70e050a44325bec835e20a1b696f1d427a
--- /dev/null
+++ b/java/res/values/whitelist.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!--
+        An entry of the whitelist word should be:
+        1. (int)frequency
+        2. (String)before
+        3. (String)after
+     -->
+    <string-array name="wordlist_whitelist">
+
+        <item>255</item>
+        <item>ill</item>
+        <item>I\'ll</item>
+
+        <item>255</item>
+        <item>thisd</item>
+        <item>this\'d</item>
+
+    </string-array>
+</resources>
diff --git a/java/res/xml-ar/kbd_qwerty.xml b/java/res/xml-ar/kbd_qwerty.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c6a4f50ab15346f2f93718056477dfcba5a38a0
--- /dev/null
+++ b/java/res/xml-ar/kbd_qwerty.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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"
+    latin:keyboardHeight="@dimen/keyboardHeight"
+    latin:maxKeyboardHeight="50%p"
+    latin:rowHeight="25%p"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:popupKeyboardTemplate="@xml/kbd_popup_template"
+    latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_ar_rows" />
+</Keyboard>
diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml
index 98bfd7e0b2d09d68be179fe025a3eb061de57f9d..72826d4618615742bd562f905ad3184c19bacd3d 100644
--- a/java/res/xml-iw/kbd_qwerty.xml
+++ b/java/res/xml-iw/kbd_qwerty.xml
@@ -1,19 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* 
+/*
 **
 ** Copyright 2010, 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 
+** 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 
+**     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 
+** 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.
 */
 -->
@@ -30,83 +30,5 @@
     latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
 >
     <include
-        latin:keyboardLayout="@xml/kbd_key_styles" />
-    <Row
-        latin:rowEdgeFlags="top"
-    >
-        <Spacer
-            latin:horizontalGap="5%p" />
-        <Key
-            latin:keyLabel="ק"
-            latin:keyEdgeFlags="left" />
-        <Key
-            latin:keyLabel="ר" />
-        <Key
-            latin:keyLabel="א" />
-        <Key
-            latin:keyLabel="ט" />
-        <Key
-            latin:keyLabel="ו" />
-        <Key
-            latin:keyLabel="ן" />
-        <Key
-            latin:keyLabel="ם" />
-        <Key
-            latin:keyLabel="פ" />
-        <Spacer
-            latin:horizontalGap="1.25%p" />
-        <Key
-            latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="13.75%p"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyLabel="ש"
-            latin:keyEdgeFlags="left" />
-        <Key
-            latin:keyLabel="ד" />
-        <Key
-            latin:keyLabel="×’" />
-        <Key
-            latin:keyLabel="×›" />
-        <Key
-            latin:keyLabel="×¢" />
-        <Key
-            latin:keyLabel="×™" />
-        <Key
-            latin:keyLabel="×—" />
-        <Key
-            latin:keyLabel="ל" />
-        <Key
-            latin:keyLabel="ך" />
-        <Key
-            latin:keyLabel="×£"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Spacer
-            latin:horizontalGap="5%p" />
-        <Key
-            latin:keyLabel="×–"
-            latin:keyEdgeFlags="left" />
-        <Key
-            latin:keyLabel="ס" />
-        <Key
-            latin:keyLabel="ב" />
-        <Key
-            latin:keyLabel="×”" />
-        <Key
-            latin:keyLabel="× " />
-        <Key
-            latin:keyLabel="מ" />
-        <Key
-            latin:keyLabel="צ" />
-        <Key
-            latin:keyLabel="ת" />
-        <Key
-            latin:keyLabel="×¥"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <include latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+        latin:keyboardLayout="@xml/kbd_iw_rows" />
 </Keyboard>
diff --git a/java/res/xml-xlarge/kbd_ar_rows.xml b/java/res/xml-xlarge/kbd_ar_rows.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e84aae6b5906c70dd83a011af3e049af9678f23d
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_ar_rows.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<!-- This file for Arabic layout is an alpha version. It allows to enter   -->
+<!-- some right-to-left text, but it has gone through no study whatsoever, -->
+<!-- and needs to be run through UX.                                       -->
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="7.49%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ض" />
+        <Key
+            latin:keyLabel="ص" />
+        <Key
+            latin:keyLabel="Ø«" />
+        <Key
+            latin:keyLabel="Ù‚" />
+        <Key
+            latin:keyLabel="ف"
+            latin:popupCharacters="ف,ڤ" />
+        <Key
+            latin:keyLabel="غ" />
+        <Key
+            latin:keyLabel="ع" />
+        <Key
+            latin:keyLabel="Ù‡"
+            latin:popupCharacters="ه,هـ" />
+        <Key
+            latin:keyLabel="Ø®" />
+        <Key
+            latin:keyLabel="Ø­" />
+        <Key
+            latin:keyLabel="ج"
+            latin:popupCharacters="ج,چ" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="7.49%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="Ø´" />
+        <Key
+            latin:keyLabel="س" />
+        <Key
+            latin:keyLabel="ÙŠ" />
+        <Key
+            latin:keyLabel="ب"
+            latin:popupCharacters="ب,پ" />
+        <Key
+            latin:keyLabel="Ù„"
+            latin:popupCharacters="ل,لا" />
+        <Key
+            latin:keyLabel="ا"
+            latin:popupCharacters="ا,أ,إ,آ" />
+        <Key
+            latin:keyLabel="ت" />
+        <Key
+            latin:keyLabel="Ù†" />
+        <Key
+            latin:keyLabel="Ù…" />
+        <Key
+            latin:keyLabel="Ùƒ"
+            latin:popupCharacters="Ùƒ,Ú¯" />
+        <Key
+            latin:keyLabel="Ø·" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="8.593%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyLabel="ئ"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="Ø¡" />
+        <Key
+            latin:keyLabel="ؤ" />
+        <Key
+            latin:keyLabel="ر" />
+        <Key
+            latin:keyLabel="Ø°" />
+        <Key
+            latin:keyLabel="Ù‰" />
+        <Key
+            latin:keyLabel="Ø©" />
+        <Key
+            latin:keyLabel="Ùˆ" />
+        <Key
+            latin:keyLabel="ز"
+            latin:popupCharacters="ز,ژ" />
+        <Key
+            latin:keyLabel="ظ" />
+        <Key
+            latin:keyLabel="د" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="11.736%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_iw_rows.xml b/java/res/xml-xlarge/kbd_iw_rows.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3a239dbf66f082cc4da668b8c0289ab01ff5d47
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_iw_rows.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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/kbd_key_styles" />
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="," />
+        <Key
+            latin:keyLabel="." />
+        <Key
+            latin:keyLabel="ק" />
+        <Key
+            latin:keyLabel="ר" />
+        <Key
+            latin:keyLabel="א" />
+        <Key
+            latin:keyLabel="ט" />
+        <Key
+            latin:keyLabel="ו" />
+        <Key
+            latin:keyLabel="ן" />
+        <Key
+            latin:keyLabel="ם" />
+        <Key
+            latin:keyLabel="פ" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.157%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="10.167%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ש" />
+        <Key
+            latin:keyLabel="ד" />
+        <Key
+            latin:keyLabel="×’"
+            latin:popupCharacters="ג,ג׳" />
+        <Key
+            latin:keyLabel="×›" />
+        <Key
+            latin:keyLabel="×¢" />
+        <Key
+            latin:keyLabel="×™"
+            latin:popupCharacters="י,ײַ" />
+        <Key
+            latin:keyLabel="×—"
+            latin:popupCharacters="ח,ח׳" />
+        <Key
+            latin:keyLabel="ל" />
+        <Key
+            latin:keyLabel="ך" />
+        <Key
+            latin:keyLabel="×£" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="8.593%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="×–"
+            latin:popupCharacters="ז,ז׳" />
+        <Key
+            latin:keyLabel="ס" />
+        <Key
+            latin:keyLabel="ב" />
+        <Key
+            latin:keyLabel="×”" />
+        <Key
+            latin:keyLabel="× " />
+        <Key
+            latin:keyLabel="מ" />
+        <Key
+            latin:keyLabel="צ"
+            latin:popupCharacters="צ,צ׳" />
+        <Key
+            latin:keyLabel="ת"
+            latin:popupCharacters="ת,ת׳" />
+        <Key
+            latin:keyLabel="×¥"
+            latin:popupCharacters="ץ,ץ׳" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_key_styles.xml b/java/res/xml-xlarge/kbd_key_styles.xml
index d211e5e6105504be08df83436bb8443ce99438dd..fc06d00fcab7f5e838fec95ee8665adaa73b7f18 100644
--- a/java/res/xml-xlarge/kbd_key_styles.xml
+++ b/java/res/xml-xlarge/kbd_key_styles.xml
@@ -165,4 +165,19 @@
         latin:keyOutputText="@string/keylabel_for_popular_domain"
         latin:keyHintIcon="@drawable/hint_popup_holo"
         latin:popupCharacters="@string/alternates_for_popular_domain" />
+    <switch>
+        <case
+            latin:passwordInput="true"
+        >
+            <key-style
+                latin:styleName="nonPasswordSymbolKeyStyle"
+                latin:enabled="false" />
+        </case>
+        <!-- latin:passwordInput="false" -->
+        <default>
+            <key-style
+                latin:styleName="nonPasswordSymbolKeyStyle"
+                latin:enabled="true" />
+        </default>
+    </switch>
 </merge>
diff --git a/java/res/xml-xlarge/kbd_number.xml b/java/res/xml-xlarge/kbd_number.xml
index 875548ba78031872ccaf2e8fa28b5e175c356485..012b751159d09542677bcf6c120b81dd3d844263 100644
--- a/java/res/xml-xlarge/kbd_number.xml
+++ b/java/res/xml-xlarge/kbd_number.xml
@@ -31,120 +31,199 @@
 >
     <include
         latin:keyboardLayout="@xml/kbd_key_styles" />
-    <!-- This row is intentionally not marked as a top row -->
-    <Row>
-        <Key
-            latin:keyStyle="tabKeyStyle"
-            latin:keyLabelOption="alignLeft"
-            latin:keyEdgeFlags="left" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="-"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="+"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="."
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="1" />
-        <Key
-            latin:keyLabel="2" />
-        <Key
-            latin:keyLabel="3" />
-        <Spacer
-            latin:horizontalGap="9.360%p" />
-        <Key
-            latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="9.804%p"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Spacer
-            latin:horizontalGap="16.406%p" />
-        <Key
-            latin:keyLabel="*"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="/"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="4" />
-        <Key
-            latin:keyLabel="5" />
-        <Key
-            latin:keyLabel="6" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyStyle="returnKeyStyle"
-            latin:keyWidth="14.706%p"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <!-- There is an empty area bellow the "More" key and left of the "(" key.  To ignore
-             the touch event on the area, "(" is intentionally not marked as a left edge key. -->
-        <Spacer
-            latin:horizontalGap="16.406%p" />
-        <Key
-            latin:keyLabel="("
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel=")"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="7" />
-        <Key
-            latin:keyLabel="8" />
-        <Key
-            latin:keyLabel="9" />
-        <!-- There is an empty area bellow the "Enter" key and right of the "9" key.  To ignore
-             the touch event on the area, "9" is intentionally not marked as a right edge key. -->
-    </Row>
-    <!-- This row is intentionally not marked as a bottom row -->
-    <Row>
-        <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
-             the touch event on the area, "space" is intentionally not marked as a left edge key. -->
-        <Spacer
-            latin:horizontalGap="8.362%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
-            latin:keyWidth="24.127%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="*" />
-        <Key
-            latin:keyLabel="0" />
-        <Key
-            latin:keyLabel="#" />
-        <switch>
-            <case
-                latin:voiceKeyEnabled="true"
-            >
-                <Key
-                    latin:keyStyle="micKeyStyle"
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <switch>
+        <case
+            latin:passwordInput="true"
+        >
+            <!-- This row is intentionally not marked as a top row -->
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyStyle="num1KeyStyle" />
+                <Key
+                    latin:keyStyle="num2KeyStyle" />
+                <Key
+                    latin:keyStyle="num3KeyStyle" />
+                <Spacer
+                    latin:horizontalGap="22.272%p" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="9.804%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyStyle="num4KeyStyle" />
+                <Key
+                    latin:keyStyle="num5KeyStyle" />
+                <Key
+                    latin:keyStyle="num6KeyStyle" />
+                <Spacer
+                    latin:horizontalGap="17.371%p" />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="14.706%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyStyle="num7KeyStyle" />
+                <Key
+                    latin:keyStyle="num8KeyStyle" />
+                <Key
+                    latin:keyStyle="num9KeyStyle" />
+                <!-- There is an empty area below the "Enter" key and right of the "9" key. To
+                     ignore the touch event on the area, "9" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+            <!-- This row is intentionally not marked as a bottom row -->
+            <Row>
+                <Spacer
+                    latin:horizontalGap="44.026%p" />
+                <Key
+                    latin:keyStyle="num0KeyStyle" />
+                <!-- There is an empty area below the "Enter" key and right of the "#" key. To
+                     ignore the touch event on the area, "#" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+        </case>
+        <!-- latin:passwordInput="false" -->
+        <default>
+            <!-- This row is intentionally not marked as a top row -->
+            <Row>
+                <Key
+                    latin:keyStyle="tabKeyStyle"
+                    latin:keyLabelOption="alignLeft"
+                    latin:keyEdgeFlags="left" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="-"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="+"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="."
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="1" />
+                <Key
+                    latin:keyLabel="2" />
+                <Key
+                    latin:keyLabel="3" />
+                <Spacer
+                    latin:horizontalGap="9.360%p" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="9.804%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="16.406%p" />
+                <Key
+                    latin:keyLabel="*"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="/"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel=","
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="4" />
+                <Key
+                    latin:keyLabel="5" />
+                <Key
+                    latin:keyLabel="6" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="14.706%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <!-- There is an empty area below the "More" key and left of the "(" key. To
+                     ignore the touch event on the area, "(" is intentionally not marked as a left
+                     edge key. -->
+                <Spacer
+                    latin:horizontalGap="16.406%p" />
+                <Key
+                    latin:keyLabel="("
                     latin:keyWidth="8.042%p" />
-            </case>
-        </switch>
-        <!-- There is an empty area bellow the "Enter" key and right of the "#" key.  To ignore
-             the touch event on the area, "#" is intentionally not marked as a right edge key. -->
-    </Row>
+                <Key
+                    latin:keyLabel=")"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="="
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="7" />
+                <Key
+                    latin:keyLabel="8" />
+                <Key
+                    latin:keyLabel="9" />
+                <!-- There is an empty area below the "Enter" key and right of the "9" key. To
+                     ignore the touch event on the area, "9" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+            <!-- This row is intentionally not marked as a bottom row -->
+            <Row>
+                <!-- There is an empty area below the "More" key and left of the "space" key. To
+                     ignore the touch event on the area, "space" is intentionally not marked as a
+                     left edge key. -->
+                <Spacer
+                    latin:horizontalGap="8.362%p" />
+                <switch>
+                    <case latin:hasSettingsKey="true">
+                        <Key
+                            latin:keyStyle="settingsKeyStyle"
+                            latin:keyWidth="8.042%p" />
+                    </case>
+                    <default>
+                        <Spacer
+                            latin:horizontalGap="8.042%p" />
+                    </default>
+                </switch>
+                <Key
+                    latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
+                    latin:keyWidth="24.127%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="*" />
+                <Key
+                    latin:keyLabel="0" />
+                <Key
+                    latin:keyLabel="#" />
+                <switch>
+                    <case
+                        latin:voiceKeyEnabled="true"
+                    >
+                        <Key
+                            latin:keyStyle="micKeyStyle"
+                            latin:keyWidth="8.042%p" />
+                    </case>
+                </switch>
+                <!-- There is an empty area below the "Enter" key and right of the "#" key. To
+                     ignore the touch event on the area, "#" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+        </default>
+    </switch>
 </Keyboard>
diff --git a/java/res/xml-xlarge/kbd_phone.xml b/java/res/xml-xlarge/kbd_phone.xml
index b9444ad504b582a571ddadf79dd557048abec7a2..9122176a96343a0bae8cc263aa6fee9de6ef9e96 100644
--- a/java/res/xml-xlarge/kbd_phone.xml
+++ b/java/res/xml-xlarge/kbd_phone.xml
@@ -129,9 +129,17 @@
              the touch event on the area, "space" is intentionally not marked as a left edge key. -->
         <Spacer
             latin:horizontalGap="12.340%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle"
-            latin:keyWidth="8.042%p" />
+        <switch>
+            <case latin:hasSettingsKey="true">
+                <Key
+                    latin:keyStyle="settingsKeyStyle"
+                    latin:keyWidth="8.042%p" />
+            </case>
+            <default>
+                <Spacer
+                    latin:horizontalGap="8.042%p" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
             latin:keyWidth="16.084%p" />
diff --git a/java/res/xml-xlarge/kbd_phone_symbols.xml b/java/res/xml-xlarge/kbd_phone_symbols.xml
index 690bcde0c48c4ad522fc9872e8d526d289a5ca59..055c148674631a239d94f34e734213fcd7e3b2bd 100644
--- a/java/res/xml-xlarge/kbd_phone_symbols.xml
+++ b/java/res/xml-xlarge/kbd_phone_symbols.xml
@@ -141,9 +141,17 @@
              the touch event on the area, "space" is intentionally not marked as a left edge key. -->
         <Spacer
             latin:horizontalGap="8.362%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle"
-            latin:keyWidth="8.042%p" />
+        <switch>
+            <case latin:hasSettingsKey="true">
+                <Key
+                    latin:keyStyle="settingsKeyStyle"
+                    latin:keyWidth="8.042%p" />
+            </case>
+            <default>
+                <Spacer
+                    latin:horizontalGap="8.042%p" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
             latin:keyWidth="24.127%p" />
diff --git a/java/res/xml-xlarge/kbd_qwerty_row4.xml b/java/res/xml-xlarge/kbd_qwerty_row4.xml
index 9d0fd81c7232419694a02f871692644c5dc5316b..f36b61fc744e85e81d973cf8b606e60b63fd67bb 100644
--- a/java/res/xml-xlarge/kbd_qwerty_row4.xml
+++ b/java/res/xml-xlarge/kbd_qwerty_row4.xml
@@ -27,29 +27,36 @@
     >
         <Spacer
             latin:horizontalGap="8.362%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle" />
         <switch>
-            <case
-                latin:mode="email"
-            >
-                <Key
-                    latin:keyStyle="comKeyStyle" />
+            <case latin:hasSettingsKey="true">
                 <Key
-                    latin:keyLabel="\@" />
+                    latin:keyStyle="settingsKeyStyle" />
             </case>
-            <!-- TODO: implement logical OR for <case> attribute -->
+            <default>
+                <Spacer
+                    latin:horizontalGap="8.042%p" />
+            </default>
+        </switch>
+        <switch>
             <case
-                latin:mode="url"
+                latin:languageCode="ru"
             >
-                <Key
-                    latin:keyStyle="comKeyStyle"
-                    latin:keyWidth="16.084%p" />
-            </case>
-            <default>
                 <switch>
+                    <!-- TODO: implement logical OR for <case> attribute -->
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyStyle="comKeyStyle" />
+                    </case>
                     <case
-                        latin:imeOptions="actionSearch"
+                        latin:mode="url"
+                    >
+                        <Key
+                            latin:keyStyle="comKeyStyle" />
+                    </case>
+                    <case
+                        latin:imeAction="actionSearch"
                     >
                         <Key
                             latin:keyLabel=":"
@@ -63,12 +70,84 @@
                             latin:keyStyle="smileyKeyStyle" />
                     </default>
                 </switch>
-                <Key
-                    latin:keyLabel="/"
-                    latin:manualTemporaryUpperCaseCode="64"
-                    latin:keyHintIcon="@drawable/key_hint_at_holo"
-                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_at_large_holo"
-                    latin:popupCharacters="\@" />
+                <switch>
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyLabel="\@" />
+                    </case>
+                    <case
+                        latin:mode="url"
+                    >
+                        <Key
+                            latin:keyLabel="-"
+                            latin:manualTemporaryUpperCaseCode="95"
+                            latin:keyHintIcon="@drawable/key_hint_underline_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo"
+                            latin:popupCharacters="_" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyLabel="/"
+                            latin:manualTemporaryUpperCaseCode="64"
+                            latin:keyHintIcon="@drawable/key_hint_at_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_at_large_holo"
+                            latin:popupCharacters="\@" />
+                    </default>
+                </switch>
+            </case>
+            <!-- not languageCode="ru" -->
+            <default>
+                <switch>
+                    <case
+                        latin:mode="url"
+                    >
+                        <Key
+                            latin:keyStyle="comKeyStyle"
+                            latin:keyWidth="16.084%p" />
+                    </case>
+                    <default>
+                        <switch>
+                            <case
+                                latin:mode="email"
+                            >
+                                <Key
+                                    latin:keyStyle="comKeyStyle" />
+                            </case>
+                            <case
+                                latin:imeAction="actionSearch"
+                            >
+                                <Key
+                                    latin:keyLabel=":"
+                                    latin:manualTemporaryUpperCaseCode="43"
+                                    latin:keyHintIcon="@drawable/key_hint_plus_holo"
+                                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_plus_large_holo"
+                                    latin:popupCharacters="+" />
+                            </case>
+                            <default>
+                                <Key
+                                    latin:keyStyle="smileyKeyStyle" />
+                            </default>
+                        </switch>
+                        <switch>
+                            <case
+                                latin:mode="email"
+                            >
+                                <Key
+                                    latin:keyLabel="\@" />
+                            </case>
+                            <default>
+                                <Key
+                                    latin:keyLabel="/"
+                                    latin:manualTemporaryUpperCaseCode="64"
+                                    latin:keyHintIcon="@drawable/key_hint_at_holo"
+                                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_at_large_holo"
+                                    latin:popupCharacters="\@" />
+                            </default>
+                        </switch>
+                    </default>
+                </switch>
             </default>
         </switch>
         <Key
@@ -76,44 +155,95 @@
             latin:keyWidth="37.454%p" />
         <switch>
             <case
-                latin:mode="email"
-            >
-                <Key
-                    latin:keyLabel="-" />
-            </case>
-            <case
-                latin:mode="url"
-            >
-                <Key
-                    latin:keyLabel="/"
-                    latin:manualTemporaryUpperCaseCode="58"
-                    latin:keyHintIcon="@drawable/key_hint_colon_holo"
-                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo"
-                    latin:popupCharacters=":" />
-            </case>
-            <default>
-                <Key
-                    latin:keyLabel="\'"
-                    latin:manualTemporaryUpperCaseCode="34"
-                    latin:keyHintIcon="@drawable/key_hint_quote_holo"
-                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_quote_large_holo"
-                    latin:popupCharacters="&quot;" />
-            </default>
-        </switch>
-        <switch>
-            <case
-                latin:mode="email"
+                latin:languageCode="ru"
             >
-                <Key
-                    latin:keyLabel="_" />
+                <switch>
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyLabel="-" />
+                    </case>
+                    <case
+                        latin:mode="url"
+                    >
+                        <Key
+                            latin:keyLabel="/"
+                            latin:manualTemporaryUpperCaseCode="58"
+                            latin:keyHintIcon="@drawable/key_hint_colon_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo"
+                            latin:popupCharacters=":" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyLabel="\?"
+                            latin:manualTemporaryUpperCaseCode="95"
+                            latin:keyHintIcon="@drawable/key_hint_underline_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo"
+                            latin:popupCharacters="_" />
+                    </default>
+                </switch>
+                <switch>
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyLabel="_" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyLabel="!"
+                            latin:manualTemporaryUpperCaseCode="39"
+                            latin:keyHintIcon="@drawable/key_hint_quote_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_quote_large_holo"
+                            latin:popupCharacters="\'" />
+                    </default>
+                </switch>
             </case>
+            <!-- not languageCode="ru" -->
             <default>
-                <Key
-                    latin:keyLabel="-"
-                    latin:manualTemporaryUpperCaseCode="95"
-                    latin:keyHintIcon="@drawable/key_hint_underline_holo"
-                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo"
-                    latin:popupCharacters="_" />
+                <switch>
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyLabel="-" />
+                    </case>
+                    <case
+                        latin:mode="url"
+                    >
+                        <Key
+                            latin:keyLabel="/"
+                            latin:manualTemporaryUpperCaseCode="58"
+                            latin:keyHintIcon="@drawable/key_hint_colon_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo"
+                            latin:popupCharacters=":" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyLabel="\'"
+                            latin:manualTemporaryUpperCaseCode="34"
+                            latin:keyHintIcon="@drawable/key_hint_quote_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_quote_large_holo"
+                            latin:popupCharacters="&quot;" />
+                    </default>
+                </switch>
+                <switch>
+                    <case
+                        latin:mode="email"
+                    >
+                        <Key
+                            latin:keyLabel="_" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyLabel="-"
+                            latin:manualTemporaryUpperCaseCode="95"
+                            latin:keyHintIcon="@drawable/key_hint_underline_holo"
+                            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo"
+                            latin:popupCharacters="_" />
+                    </default>
+                </switch>
             </default>
         </switch>
         <switch>
diff --git a/java/res/xml-xlarge/kbd_ru_rows.xml b/java/res/xml-xlarge/kbd_ru_rows.xml
index 008988a84f6586469f6314ac97b93f197ffcd220..c5cd043712e0763b12997c44ced00cfb587ef683 100644
--- a/java/res/xml-xlarge/kbd_ru_rows.xml
+++ b/java/res/xml-xlarge/kbd_ru_rows.xml
@@ -105,11 +105,11 @@
             latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        latin:keyWidth="8.042%p"
+        latin:keyWidth="7.520%p"
     >
         <Key
             latin:keyStyle="shiftKeyStyle"
-            latin:keyWidth="15.192%p"
+            latin:keyWidth="12.400%p"
             latin:keyEdgeFlags="left" />
         <Key
             latin:keyLabel="я" />
@@ -130,9 +130,15 @@
             latin:keyLabel="б" />
         <Key
             latin:keyLabel="ÑŽ" />
+        <Key
+            latin:keyLabel="."
+            latin:manualTemporaryUpperCaseCode="44"
+            latin:keyHintIcon="@drawable/key_hint_comma_holo"
+            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_comma_large_holo"
+            latin:popupCharacters="," />
         <Key
             latin:keyStyle="shiftKeyStyle"
-            latin:keyWidth="12.530%p"
+            latin:keyWidth="12.400%p"
             latin:keyEdgeFlags="right" />
     </Row>
     <include
diff --git a/java/res/xml-xlarge/kbd_symbols.xml b/java/res/xml-xlarge/kbd_symbols.xml
index e56cc92d272b9170096762a98456eff22860167f..1061178e092d61b2e7583a4ad51b0b890b308e2f 100644
--- a/java/res/xml-xlarge/kbd_symbols.xml
+++ b/java/res/xml-xlarge/kbd_symbols.xml
@@ -30,6 +30,8 @@
 >
     <include
         latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_currency_key_styles" />
     <!-- This row is intentionally not marked as a top row -->
     <Row
         latin:keyWidth="8.272%p"
@@ -82,8 +84,7 @@
         <Key
             latin:keyLabel="#" />
         <Key
-            latin:keyLabel="$"
-            latin:popupCharacters="¢,£,€,¥,₣,₤,₱" />
+            latin:keyStyle="currencyKeyStyle" />
         <Key
             latin:keyLabel="%"
             latin:popupCharacters="‰" />
@@ -125,20 +126,53 @@
         <Key
             latin:keyLabel="="
             latin:popupCharacters="≠,≈" />
-        <Key
-            latin:keyLabel=":" />
+        <switch>
+            <case
+                latin:languageCode="ru"
+            >
+                <Key
+                    latin:keyLabel=":" />
+            </case>
+            <case
+                latin:mode="url"
+            >
+                <Key
+                    latin:keyLabel="\'" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=":" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel=";" />
-        <Key
-            latin:keyLabel="," />
-        <Key
-            latin:keyLabel="." />
-        <Key
-            latin:keyLabel="!"
-            latin:popupCharacters="¡" />
-        <Key
-            latin:keyLabel="\?"
-            latin:popupCharacters="¿" />
+        <switch>
+            <case
+                latin:languageCode="ru"
+            >
+                <Key
+                    latin:keyLabel="\'" />
+                <Key
+                    latin:keyLabel="&quot;"
+                    latin:popupCharacters="“,”,«,»,˝" />
+                <Key
+                    latin:keyLabel="." />
+                <Key
+                    latin:keyLabel="," />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="," />
+                <Key
+                    latin:keyLabel="." />
+                <Key
+                    latin:keyLabel="!"
+                    latin:popupCharacters="¡" />
+                <Key
+                    latin:keyLabel="\?"
+                    latin:popupCharacters="¿" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="moreKeyStyle"
             latin:keyWidth="12.530%p"
@@ -150,8 +184,16 @@
     >
         <Spacer
             latin:horizontalGap="8.362%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle" />
+        <switch>
+            <case latin:hasSettingsKey="true">
+                <Key
+                    latin:keyStyle="settingsKeyStyle" />
+            </case>
+            <default>
+                <Spacer
+                    latin:horizontalGap="8.042%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="/" />
         <Key
@@ -159,11 +201,23 @@
         <Key
             latin:keyStyle="spaceKeyStyle"
             latin:keyWidth="37.454%p" />
-        <Key
-            latin:keyLabel="&quot;"
-            latin:popupCharacters="“,”,«,»,˝" />
-        <Key
-            latin:keyLabel="_" />
+        <switch>
+            <case
+                latin:languageCode="ru"
+            >
+                <Key
+                    latin:keyLabel="_" />
+                <Key
+                    latin:keyLabel="-" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="&quot;"
+                    latin:popupCharacters="“,”,«,»,˝" />
+                <Key
+                    latin:keyLabel="_" />
+            </default>
+        </switch>
         <switch>
             <case
                 latin:voiceKeyEnabled="true"
diff --git a/java/res/xml-xlarge/kbd_symbols_shift.xml b/java/res/xml-xlarge/kbd_symbols_shift.xml
index f7cf24a3f0d15dfccc89281ad0fde19b7e00f1c2..8359b757144112ad915e35be4b9b258f5c37a3f7 100644
--- a/java/res/xml-xlarge/kbd_symbols_shift.xml
+++ b/java/res/xml-xlarge/kbd_symbols_shift.xml
@@ -46,21 +46,28 @@
         <Key
             latin:keyLabel="|" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="•"
             latin:popupCharacters="♪,♥,♠,♦,♣" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="√" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="Ï€"
             latin:popupCharacters="Π" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="÷" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="×" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="§"
             latin:popupCharacters="¶" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="Δ" />
         <Key
             latin:keyStyle="deleteKeyStyle"
@@ -76,19 +83,25 @@
             latin:keyWidth="11.167%p"
             latin:keyEdgeFlags="left" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="£" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="¢" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="€" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="Â¥" />
         <Key
             latin:keyLabel="^"
             latin:popupCharacters="↑,↓,←,→" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="°" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="±"
             latin:popupCharacters="∞" />
         <Key
@@ -110,20 +123,26 @@
         <Key
             latin:keyLabel="\\" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="©" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="®" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="â„¢" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="â„…" />
         <Key
             latin:keyLabel="[" />
         <Key
             latin:keyLabel="]" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="¡" />
         <Key
+            latin:keyStyle="nonPasswordSymbolKeyStyle"
             latin:keyLabel="¿" />
         <Key
             latin:keyStyle="moreKeyStyle"
@@ -136,8 +155,16 @@
     >
         <Spacer
             latin:horizontalGap="24.446%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle" />
+        <switch>
+            <case latin:hasSettingsKey="true">
+                <Key
+                    latin:keyStyle="settingsKeyStyle" />
+            </case>
+            <default>
+                <Spacer
+                    latin:horizontalGap="8.042%p" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="spaceKeyStyle"
             latin:keyWidth="37.454%p" />
diff --git a/java/res/xml/kbd_currency_key_styles.xml b/java/res/xml/kbd_currency_key_styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b30dd645154836231059dbd78f4357b533955e17
--- /dev/null
+++ b/java/res/xml/kbd_currency_key_styles.xml
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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"
+>
+    <switch>
+        <case
+            latin:passwordInput="true"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="$"
+                latin:popupCharacters="@string/alternates_for_currency_dollar" />
+        </case>
+        <!-- Countries using Euro currency, 23 countries as for January 2011. -->
+        <!-- 1. Andorra (ca_AD, ca_ES) -->
+        <case
+            latin:languageCode="ca"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 2. Austria (de_AT) -->
+<!--        <case-->
+<!--            latin:countryCode="AT"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 3. Belgium (nl_BE, fr_BE, de_BE) -->
+<!--        <case-->
+<!--            latin:countryCode="BE"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 4. Cyprus (el_CY, tr_CY) -->
+        <case
+            latin:countryCode="CY"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 5. Estonia (et_EE) -->
+<!--        <case-->
+<!--            latin:languageCode="et"-->
+<!--            latin:countryCode=""-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 6. Finland (fi_FI, sv_FI) -->
+        <case
+            latin:languageCode="fi"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 7. France (fr_FR) -->
+        <case
+            latin:languageCode="fr"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 8. Germany (de_DE) -->
+        <case
+            latin:languageCode="de"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 9. Greece (el_GR) -->
+        <case
+            latin:languageCode="el"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 10. Ireland (ga_IE, en_IE) -->
+        <case
+            latin:countryCode="IE"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 11. Italy (it_IT) -->
+        <case
+            latin:languageCode="it"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 12. Kosovo -->
+<!--        <case-->
+<!--            latin:countryCode="XK"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 13. Luxembourg (lb_LU, fr_LU, de_LU) -->
+        <case
+            latin:countryCode="LU"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 14. Malta (mt_MT, en_MT) -->
+        <case
+            latin:countryCode="MT"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 15. Monaco (fr_MO) -->
+<!--        <case-->
+<!--            latin:countryCode="MO"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 16. Montenegro (sla_ME) -->
+        <case
+            latin:countryCode="ME"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 17. Netherlands (nl_NL) -->
+        <case
+            latin:languageCode="nl"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 18. Portugal (pt_PT) -->
+        <case
+            latin:languageCode="pt"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 19. San Marino (it_SM) -->
+<!--        <case-->
+<!--            latin:countryCode="SM"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- 20. Slovakia (sk_SK) -->
+        <case
+            latin:languageCode="sk"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 21. Slovenia (sl_SI) -->
+        <case
+            latin:languageCode="sl"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 22. Spain (es_ES, ca_ES) -->
+        <case
+            latin:languageCode="es"
+            latin:countryCode=""
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="€"
+                latin:popupCharacters="@string/alternates_for_currency_euro" />
+        </case>
+        <!-- 23. Vatican City (it_VA) -->
+<!--        <case-->
+<!--            latin:countryCode="VA"-->
+<!--        >-->
+<!--            <key-style-->
+<!--                latin:styleName="currencyKeyStyle"-->
+<!--                latin:keyLabel="€"-->
+<!--                latin:popupCharacters="@string/alternates_for_currency_euro" />-->
+<!--        </case>-->
+        <!-- United Kingdom -->
+        <case
+            latin:countryCode="GB"
+        >
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="£"
+                latin:popupCharacters="@string/alternates_for_currency_pound" />
+        </case>
+        <default>
+            <key-style
+                latin:styleName="currencyKeyStyle"
+                latin:keyLabel="$"
+                latin:popupCharacters="@string/alternates_for_currency_dollar" />
+        </default>
+    </switch>
+</merge>
\ No newline at end of file
diff --git a/java/res/xml/kbd_iw_rows.xml b/java/res/xml/kbd_iw_rows.xml
new file mode 100644
index 0000000000000000000000000000000000000000..db49ad76f865b5a711d7d633ba3ae6a354f61efb
--- /dev/null
+++ b/java/res/xml/kbd_iw_rows.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<!-- This file for Hebrew layout is an alpha version. It allows to enter   -->
+<!-- some right-to-left text, but it has gone through no study whatsoever, -->
+<!-- and needs to be run through UX.                                       -->
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:rowEdgeFlags="top"
+    >
+        <Spacer
+            latin:horizontalGap="5%p" />
+        <Key
+            latin:keyLabel="ק"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ר" />
+        <Key
+            latin:keyLabel="א" />
+        <Key
+            latin:keyLabel="ט" />
+        <Key
+            latin:keyLabel="ו" />
+        <Key
+            latin:keyLabel="ן" />
+        <Key
+            latin:keyLabel="ם" />
+        <Key
+            latin:keyLabel="פ" />
+        <Spacer
+            latin:horizontalGap="1.25%p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="13.75%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel="ש"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ד" />
+        <Key
+            latin:keyLabel="×’" />
+        <Key
+            latin:keyLabel="×›" />
+        <Key
+            latin:keyLabel="×¢" />
+        <Key
+            latin:keyLabel="×™" />
+        <Key
+            latin:keyLabel="×—" />
+        <Key
+            latin:keyLabel="ל" />
+        <Key
+            latin:keyLabel="ך" />
+        <Key
+            latin:keyLabel="×£"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Spacer
+            latin:horizontalGap="5%p" />
+        <Key
+            latin:keyLabel="×–"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ס" />
+        <Key
+            latin:keyLabel="ב" />
+        <Key
+            latin:keyLabel="×”" />
+        <Key
+            latin:keyLabel="× " />
+        <Key
+            latin:keyLabel="מ" />
+        <Key
+            latin:keyLabel="צ" />
+        <Key
+            latin:keyLabel="ת" />
+        <Key
+            latin:keyLabel="×¥"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/kbd_key_styles.xml
index 3b35f35609c24c3123bc90c233aab4560295860c..473510ec4be8e7819ea70383d1e0cf2036bb39fc 100644
--- a/java/res/xml/kbd_key_styles.xml
+++ b/java/res/xml/kbd_key_styles.xml
@@ -182,7 +182,7 @@
     <!-- Return key style -->
     <switch>
         <case
-            latin:imeOptions="actionGo"
+            latin:imeAction="actionGo"
         >
             <key-style
                 latin:styleName="returnKeyStyle"
@@ -191,7 +191,7 @@
                 latin:parentStyle="functionalKeyStyle" />
         </case>
         <case
-            latin:imeOptions="actionNext"
+            latin:imeAction="actionNext"
         >
             <key-style
                 latin:styleName="returnKeyStyle"
@@ -200,7 +200,7 @@
                 latin:parentStyle="functionalKeyStyle" />
         </case>
         <case
-            latin:imeOptions="actionDone"
+            latin:imeAction="actionDone"
         >
             <key-style
                 latin:styleName="returnKeyStyle"
@@ -209,7 +209,7 @@
                 latin:parentStyle="functionalKeyStyle" />
         </case>
         <case
-            latin:imeOptions="actionSend"
+            latin:imeAction="actionSend"
         >
             <key-style
                 latin:styleName="returnKeyStyle"
@@ -218,7 +218,7 @@
                 latin:parentStyle="functionalKeyStyle" />
         </case>
         <case
-            latin:imeOptions="actionSearch"
+            latin:imeAction="actionSearch"
         >
             <switch>
                 <case
diff --git a/java/res/xml/kbd_number.xml b/java/res/xml/kbd_number.xml
index f4fe8401a9423ce4706924ee60ddd9007276b956..7bd679bce529957d6b156c1fbcac71606cf05162 100644
--- a/java/res/xml/kbd_number.xml
+++ b/java/res/xml/kbd_number.xml
@@ -31,6 +31,7 @@
 >
     <include
         latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- TODO: Should add number password layout just like the xlarge layout does. -->
     <switch>
         <case
             latin:colorScheme="white"
diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml
index 5d62deaa4e698565fda33411ee8cef8c657d2dc7..b3b3f4ebd714d1dceeafdc757db92d46ad26ae28 100644
--- a/java/res/xml/kbd_symbols.xml
+++ b/java/res/xml/kbd_symbols.xml
@@ -31,6 +31,8 @@
 >
     <include
         latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_currency_key_styles" />
     <Row
         latin:rowEdgeFlags="top"
     >
@@ -71,8 +73,7 @@
         <Key
             latin:keyLabel="\#" />
         <Key
-            latin:keyLabel="$"
-            latin:popupCharacters="¢,£,€,¥,₣,₤,₱" />
+            latin:keyStyle="currencyKeyStyle" />
         <Key
             latin:keyLabel="%"
             latin:popupCharacters="‰" />
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 3167ae8a81b5ffbd1cc1388597bda092f19eb483..a9883b1183f3a51943c56505a25a62f95b575438 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -20,7 +20,13 @@
 <!-- The attributes in this XML file provide configuration information -->
 <!-- for the Input Method Manager. -->
 
+<!-- Keyboard: en_US, en_GB, cs, da, de, es, es_US, fr, fr_CA, fr_CH, it, nb, nl, sr, sv -->
+<!-- Voice: af, cs, da, de, en, es, fr, it, ja, ko, nl, pl, pt, ru, tr, yue, zh, zu -->
+<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
+<!-- TODO: use <lang>_mic icon instead of a common mic icon. -->
+<!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
+     subtype.-->
 <input-method xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity="com.android.inputmethod.latin.Settings"
-        android:isDefault="@bool/im_is_default"
-/>
+        android:isDefault="@bool/im_is_default">
+</input-method>
diff --git a/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..99262c4345799fcdcf58ba5bcfb7f89ed88b0c6e
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/AbstractCompatWrapper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 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.util.Log;
+
+public abstract class AbstractCompatWrapper {
+    private static final String TAG = AbstractCompatWrapper.class.getSimpleName();
+    protected final Object mObj;
+
+    public AbstractCompatWrapper(Object obj) {
+        if (obj == null) {
+            Log.e(TAG, "Invalid input to AbstructCompatWrapper");
+        }
+        mObj = obj;
+    }
+
+    public Object getOriginalObject() {
+        return mObj;
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8086919c4105cbe6d2b1081d37aad12b954e6ef
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/CompatUtils.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 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.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CompatUtils {
+    private static final String TAG = CompatUtils.class.getSimpleName();
+    private static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+    // TODO: Can these be constants instead of literal String constants?
+    private static final String INPUT_METHOD_SUBTYPE_SETTINGS =
+            "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
+    private static final String INPUT_LANGUAGE_SELECTION =
+            "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION";
+
+    public static Intent getInputLanguageSelectionIntent(String inputMethodId,
+            int flagsForSubtypeSettings) {
+        final String action;
+        Intent intent;
+        if (android.os.Build.VERSION.SDK_INT
+                >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) {
+            // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
+            action = INPUT_METHOD_SUBTYPE_SETTINGS;
+            intent = new Intent(action);
+            if (!TextUtils.isEmpty(inputMethodId)) {
+                intent.putExtra(EXTRA_INPUT_METHOD_ID, inputMethodId);
+            }
+            if (flagsForSubtypeSettings > 0) {
+                intent.setFlags(flagsForSubtypeSettings);
+            }
+        } else {
+            action = INPUT_LANGUAGE_SELECTION;
+            intent = new Intent(action);
+        }
+        return intent;
+    }
+
+    public static Class<?> getClass(String className) {
+        try {
+            return Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+
+    public static Method getMethod(Class<?> targetClass, String name,
+            Class<?>... parameterTypes) {
+        try {
+            return targetClass.getMethod(name, parameterTypes);
+        } catch (SecurityException e) {
+            // ignore
+            return null;
+        } catch (NoSuchMethodException e) {
+            // ignore
+            return null;
+        }
+    }
+
+    public static Field getField(Class<?> targetClass, String name) {
+        try {
+            return targetClass.getField(name);
+        } catch (SecurityException e) {
+            // ignore
+            return null;
+        } catch (NoSuchFieldException e) {
+            // ignore
+            return null;
+        }
+    }
+
+    public static Constructor<?> getConstructor(Class<?> targetClass, Class<?>[] types) {
+        if (targetClass == null || types == null) return null;
+        try {
+            return targetClass.getConstructor(types);
+        } catch (SecurityException e) {
+            // ignore
+            return null;
+        } catch (NoSuchMethodException e) {
+            // ignore
+            return null;
+        }
+    }
+
+    public static Object invoke(
+            Object receiver, Object defaultValue, Method method, Object... args) {
+        if (receiver == null || method == null) return defaultValue;
+        try {
+            return method.invoke(receiver, args);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Exception in invoke: IllegalArgumentException");
+            return defaultValue;
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Exception in invoke: IllegalAccessException");
+            return defaultValue;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Exception in invoke: IllegalTargetException");
+            return defaultValue;
+        }
+    }
+
+    public static Object getFieldValue(Object receiver, Object defaultValue, Field field) {
+        if (receiver == null || field == null) return defaultValue;
+        try {
+            return field.get(receiver);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Exception in getFieldValue: IllegalArgumentException");
+            return defaultValue;
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Exception in getFieldValue: IllegalAccessException");
+            return defaultValue;
+        }
+    }
+
+    public static void setFieldValue(Object receiver, Field field, Object value) {
+        if (receiver == null || field == null) return;
+        try {
+            field.set(receiver, value);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Exception in setFieldValue: IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Exception in setFieldValue: IllegalAccessException");
+        }
+    }
+
+    public static List<InputMethodSubtypeCompatWrapper> copyInputMethodSubtypeListToWrapper(
+            Object listObject) {
+        if (!(listObject instanceof List<?>)) return null;
+        final List<InputMethodSubtypeCompatWrapper> subtypes =
+                new ArrayList<InputMethodSubtypeCompatWrapper>();
+        for (Object o: (List<?>)listObject) {
+            subtypes.add(new InputMethodSubtypeCompatWrapper(o));
+        }
+        return subtypes;
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6f4f7a593c56522070c1dfd105118f26b7bc80f
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 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.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.reflect.Field;
+
+public class EditorInfoCompatUtils {
+    private static final Field FIELD_IME_FLAG_NAVIGATE_NEXT = CompatUtils.getField(
+            EditorInfo.class, "IME_FLAG_NAVIGATE_NEXT");
+    private static final Field FIELD_IME_FLAG_NAVIGATE_PREVIOUS = CompatUtils.getField(
+            EditorInfo.class, "IME_FLAG_NAVIGATE_PREVIOUS");
+    private static final Field FIELD_IME_ACTION_PREVIOUS = CompatUtils.getField(
+            EditorInfo.class, "IME_FLAG_ACTION_PREVIOUS");
+    private static final Integer OBJ_IME_FLAG_NAVIGATE_NEXT = (Integer) CompatUtils
+            .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_NEXT);
+    private static final Integer OBJ_IME_FLAG_NAVIGATE_PREVIOUS = (Integer) CompatUtils
+            .getFieldValue(null, null, FIELD_IME_FLAG_NAVIGATE_PREVIOUS);
+    private static final Integer OBJ_IME_ACTION_PREVIOUS = (Integer) CompatUtils
+            .getFieldValue(null, null, FIELD_IME_ACTION_PREVIOUS);
+
+    public static boolean hasFlagNavigateNext(int imeOptions) {
+        if (OBJ_IME_FLAG_NAVIGATE_NEXT == null)
+            return false;
+        return (imeOptions & OBJ_IME_FLAG_NAVIGATE_NEXT) != 0;
+    }
+
+    public static boolean hasFlagNavigatePrevious(int imeOptions) {
+        if (OBJ_IME_FLAG_NAVIGATE_PREVIOUS == null)
+            return false;
+        return (imeOptions & OBJ_IME_FLAG_NAVIGATE_PREVIOUS) != 0;
+    }
+
+    public static void performEditorActionNext(InputConnection ic) {
+        ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
+    }
+
+    public static void performEditorActionPrevious(InputConnection ic) {
+        if (OBJ_IME_ACTION_PREVIOUS == null)
+            return;
+        ic.performEditorAction(OBJ_IME_ACTION_PREVIOUS);
+    }
+
+    public static String imeOptionsName(int imeOptions) {
+        if (imeOptions == -1)
+            return null;
+        final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION;
+        final String action;
+        switch (actionId) {
+            case EditorInfo.IME_ACTION_UNSPECIFIED:
+                action = "actionUnspecified";
+                break;
+            case EditorInfo.IME_ACTION_NONE:
+                action = "actionNone";
+                break;
+            case EditorInfo.IME_ACTION_GO:
+                action = "actionGo";
+                break;
+            case EditorInfo.IME_ACTION_SEARCH:
+                action = "actionSearch";
+                break;
+            case EditorInfo.IME_ACTION_SEND:
+                action = "actionSend";
+                break;
+            case EditorInfo.IME_ACTION_DONE:
+                action = "actionDone";
+                break;
+            default: {
+                if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) {
+                    action = "actionPrevious";
+                } else {
+                    action = "actionUnknown(" + actionId + ")";
+                }
+                break;
+            }
+        }
+        if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
+            return "flagNoEnterAction|" + action;
+        } else {
+            return action;
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4fe3276516255a3ea9ca6fac4952697ca91f918
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 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.util.Log;
+import android.view.inputmethod.InputConnection;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class InputConnectionCompatUtils {
+    private static final String TAG = InputConnectionCompatUtils.class.getSimpleName();
+    private static final Class<?> CLASS_CorrectionInfo = CompatUtils
+            .getClass("android.view.inputmethod.CorrectionInfo");
+    private static final Class<?>[] INPUT_TYPE_CorrectionInfo = new Class<?>[] { int.class,
+            CharSequence.class, CharSequence.class };
+    private static final Constructor<?> CONSTRUCTOR_CorrectionInfo = CompatUtils
+            .getConstructor(CLASS_CorrectionInfo, INPUT_TYPE_CorrectionInfo);
+    private static final Method METHOD_InputConnection_commitCorrection = CompatUtils
+            .getMethod(InputConnection.class, "commitCorrection", CLASS_CorrectionInfo);
+
+    public static void commitCorrection(InputConnection ic, int offset, CharSequence oldText,
+            CharSequence newText) {
+        if (ic == null || CONSTRUCTOR_CorrectionInfo == null
+                || METHOD_InputConnection_commitCorrection == null) {
+            return;
+        }
+        Object[] args = { offset, oldText, newText };
+        try {
+            Object correctionInfo = CONSTRUCTOR_CorrectionInfo.newInstance(args);
+            CompatUtils.invoke(ic, null, METHOD_InputConnection_commitCorrection,
+                    correctionInfo);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Error in commitCorrection: IllegalArgumentException");
+        } catch (InstantiationException e) {
+            Log.e(TAG, "Error in commitCorrection: InstantiationException");
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Error in commitCorrection: IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Error in commitCorrection: InvocationTargetException");
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e22bbc791fd8fc2c5ddc47b5e7cb5ec660e2e98
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodInfoCompatWrapper.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 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.content.pm.ServiceInfo;
+import android.view.inputmethod.InputMethodInfo;
+
+import java.lang.reflect.Method;
+
+public class InputMethodInfoCompatWrapper {
+    private final InputMethodInfo mImi;
+    private static final Method METHOD_getSubtypeAt = CompatUtils.getMethod(
+            InputMethodInfo.class, "getSubtypeAt", int.class);
+    private static final Method METHOD_getSubtypeCount = CompatUtils.getMethod(
+            InputMethodInfo.class, "getSubtypeCount");
+
+    public InputMethodInfoCompatWrapper(InputMethodInfo imi) {
+        mImi = imi;
+    }
+
+    public InputMethodInfo getInputMethodInfo() {
+        return mImi;
+    }
+
+    public String getId() {
+        return mImi.getId();
+    }
+
+    public String getPackageName() {
+        return mImi.getPackageName();
+    }
+
+    public ServiceInfo getServiceInfo() {
+        return mImi.getServiceInfo();
+    }
+
+    public int getSubtypeCount() {
+        return (Integer) CompatUtils.invoke(mImi, 0, METHOD_getSubtypeCount);
+    }
+
+    public InputMethodSubtypeCompatWrapper getSubtypeAt(int index) {
+        return new InputMethodSubtypeCompatWrapper(CompatUtils.invoke(mImi, null,
+                METHOD_getSubtypeAt, index));
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0d54da3b7e749e8afbff9f5e8bb6cca7d344551
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 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.content.Context;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+// TODO: Override this class with the concrete implementation if we need to take care of the
+// performance.
+public class InputMethodManagerCompatWrapper {
+    private static final String TAG = InputMethodManagerCompatWrapper.class.getSimpleName();
+    private static final Method METHOD_getCurrentInputMethodSubtype =
+            CompatUtils.getMethod(InputMethodManager.class, "getCurrentInputMethodSubtype");
+    private static final Method METHOD_getEnabledInputMethodSubtypeList =
+            CompatUtils.getMethod(InputMethodManager.class, "getEnabledInputMethodSubtypeList",
+                    InputMethodInfo.class, boolean.class);
+    private static final Method METHOD_getShortcutInputMethodsAndSubtypes =
+            CompatUtils.getMethod(InputMethodManager.class, "getShortcutInputMethodsAndSubtypes");
+    private static final Method METHOD_setInputMethodAndSubtype =
+            CompatUtils.getMethod(
+                    InputMethodManager.class, "setInputMethodAndSubtype", IBinder.class,
+                    String.class, InputMethodSubtypeCompatWrapper.CLASS_InputMethodSubtype);
+
+    private static final InputMethodManagerCompatWrapper sInstance =
+            new InputMethodManagerCompatWrapper();
+
+    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper() {
+    }
+
+    public static InputMethodManagerCompatWrapper getInstance(Context context) {
+        if (sInstance.mImm == null) {
+            sInstance.init(context);
+        }
+        return sInstance;
+    }
+
+    private synchronized void init(Context context) {
+        mImm = (InputMethodManager) context.getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+    }
+
+    public InputMethodSubtypeCompatWrapper getCurrentInputMethodSubtype() {
+        return new InputMethodSubtypeCompatWrapper(
+                CompatUtils.invoke(mImm, null, METHOD_getCurrentInputMethodSubtype));
+    }
+
+    public List<InputMethodSubtypeCompatWrapper> getEnabledInputMethodSubtypeList(
+            InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) {
+        Object retval = CompatUtils.invoke(mImm, null, METHOD_getEnabledInputMethodSubtypeList,
+                (imi != null ? imi.getInputMethodInfo() : null), allowsImplicitlySelectedSubtypes);
+        return CompatUtils.copyInputMethodSubtypeListToWrapper((List<?>)retval);
+    }
+
+    public Map<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>>
+            getShortcutInputMethodsAndSubtypes() {
+        Object retval = CompatUtils.invoke(mImm, null, METHOD_getShortcutInputMethodsAndSubtypes);
+        if (!(retval instanceof Map)) return null;
+        Map<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>> shortcutMap =
+                new HashMap<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>>();
+        final Map<?, ?> retvalMap = (Map<?, ?>)retval;
+        for (Object key : retvalMap.keySet()) {
+            if (!(key instanceof InputMethodInfo)) {
+                Log.e(TAG, "Class type error.");
+                return null;
+            }
+            shortcutMap.put(new InputMethodInfoCompatWrapper((InputMethodInfo)key),
+                    CompatUtils.copyInputMethodSubtypeListToWrapper(retvalMap.get(key)));
+        }
+        return shortcutMap;
+    }
+
+    public void setInputMethodAndSubtype(
+            IBinder token, String id, InputMethodSubtypeCompatWrapper subtype) {
+        CompatUtils.invoke(mImm, null, METHOD_setInputMethodAndSubtype,
+                token, id, subtype.getOriginalObject());
+    }
+
+    public boolean switchToLastInputMethod(IBinder token) {
+        return false;
+    }
+
+    public List<InputMethodInfoCompatWrapper> getEnabledInputMethodList() {
+        if (mImm == null) return null;
+        List<InputMethodInfoCompatWrapper> imis = new ArrayList<InputMethodInfoCompatWrapper>();
+        for (InputMethodInfo imi : mImm.getEnabledInputMethodList()) {
+            imis.add(new InputMethodInfoCompatWrapper(imi));
+        }
+        return imis;
+    }
+
+    public void showInputMethodPicker() {
+        if (mImm == null) return;
+        mImm.showInputMethodPicker();
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..88167ae747dbd568ffa3c9ec038e63677794cc76
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodServiceCompatWrapper.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 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 com.android.inputmethod.latin.SubtypeSwitcher;
+
+import android.inputmethodservice.InputMethodService;
+import android.view.View;
+// import android.view.inputmethod.InputMethodSubtype;
+import android.widget.HorizontalScrollView;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class InputMethodServiceCompatWrapper extends InputMethodService {
+    private static final Method METHOD_HorizontalScrollView_setOverScrollMode =
+            CompatUtils.getMethod(HorizontalScrollView.class, "setOverScrollMode", int.class);
+    private static final Field FIELD_View_OVER_SCROLL_NEVER =
+            CompatUtils.getField(View.class, "OVER_SCROLL_NEVER");
+    private static final Integer View_OVER_SCROLL_NEVER =
+            (Integer)CompatUtils.getFieldValue(null, null, FIELD_View_OVER_SCROLL_NEVER);
+    // CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED needs to be false if the API level is 10
+    // or previous. Note that InputMethodSubtype was added in the API level 11.
+    // For the API level 11 or later, LatinIME should override onCurrentInputMethodSubtypeChanged().
+    // For the API level 10 or previous, we handle the "subtype changed" events by ourselves
+    // without having support from framework -- onCurrentInputMethodSubtypeChanged().
+    private static final boolean CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED = false;
+
+    private InputMethodManagerCompatWrapper mImm;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mImm = InputMethodManagerCompatWrapper.getInstance(this);
+    }
+
+    // When the API level is 10 or previous, notifyOnCurrentInputMethodSubtypeChanged should
+    // handle the event the current subtype was changed. LatinIME calls
+    // notifyOnCurrentInputMethodSubtypeChanged every time LatinIME
+    // changes the current subtype.
+    // This call is required to let LatinIME itself know a subtype changed
+    // event when the API level is 10 or previous.
+    @SuppressWarnings("unused")
+    public void notifyOnCurrentInputMethodSubtypeChanged(InputMethodSubtypeCompatWrapper subtype) {
+        // Do nothing when the API level is 11 or later
+        if (CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) return;
+        if (subtype == null) {
+            subtype = mImm.getCurrentInputMethodSubtype();
+        }
+        if (subtype != null) {
+            SubtypeSwitcher.getInstance().updateSubtype(subtype);
+        }
+    }
+
+    protected static void setOverScrollModeNever(HorizontalScrollView scrollView) {
+        if (View_OVER_SCROLL_NEVER != null) {
+            CompatUtils.invoke(scrollView, null, METHOD_HorizontalScrollView_setOverScrollMode,
+                    View_OVER_SCROLL_NEVER);
+        }
+    }
+
+    //////////////////////////////////////
+    // Functions using API v11 or later //
+    //////////////////////////////////////
+    /*@Override
+    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
+        // Do nothing when the API level is 10 or previous
+        if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) return;
+        SubtypeSwitcher.getInstance().updateSubtype(
+                new InputMethodSubtypeCompatWrapper(subtype));
+    }*/
+
+    protected static void setTouchableRegionCompat(InputMethodService.Insets outInsets,
+            int x, int y, int width, int height) {
+        //outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
+        //outInsets.touchableRegion.set(x, y, width, height);
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtype.java b/java/src/com/android/inputmethod/compat/InputMethodSubtype.java
deleted file mode 100644
index 6630dbe75efba8e966b726959e0b553d3f0664dd..0000000000000000000000000000000000000000
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtype.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-// Note: This class has been copied from Honeycomb framework.
-// Original class in Honeycomb framework is {@link android.view.inputmethod.InputMethodSubtype}.
-
-package com.android.inputmethod.compat;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * Information given to an {@link InputMethod} about a client connecting
- * to it.
- */
-/**
- * InputMethodSubtype is a subtype contained in the input method. Subtype can describe
- * locales (e.g. en_US, fr_FR...) and modes (e.g. voice, keyboard...), and is used for
- * IME switch. The subtype allows the system to call the specified subtype of IME directly.
- */
-public final class InputMethodSubtype implements Parcelable {
-    private final int mSubtypeNameResId;
-    private final int mSubtypeIconResId;
-    private final String mSubtypeLocale;
-    private final String mSubtypeMode;
-    private final String mSubtypeExtraValue;
-    private final int mSubtypeHashCode;
-
-    /**
-     * Constructor
-     * @param nameId The name of the subtype
-     * @param iconId The icon of the subtype
-     * @param locale The locale supported by the subtype
-     * @param modeId The mode supported by the subtype
-     * @param extraValue The extra value of the subtype
-     */
-    InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue) {
-        mSubtypeNameResId = nameId;
-        mSubtypeIconResId = iconId;
-        mSubtypeLocale = locale != null ? locale : "";
-        mSubtypeMode = mode != null ? mode : "";
-        mSubtypeExtraValue = extraValue != null ? extraValue : "";
-        mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
-                mSubtypeMode, mSubtypeExtraValue);
-    }
-
-    InputMethodSubtype(Parcel source) {
-        String s;
-        mSubtypeNameResId = source.readInt();
-        mSubtypeIconResId = source.readInt();
-        s = source.readString();
-        mSubtypeLocale = s != null ? s : "";
-        s = source.readString();
-        mSubtypeMode = s != null ? s : "";
-        s = source.readString();
-        mSubtypeExtraValue = s != null ? s : "";
-        mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
-                mSubtypeMode, mSubtypeExtraValue);
-    }
-
-    /**
-     * @return the name of the subtype
-     */
-    public int getNameResId() {
-        return mSubtypeNameResId;
-    }
-
-    /**
-     * @return the icon of the subtype
-     */
-    public int getIconResId() {
-        return mSubtypeIconResId;
-    }
-
-    /**
-     * @return the locale of the subtype
-     */
-    public String getLocale() {
-        return mSubtypeLocale;
-    }
-
-    /**
-     * @return the mode of the subtype
-     */
-    public String getMode() {
-        return mSubtypeMode;
-    }
-
-    /**
-     * @return the extra value of the subtype
-     */
-    public String getExtraValue() {
-        return mSubtypeExtraValue;
-    }
-
-    @Override
-    public int hashCode() {
-        return mSubtypeHashCode;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof InputMethodSubtype) {
-            InputMethodSubtype subtype = (InputMethodSubtype) o;
-            return (subtype.hashCode() == hashCode())
-                && (subtype.getNameResId() == getNameResId())
-                && (subtype.getMode().equals(getMode()))
-                && (subtype.getIconResId() == getIconResId())
-                && (subtype.getLocale().equals(getLocale()))
-                && (subtype.getExtraValue().equals(getExtraValue()));
-        }
-        return false;
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel dest, int parcelableFlags) {
-        dest.writeInt(mSubtypeNameResId);
-        dest.writeInt(mSubtypeIconResId);
-        dest.writeString(mSubtypeLocale);
-        dest.writeString(mSubtypeMode);
-        dest.writeString(mSubtypeExtraValue);
-    }
-
-    public static final Parcelable.Creator<InputMethodSubtype> CREATOR
-            = new Parcelable.Creator<InputMethodSubtype>() {
-        public InputMethodSubtype createFromParcel(Parcel source) {
-            return new InputMethodSubtype(source);
-        }
-
-        public InputMethodSubtype[] newArray(int size) {
-            return new InputMethodSubtype[size];
-        }
-    };
-
-    private static int hashCodeInternal(int nameResId, int iconResId, String locale,
-            String mode, String extraValue) {
-        return Arrays.hashCode(new Object[] {nameResId, iconResId, locale, mode, extraValue});
-    }
-}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..90b7df94924dacc36799506209fd6d2223824455
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 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 com.android.inputmethod.latin.LatinImeLogger;
+
+import android.util.Log;
+
+import java.lang.reflect.Method;
+
+// TODO: Override this class with the concrete implementation if we need to take care of the
+// performance.
+public final class InputMethodSubtypeCompatWrapper extends AbstractCompatWrapper {
+    private static final boolean DBG = LatinImeLogger.sDBG;
+    private static final String TAG = InputMethodSubtypeCompatWrapper.class.getSimpleName();
+    private static final String DEFAULT_LOCALE = "en_US";
+    private static final String DEFAULT_MODE = "keyboard";
+
+    public static final Class<?> CLASS_InputMethodSubtype =
+            CompatUtils.getClass("android.view.inputmethod.InputMethodSubtype");
+    private static final Method METHOD_getNameResId =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getNameResId");
+    private static final Method METHOD_getIconResId =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getIconResId");
+    private static final Method METHOD_getLocale =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getLocale");
+    private static final Method METHOD_getMode =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getMode");
+    private static final Method METHOD_getExtraValue =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValue");
+    private static final Method METHOD_containsExtraValueKey =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "containsExtraValueKey", String.class);
+    private static final Method METHOD_getExtraValueOf =
+            CompatUtils.getMethod(CLASS_InputMethodSubtype, "getExtraValueOf", String.class);
+
+    public InputMethodSubtypeCompatWrapper(Object subtype) {
+        super(CLASS_InputMethodSubtype.isInstance(subtype) ? subtype : null);
+        if (DBG) {
+            Log.d(TAG, "CreateInputMethodSubtypeCompatWrapper");
+        }
+    }
+
+    public int getNameResId() {
+        return (Integer)CompatUtils.invoke(mObj, 0, METHOD_getNameResId);
+    }
+
+    public int getIconResId() {
+        return (Integer)CompatUtils.invoke(mObj, 0, METHOD_getIconResId);
+    }
+
+    public String getLocale() {
+        final String s = (String)CompatUtils.invoke(mObj, null, METHOD_getLocale);
+        if (s == null) return DEFAULT_LOCALE;
+        return s;
+    }
+
+    public String getMode() {
+        String s = (String)CompatUtils.invoke(mObj, null, METHOD_getMode);
+        if (s == null) return DEFAULT_MODE;
+        return s;
+    }
+
+    public String getExtraValue() {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getExtraValue);
+    }
+
+    public boolean containsExtraValueKey(String key) {
+        return (Boolean)CompatUtils.invoke(mObj, false, METHOD_containsExtraValueKey, key);
+    }
+
+    public String getExtraValueOf(String key) {
+        return (String)CompatUtils.invoke(mObj, null, METHOD_getExtraValueOf, key);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof InputMethodSubtypeCompatWrapper) {
+            InputMethodSubtypeCompatWrapper subtype = (InputMethodSubtypeCompatWrapper)o;
+            return mObj.equals(subtype.getOriginalObject());
+        } else {
+            return mObj.equals(o);
+        }
+    }
+
+}
diff --git a/java/src/com/android/inputmethod/compat/InputTypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputTypeCompatUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..d85174188735d7b6c43432fee473aa01c5a94a9c
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/InputTypeCompatUtils.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 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.text.InputType;
+
+import java.lang.reflect.Field;
+
+public class InputTypeCompatUtils {
+    private static final Field FIELD_InputType_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS =
+            CompatUtils.getField(InputType.class, "TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS");
+    private static final Field FIELD_InputType_TYPE_TEXT_VARIATION_WEB_PASSWORD = CompatUtils
+            .getField(InputType.class, "TYPE_TEXT_VARIATION_WEB_PASSWORD");
+    private static final Field FIELD_InputType_TYPE_NUMBER_VARIATION_PASSWORD = CompatUtils
+            .getField(InputType.class, "TYPE_NUMBER_VARIATION_PASSWORD");
+    private static final Integer OBJ_InputType_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS =
+            (Integer) CompatUtils.getFieldValue(null, null,
+                    FIELD_InputType_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS);
+    private static final Integer OBJ_InputType_TYPE_TEXT_VARIATION_WEB_PASSWORD =
+            (Integer) CompatUtils.getFieldValue(null, null,
+                    FIELD_InputType_TYPE_TEXT_VARIATION_WEB_PASSWORD);
+    private static final Integer OBJ_InputType_TYPE_NUMBER_VARIATION_PASSWORD =
+            (Integer) CompatUtils.getFieldValue(null, null,
+                    FIELD_InputType_TYPE_NUMBER_VARIATION_PASSWORD);
+    private static final int WEB_TEXT_PASSWORD_INPUT_TYPE;
+    private static final int NUMBER_PASSWORD_INPUT_TYPE;
+    private static final int TEXT_PASSWORD_INPUT_TYPE =
+            InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+    private static final int TEXT_VISIBLE_PASSWORD_INPUT_TYPE =
+            InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+
+    static {
+        WEB_TEXT_PASSWORD_INPUT_TYPE =
+                OBJ_InputType_TYPE_TEXT_VARIATION_WEB_PASSWORD != null
+                        ? InputType.TYPE_CLASS_TEXT | OBJ_InputType_TYPE_TEXT_VARIATION_WEB_PASSWORD
+                        : 0;
+        NUMBER_PASSWORD_INPUT_TYPE =
+                OBJ_InputType_TYPE_NUMBER_VARIATION_PASSWORD != null
+                        ? InputType.TYPE_CLASS_NUMBER | OBJ_InputType_TYPE_NUMBER_VARIATION_PASSWORD
+                        : 0;
+    }
+
+    private static boolean isWebPasswordInputType(int inputType) {
+        return WEB_TEXT_PASSWORD_INPUT_TYPE != 0
+                && inputType == WEB_TEXT_PASSWORD_INPUT_TYPE;
+    }
+
+    private static boolean isNumberPasswordInputType(int inputType) {
+        return NUMBER_PASSWORD_INPUT_TYPE != 0
+                && inputType == NUMBER_PASSWORD_INPUT_TYPE;
+    }
+
+    private static boolean isTextPasswordInputType(int inputType) {
+        return inputType == TEXT_PASSWORD_INPUT_TYPE;
+    }
+
+    private static boolean isWebEmailAddressVariation(int variation) {
+        return OBJ_InputType_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS != null
+                && variation == OBJ_InputType_TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
+    }
+
+    public static boolean isEmailVariation(int variation) {
+        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+                || isWebEmailAddressVariation(variation);
+    }
+
+    // Please refer to TextView.isPasswordInputType
+    public static boolean isPasswordInputType(int inputType) {
+        final int maskedInputType =
+                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+        return isTextPasswordInputType(maskedInputType) || isWebPasswordInputType(maskedInputType)
+                || isNumberPasswordInputType(maskedInputType);
+    }
+
+    // Please refer to TextView.isVisiblePasswordInputType
+    public static boolean isVisiblePasswordInputType(int inputType) {
+        final int maskedInputType =
+                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+        return maskedInputType == TEXT_VISIBLE_PASSWORD_INPUT_TYPE;
+    }
+}
diff --git a/java/src/com/android/inputmethod/compat/VibratorCompatWrapper.java b/java/src/com/android/inputmethod/compat/VibratorCompatWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e2a2e0b824337ca5531dfc6c404076b7b2b2076
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/VibratorCompatWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.content.Context;
+import android.os.Vibrator;
+
+import java.lang.reflect.Method;
+
+public class VibratorCompatWrapper {
+    private static final Method METHOD_hasVibrator = CompatUtils.getMethod(Vibrator.class,
+            "hasVibrator", int.class);
+
+    private static final VibratorCompatWrapper sInstance = new VibratorCompatWrapper();
+    private Vibrator mVibrator;
+
+    private VibratorCompatWrapper() {
+    }
+
+    public static VibratorCompatWrapper getInstance(Context context) {
+        if (sInstance.mVibrator == null) {
+            sInstance.mVibrator =
+                    (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+        }
+        return sInstance;
+    }
+
+    public boolean hasVibrator() {
+        if (mVibrator == null)
+            return false;
+        return (Boolean) CompatUtils.invoke(mVibrator, true, METHOD_hasVibrator);
+    }
+}
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
similarity index 83%
rename from java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
rename to java/src/com/android/inputmethod/deprecated/VoiceProxy.java
index 267bef21d6c4fc29a7bae1af139ec4e01f83776f..5fba29d906087df445538331659c83b7586fccad 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
@@ -14,8 +14,14 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
-
+package com.android.inputmethod.deprecated;
+
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.deprecated.voice.FieldContext;
+import com.android.inputmethod.deprecated.voice.Hints;
+import com.android.inputmethod.deprecated.voice.SettingsUtil;
+import com.android.inputmethod.deprecated.voice.VoiceInput;
+import com.android.inputmethod.deprecated.voice.VoiceInputLogger;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.latin.EditingUtils;
 import com.android.inputmethod.latin.LatinIME;
@@ -25,8 +31,10 @@ import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SharedPreferencesCompat;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.Utils;
 
 import android.app.AlertDialog;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -53,7 +61,6 @@ import android.view.WindowManager;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
 import java.util.ArrayList;
@@ -61,8 +68,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-public class VoiceIMEConnector implements VoiceInput.UiListener {
-    private static final VoiceIMEConnector sInstance = new VoiceIMEConnector();
+public class VoiceProxy implements VoiceInput.UiListener {
+    private static final VoiceProxy sInstance = new VoiceProxy();
 
     public static final boolean VOICE_INSTALLED = true;
     private static final boolean ENABLE_VOICE_BUTTON = true;
@@ -74,13 +81,9 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     // For example, the user has a Chinese UI but activates voice input.
     private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
             "has_used_voice_input_unsupported_locale";
-    // The private IME option used to indicate that no microphone should be shown for a
-    // given text field. For instance this is specified by the search dialog when the
-    // dialog is already showing a voice search button.
-    private static final String IME_OPTION_NO_MICROPHONE = "nm";
     private static final int RECOGNITIONVIEW_HEIGHT_THRESHOLD_RATIO = 6;
 
-    private static final String TAG = VoiceIMEConnector.class.getSimpleName();
+    private static final String TAG = VoiceProxy.class.getSimpleName();
     private static final boolean DEBUG = LatinImeLogger.sDBG;
 
     private boolean mAfterVoiceInput;
@@ -96,7 +99,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     private boolean mVoiceButtonOnPrimary;
     private boolean mVoiceInputHighlighted;
 
-    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper mImm;
     private LatinIME mService;
     private AlertDialog mVoiceWarningDialog;
     private VoiceInput mVoiceInput;
@@ -108,19 +111,19 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     private final Map<String, List<CharSequence>> mWordToSuggestions =
             new HashMap<String, List<CharSequence>>();
 
-    public static VoiceIMEConnector init(LatinIME context, SharedPreferences prefs, UIHandler h) {
+    public static VoiceProxy init(LatinIME context, SharedPreferences prefs, UIHandler h) {
         sInstance.initInternal(context, prefs, h);
         return sInstance;
     }
 
-    public static VoiceIMEConnector getInstance() {
+    public static VoiceProxy getInstance() {
         return sInstance;
     }
 
     private void initInternal(LatinIME service, SharedPreferences prefs, UIHandler h) {
         mService = service;
         mHandler = h;
-        mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mImm = InputMethodManagerCompatWrapper.getInstance(service);
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         if (VOICE_INSTALLED) {
             mVoiceInput = new VoiceInput(service, this);
@@ -136,7 +139,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
         }
     }
 
-    private VoiceIMEConnector() {
+    private VoiceProxy() {
         // Intentional empty constructor for singleton.
     }
 
@@ -554,10 +557,36 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     }
 
     private void switchToLastInputMethod() {
-        /* @@@
-        IBinder token = mContext.getWindow().getWindow().getAttributes().token;
-        mImm.switchToLastInputMethod(token);
-        */
+        final IBinder token = mService.getWindow().getWindow().getAttributes().token;
+        new AsyncTask<Void, Void, Boolean>() {
+            @Override
+            protected Boolean doInBackground(Void... params) {
+                return mImm.switchToLastInputMethod(token);
+            }
+
+            @Override
+            protected void onPostExecute(Boolean result) {
+                // Calls in this method need to be done in the same thread as the thread which
+                // called switchToLastInputMethod()
+                if (!result) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Couldn't switch back to last IME.");
+                    }
+                    // Because the current IME and subtype failed to switch to any other IME and
+                    // subtype by switchToLastInputMethod, the current IME and subtype should keep
+                    // being LatinIME and voice subtype in the next time. And for re-showing voice
+                    // mode, the state of voice input should be reset and the voice view should be
+                    // hidden.
+                    mVoiceInput.reset();
+                    mService.requestHideSelf(0);
+                } else {
+                    // Notify an event that the current subtype was changed. This event will be
+                    // handled if "onCurrentInputMethodSubtypeChanged" can't be implemented
+                    // when the API level is 10 or previous.
+                    mService.notifyOnCurrentInputMethodSubtypeChanged(null);
+                }
+            }
+        }.execute();
     }
 
     private void reallyStartListening(boolean swipe) {
@@ -611,9 +640,12 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     }
 
     private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
-        return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
-                && !(attribute != null
-                        && IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
+        @SuppressWarnings("deprecation")
+        final boolean noMic = Utils.inPrivateImeOptions(null,
+                LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, attribute)
+                || Utils.inPrivateImeOptions(mService.getPackageName(),
+                        LatinIME.IME_OPTION_NO_MICROPHONE, attribute);
+        return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic
                 && SpeechRecognizer.isRecognitionAvailable(mService);
     }
 
@@ -659,7 +691,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     public void onAttachedToWindow() {
         // After onAttachedToWindow, we can show the voice warning dialog. See startListening()
         // above.
-        mSubtypeSwitcher.setVoiceInput(mVoiceInput);
+        VoiceInputWrapper.getInstance().setVoiceInput(mVoiceInput, mSubtypeSwitcher);
     }
 
     public void onConfigurationChanged(Configuration configuration) {
@@ -710,4 +742,91 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
         List<String> candidates;
         Map<String, List<CharSequence>> alternatives;
     }
+
+    public static class VoiceLoggerWrapper {
+        private static final VoiceLoggerWrapper sInstance = new VoiceLoggerWrapper();
+        private VoiceInputLogger mLogger;
+
+        public static VoiceLoggerWrapper getInstance(Context context) {
+            if (sInstance.mLogger == null) {
+                // Not thread safe, but it's ok.
+                sInstance.mLogger = VoiceInputLogger.getLogger(context);
+            }
+            return sInstance;
+        }
+
+        // private for the singleton
+        private VoiceLoggerWrapper() {
+        }
+
+        public void settingsWarningDialogCancel() {
+            mLogger.settingsWarningDialogCancel();
+        }
+
+        public void settingsWarningDialogOk() {
+            mLogger.settingsWarningDialogOk();
+        }
+
+        public void settingsWarningDialogShown() {
+            mLogger.settingsWarningDialogShown();
+        }
+
+        public void settingsWarningDialogDismissed() {
+            mLogger.settingsWarningDialogDismissed();
+        }
+
+        public void voiceInputSettingEnabled(boolean enabled) {
+            if (enabled) {
+                mLogger.voiceInputSettingEnabled();
+            } else {
+                mLogger.voiceInputSettingDisabled();
+            }
+        }
+    }
+
+    public static class VoiceInputWrapper {
+        private static final VoiceInputWrapper sInstance = new VoiceInputWrapper();
+        private VoiceInput mVoiceInput;
+        public static VoiceInputWrapper getInstance() {
+            return sInstance;
+        }
+        public void setVoiceInput(VoiceInput voiceInput, SubtypeSwitcher switcher) {
+            if (mVoiceInput == null && voiceInput != null) {
+                mVoiceInput = voiceInput;
+            }
+            switcher.setVoiceInputWrapper(this);
+        }
+
+        private VoiceInputWrapper() {
+        }
+
+        public void cancel() {
+            if (mVoiceInput != null) mVoiceInput.cancel();
+        }
+
+        public void reset() {
+            if (mVoiceInput != null) mVoiceInput.reset();
+        }
+    }
+
+    // A list of locales which are supported by default for voice input, unless we get a
+    // different list from Gservices.
+    private static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
+            "en " +
+            "en_US " +
+            "en_GB " +
+            "en_AU " +
+            "en_CA " +
+            "en_IE " +
+            "en_IN " +
+            "en_NZ " +
+            "en_SG " +
+            "en_ZA ";
+
+    public static String getSupportedLocalesString (ContentResolver resolver) {
+        return SettingsUtil.getSettingsString(
+                resolver,
+                SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
+                DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
+    }
 }
diff --git a/java/src/com/android/inputmethod/voice/FieldContext.java b/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java
similarity index 98%
rename from java/src/com/android/inputmethod/voice/FieldContext.java
rename to java/src/com/android/inputmethod/deprecated/voice/FieldContext.java
index dfdfbaa9f7896ec8e2853b7fcd379085b24f229c..0ef73d2d718879319544808866a547116f62bcb9 100644
--- a/java/src/com/android/inputmethod/voice/FieldContext.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/FieldContext.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import android.os.Bundle;
 import android.util.Log;
diff --git a/java/src/com/android/inputmethod/voice/Hints.java b/java/src/com/android/inputmethod/deprecated/voice/Hints.java
similarity index 99%
rename from java/src/com/android/inputmethod/voice/Hints.java
rename to java/src/com/android/inputmethod/deprecated/voice/Hints.java
index d11d3b04268d1e8bb4a78789853a96d92ea979b4..52a4f4e584adbefc7df242d5e1a1bd2efd5873c6 100644
--- a/java/src/com/android/inputmethod/voice/Hints.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/Hints.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SharedPreferencesCompat;
diff --git a/java/src/com/android/inputmethod/voice/RecognitionView.java b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java
similarity index 99%
rename from java/src/com/android/inputmethod/voice/RecognitionView.java
rename to java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java
index 95a79f463970de549ce262934667e5036ae65cc4..52c73ce90f6a38410011b76ffe50502dbe6986df 100644
--- a/java/src/com/android/inputmethod/voice/RecognitionView.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SubtypeSwitcher;
diff --git a/java/src/com/android/inputmethod/voice/SettingsUtil.java b/java/src/com/android/inputmethod/deprecated/voice/SettingsUtil.java
similarity index 98%
rename from java/src/com/android/inputmethod/voice/SettingsUtil.java
rename to java/src/com/android/inputmethod/deprecated/voice/SettingsUtil.java
index 4d746e120e551e225a23595f94e028a58cb15b13..7721fe26867aaa5ea04c689ca0d6cd5954eba944 100644
--- a/java/src/com/android/inputmethod/voice/SettingsUtil.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/SettingsUtil.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import android.content.ContentResolver;
 import android.provider.Settings;
diff --git a/java/src/com/android/inputmethod/voice/SoundIndicator.java b/java/src/com/android/inputmethod/deprecated/voice/SoundIndicator.java
similarity index 98%
rename from java/src/com/android/inputmethod/voice/SoundIndicator.java
rename to java/src/com/android/inputmethod/deprecated/voice/SoundIndicator.java
index 543290b327c79c59e2453c068ed04bed8342f2f0..8cc79de1e2f6ba833581845117b3c8ca76f0f230 100644
--- a/java/src/com/android/inputmethod/voice/SoundIndicator.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/SoundIndicator.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import android.content.Context;
 import android.graphics.Bitmap;
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
similarity index 99%
rename from java/src/com/android/inputmethod/voice/VoiceInput.java
rename to java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
index 2df9e85883da9ef3f67db2767128f7dd5bdc6533..7ee0de9c97dd749c48626cb9c5c003255bae5c78 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/VoiceInput.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import com.android.inputmethod.latin.EditingUtils;
 import com.android.inputmethod.latin.LatinImeLogger;
diff --git a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
similarity index 98%
rename from java/src/com/android/inputmethod/voice/VoiceInputLogger.java
rename to java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
index 1cea681f82a6e577ea47003b694705dee6380d99..3f59ad09971ccf702f15f54b102b6c24b82b14f0 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/VoiceInputLogger.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import com.android.common.speech.LoggingEvents;
 import com.android.common.userhappiness.UserHappinessSignals;
@@ -212,7 +212,7 @@ public class VoiceInputLogger {
         setHasLoggingInfo(true);
         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, suggestionLength);
-        i.putExtra("rlength", replacedPhraseLength);
+        i.putExtra("length", replacedPhraseLength);
         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION);
 
@@ -257,7 +257,7 @@ public class VoiceInputLogger {
         // 2. type subject in subject field
         // 3. speak message in message field
         // 4. press send
-        // @@@ UserHappinessSignals.setHasVoiceLoggingInfo(hasLoggingInfo);
+        //  UserHappinessSignals.setHasVoiceLoggingInfo(hasLoggingInfo);
     }
 
     private boolean hasLoggingInfo(){
diff --git a/java/src/com/android/inputmethod/voice/WaveformImage.java b/java/src/com/android/inputmethod/deprecated/voice/WaveformImage.java
similarity index 98%
rename from java/src/com/android/inputmethod/voice/WaveformImage.java
rename to java/src/com/android/inputmethod/deprecated/voice/WaveformImage.java
index 8bac669fcd19492981ee95e877aa8410ee8691d1..a3025f252325cf4a3af108b0e3ad1cdda13ff83d 100644
--- a/java/src/com/android/inputmethod/voice/WaveformImage.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/WaveformImage.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
diff --git a/java/src/com/android/inputmethod/voice/Whitelist.java b/java/src/com/android/inputmethod/deprecated/voice/Whitelist.java
similarity index 97%
rename from java/src/com/android/inputmethod/voice/Whitelist.java
rename to java/src/com/android/inputmethod/deprecated/voice/Whitelist.java
index f4c24de0c2f90747d6929ac18db0b9b46e9e989d..310689cb2d89e2fcd5a50c4baff0d301480b5b6e 100644
--- a/java/src/com/android/inputmethod/voice/Whitelist.java
+++ b/java/src/com/android/inputmethod/deprecated/voice/Whitelist.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.voice;
+package com.android.inputmethod.deprecated.voice;
 
 import android.os.Bundle;
 
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 23886ad97ca91ade194e88a122c0eb05da62fa95..7396f0518fe9c633268c3530b59285f45954be17 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -95,7 +95,7 @@ public class Key {
     public boolean mPressed;
     /** If this is a sticky key, is it on? */
     public boolean mOn;
-    /** Key is enabled or not. */
+    /** Key is enabled and responds on press */
     public boolean mEnabled = true;
 
     private final static int[] KEY_STATE_NORMAL_ON = {
@@ -226,6 +226,7 @@ public class Key {
             mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false);
             mModifier = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isModifier, false);
             mSticky = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky, false);
+            mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true);
             mEdgeFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyEdgeFlags, 0)
                     | row.mRowEdgeFlags;
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 3979fb53e1fd70e86054d00f549cac2122701539..1a4f901950a135bc584f2397cd1a3111e91197bb 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 public abstract class KeyDetector {
     public static final int NOT_A_KEY = -1;
+    public static final int NOT_A_CODE = -1;
 
     protected Keyboard mKeyboard;
 
@@ -105,10 +106,10 @@ public abstract class KeyDetector {
      *
      * @param x The x-coordinate of a touch point
      * @param y The y-coordinate of a touch point
-     * @param allKeys All nearby key indices are returned in this array
+     * @param allCodes All nearby key code except functional key are returned in this array
      * @return The nearest key index
      */
-    abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys);
+    abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);
 
     /**
      * Compute the most common key width in order to use it as proximity key detection threshold.
@@ -116,14 +117,14 @@ public abstract class KeyDetector {
      * @param keyboard The keyboard to compute the most common key width
      * @return The most common key width in the keyboard
      */
-    public static int getMostCommonKeyWidth(Keyboard keyboard) {
+    public static int getMostCommonKeyWidth(final Keyboard keyboard) {
         if (keyboard == null) return 0;
         final List<Key> keys = keyboard.getKeys();
         if (keys == null || keys.size() == 0) return 0;
         final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
         int maxCount = 0;
         int mostCommonWidth = 0;
-        for (Key key : keys) {
+        for (final Key key : keys) {
             final Integer width = key.mWidth + key.mGap;
             Integer count = histogram.get(width);
             if (count == null)
diff --git a/java/src/com/android/inputmethod/keyboard/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
index 44ec53181e322f5491ef8f7289bae2d73a806eb3..169f2e6c3e4db5dadd15b07c1873758fc19a1096 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
@@ -188,6 +188,7 @@ public class KeyStyles {
             readBoolean(keyAttr, R.styleable.Keyboard_Key_isModifier);
             readBoolean(keyAttr, R.styleable.Keyboard_Key_isSticky);
             readBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable);
+            readBoolean(keyAttr, R.styleable.Keyboard_Key_enabled);
         }
 
         private void readDrawable(TypedArray a, int index) {
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 3a0bf53ab3b485a8749e49aaf99085556de4e7a3..06d44680d62b4f9a009328341e84e94ccee164cb 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -132,6 +132,7 @@ public class Keyboard {
 
     // Variables for pre-computing nearest keys.
 
+    // TODO: Change GRID_WIDTH and GRID_HEIGHT to private.
     public final int GRID_WIDTH;
     public final int GRID_HEIGHT;
     private final int GRID_SIZE;
@@ -143,6 +144,8 @@ public class Keyboard {
     /** Number of key widths from current touch point to search for nearest keys. */
     private static float SEARCH_DISTANCE = 1.2f;
 
+    private final ProximityInfo mProximityInfo;
+
     /**
      * Creates a keyboard from the given xml key layout file.
      * @param context the application or service context
@@ -171,6 +174,11 @@ public class Keyboard {
         mDefaultHeight = mDefaultWidth;
         mId = id;
         loadKeyboard(context, xmlLayoutResId);
+        mProximityInfo = new ProximityInfo(GRID_WIDTH, GRID_HEIGHT);
+    }
+
+    public int getProximityInfo() {
+        return mProximityInfo.getNativeProximityInfo(this);
     }
 
     public List<Key> getKeys() {
@@ -345,7 +353,8 @@ public class Keyboard {
         return mId != null && mId.isNumberKeyboard();
     }
 
-    private void computeNearestNeighbors() {
+    // TODO: Move this function to ProximityInfo and make this private.
+    public void computeNearestNeighbors() {
         // Round-up so we don't have any pixels outside the grid
         mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
         mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT;
@@ -369,6 +378,7 @@ public class Keyboard {
                 mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell;
             }
         }
+        mProximityInfo.setProximityInfo(mGridNeighbors, getMinWidth(), getHeight(), mKeys);
     }
 
     public boolean isInside(Key key, int x, int y) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index 734a55a79acd95aad93ca68d21592cfed1a8d67d..098af214eb7ad03d524be964719321c687ba6357 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -24,16 +24,20 @@ public interface KeyboardActionListener {
      *
      * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid key,
      *            the value will be zero.
+     * @param withSliding true if pressing has occurred because the user slid finger from other key
+     *             to this key without releasing the finger.
      */
-    public void onPress(int primaryCode);
+    public void onPress(int primaryCode, boolean withSliding);
 
     /**
      * Called when the user releases a key. This is sent after the {@link #onCodeInput} is called.
      * For keys that repeat, this is only called once.
      *
      * @param primaryCode the code of the key that was released
+     * @param withSliding true if releasing has occurred because the user slid finger from the key
+     *             to other key without releasing the finger.
      */
-    public void onRelease(int primaryCode);
+    public void onRelease(int primaryCode, boolean withSliding);
 
     /**
      * Send a key code to the listener.
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 8c70d8ffe312871b6901eaf052d48d70da1bb9d9..f68b68f1d298dad1c592439007f3e47d6ca38ee3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.keyboard;
 
+import com.android.inputmethod.compat.EditorInfoCompatUtils;
+import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.latin.R;
 
 import android.view.inputmethod.EditorInfo;
@@ -41,29 +43,35 @@ public class KeyboardId {
     public final int mMode;
     public final int mXmlId;
     public final int mColorScheme;
+    public final boolean mPasswordInput;
     public final boolean mHasSettingsKey;
     public final boolean mVoiceKeyEnabled;
     public final boolean mHasVoiceKey;
-    public final int mImeOptions;
+    public final int mImeAction;
     public final boolean mEnableShiftLock;
     public final String mXmlName;
 
     private final int mHashCode;
 
-    public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int mode,
-            int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled, boolean hasVoiceKey,
-            int imeOptions, boolean enableShiftLock) {
+    public KeyboardId(String xmlName, int xmlId, int colorScheme, Locale locale, int orientation,
+            int mode, EditorInfo attribute, boolean hasSettingsKey, boolean voiceKeyEnabled,
+            boolean hasVoiceKey, boolean enableShiftLock) {
+        final int inputType = (attribute != null) ? attribute.inputType : 0;
+        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
         this.mLocale = locale;
         this.mOrientation = orientation;
         this.mMode = mode;
         this.mXmlId = xmlId;
         this.mColorScheme = colorScheme;
+        this.mPasswordInput = InputTypeCompatUtils.isPasswordInputType(inputType)
+                || InputTypeCompatUtils.isVisiblePasswordInputType(inputType);
         this.mHasSettingsKey = hasSettingsKey;
         this.mVoiceKeyEnabled = voiceKeyEnabled;
         this.mHasVoiceKey = hasVoiceKey;
-        // We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
-        this.mImeOptions = imeOptions
-                & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+        // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and
+        // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}.
+        this.mImeAction = imeOptions & (
+                EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
         this.mEnableShiftLock = enableShiftLock;
         this.mXmlName = xmlName;
 
@@ -73,10 +81,11 @@ public class KeyboardId {
                 mode,
                 xmlId,
                 colorScheme,
+                mPasswordInput,
                 hasSettingsKey,
                 voiceKeyEnabled,
                 hasVoiceKey,
-                imeOptions,
+                mImeAction,
                 enableShiftLock,
         });
     }
@@ -112,10 +121,11 @@ public class KeyboardId {
             && other.mMode == this.mMode
             && other.mXmlId == this.mXmlId
             && other.mColorScheme == this.mColorScheme
+            && other.mPasswordInput == this.mPasswordInput
             && other.mHasSettingsKey == this.mHasSettingsKey
             && other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
             && other.mHasVoiceKey == this.mHasVoiceKey
-            && other.mImeOptions == this.mImeOptions
+            && other.mImeAction == this.mImeAction
             && other.mEnableShiftLock == this.mEnableShiftLock;
     }
 
@@ -126,17 +136,19 @@ public class KeyboardId {
 
     @Override
     public String toString() {
-        return String.format("[%s.xml %s %s %s imeOptions=%s %s%s%s%s%s]",
+        return String.format("[%s.xml %s %s %s imeAction=%s %s%s%s%s%s%s]",
                 mXmlName,
                 mLocale,
                 (mOrientation == 1 ? "port" : "land"),
                 modeName(mMode),
-                imeOptionsName(mImeOptions),
-                colorSchemeName(mColorScheme),
+                EditorInfoCompatUtils.imeOptionsName(mImeAction),
+                (mPasswordInput ? " passwordInput" : ""),
                 (mHasSettingsKey ? " hasSettingsKey" : ""),
                 (mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
                 (mHasVoiceKey ? " hasVoiceKey" : ""),
-                (mEnableShiftLock ? " enableShiftLock" : ""));
+                (mEnableShiftLock ? " enableShiftLock" : ""),
+                colorSchemeName(mColorScheme)
+        );
     }
 
     public static String modeName(int mode) {
@@ -159,26 +171,4 @@ public class KeyboardId {
         }
         return null;
     }
-
-    public static String imeOptionsName(int imeOptions) {
-        if (imeOptions == -1) return null;
-        final int actionNo = imeOptions & EditorInfo.IME_MASK_ACTION;
-        final String action;
-        switch (actionNo) {
-        case EditorInfo.IME_ACTION_UNSPECIFIED: action = "actionUnspecified"; break;
-        case EditorInfo.IME_ACTION_NONE: action = "actionNone"; break;
-        case EditorInfo.IME_ACTION_GO: action = "actionGo"; break;
-        case EditorInfo.IME_ACTION_SEARCH: action = "actionSearch"; break;
-        case EditorInfo.IME_ACTION_SEND: action = "actionSend"; break;
-        case EditorInfo.IME_ACTION_DONE: action = "actionDone"; break;
-        // @@@ case EditorInfo.IME_ACTION_PREVIOUS: action = "actionPrevious"; break;
-        default: action = "actionUnknown(" + actionNo + ")"; break;
-        }
-        if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
-            return "flagNoEnterAction|" + action;
-        } else {
-            return action;
-        }
-    }
 }
-
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
index e8324e5fd156f0c3bcc2afb9f242c8d15a5bea15..62e6f302def7ede23ed09b5b9cf19436b3ab4144 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.keyboard;
 
+import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.latin.R;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -103,7 +104,7 @@ import java.util.List;
  */
 
 public class KeyboardParser {
-    private static final String TAG = "KeyboardParser";
+    private static final String TAG = KeyboardParser.class.getSimpleName();
     private static final boolean DEBUG = false;
 
     // Keyboard XML Tags
@@ -279,8 +280,8 @@ public class KeyboardParser {
             checkEndTag(TAG_KEY, parser);
         } else {
             Key key = new Key(mResources, row, mCurrentX, mCurrentY, parser, mKeyStyles);
-            if (DEBUG) Log.d(TAG, String.format("<%s keyLabel=%s code=%d popupCharacters=%s />",
-                    TAG_KEY, key.mLabel, key.mCode,
+            if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d popupCharacters=%s />",
+                    TAG_KEY, (key.mEnabled ? "" : " disabled"), key.mLabel, key.mCode,
                     Arrays.toString(key.mPopupCharacters)));
             checkEndTag(TAG_KEY, parser);
             keys.add(key);
@@ -419,6 +420,8 @@ public class KeyboardParser {
         try {
             final boolean modeMatched = matchInteger(a,
                     R.styleable.Keyboard_Case_mode, id.mMode);
+            final boolean passwordInputMatched = matchBoolean(a,
+                    R.styleable.Keyboard_Case_passwordInput, id.mPasswordInput);
             final boolean settingsKeyMatched = matchBoolean(a,
                     R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey);
             final boolean voiceEnabledMatched = matchBoolean(a,
@@ -427,24 +430,34 @@ public class KeyboardParser {
                     R.styleable.Keyboard_Case_hasVoiceKey, id.mHasVoiceKey);
             final boolean colorSchemeMatched = matchInteger(viewAttr,
                     R.styleable.KeyboardView_colorScheme, id.mColorScheme);
-            // As noted at KeyboardSwitcher.KeyboardId class, we are interested only in
-            // enum value masked by IME_MASK_ACTION and IME_FLAG_NO_ENTER_ACTION. So matching
+            // As noted at {@link KeyboardId} class, we are interested only in enum value masked by
+            // {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
+            // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
             // this attribute with id.mImeOptions as integer value is enough for our purpose.
-            final boolean imeOptionsMatched = matchInteger(a,
-                    R.styleable.Keyboard_Case_imeOptions, id.mImeOptions);
-            final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched
-                    && voiceKeyMatched && colorSchemeMatched && imeOptionsMatched;
-
-            if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s> %s", TAG_CASE,
+            final boolean imeActionMatched = matchInteger(a,
+                    R.styleable.Keyboard_Case_imeAction, id.mImeAction);
+            final boolean languageCodeMatched = matchString(a,
+                    R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
+            final boolean countryCodeMatched = matchString(a,
+                    R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
+            final boolean selected = modeMatched && passwordInputMatched && settingsKeyMatched
+                    && voiceEnabledMatched && voiceKeyMatched && colorSchemeMatched
+                    && imeActionMatched && languageCodeMatched && countryCodeMatched;
+
+            if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
                     textAttr(KeyboardId.modeName(
                             a.getInt(R.styleable.Keyboard_Case_mode, -1)), "mode"),
                     textAttr(KeyboardId.colorSchemeName(
-                            a.getInt(R.styleable.KeyboardView_colorScheme, -1)), "colorSchemeName"),
+                            viewAttr.getInt(
+                                    R.styleable.KeyboardView_colorScheme, -1)), "colorSchemeName"),
+                    booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
                     booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
                     booleanAttr(a, R.styleable.Keyboard_Case_voiceKeyEnabled, "voiceKeyEnabled"),
                     booleanAttr(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"),
-                    textAttr(KeyboardId.imeOptionsName(
-                            a.getInt(R.styleable.Keyboard_Case_imeOptions, -1)), "imeOptions"),
+                    textAttr(EditorInfoCompatUtils.imeOptionsName(
+                            a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"),
+                    textAttr(a.getString(R.styleable.Keyboard_Case_languageCode), "languageCode"),
+                    textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"),
                     Boolean.toString(selected)));
 
             return selected;
@@ -466,6 +479,12 @@ public class KeyboardParser {
         return !a.hasValue(index) || a.getBoolean(index, false) == value;
     }
 
+    private static boolean matchString(TypedArray a, int index, String value) {
+        // If <case> does not have "index" attribute, that means this <case> is wild-card for the
+        // attribute.
+        return !a.hasValue(index) || a.getString(index).equals(value);
+    }
+
     private boolean parseDefault(XmlResourceParser parser, Row row, List<Key> keys)
             throws XmlPullParserException, IOException {
         if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT));
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 2648ff3d401f5995edadbf31ac51480b2e56f46c..cfa3c446e6b8cf8dca1db07147547fc16038e356 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.keyboard;
 
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
@@ -28,7 +29,7 @@ import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.util.Log;
 import android.view.InflateException;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 
 import java.lang.ref.SoftReference;
 import java.util.HashMap;
@@ -66,8 +67,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
             new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
 
-    private int mMode = KeyboardId.MODE_TEXT; /* default value */
-    private int mImeOptions;
+    private EditorInfo mAttribute;
     private boolean mIsSymbols;
     /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
      * what user actually typed. */
@@ -83,8 +83,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4;
     private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
 
-    // Indicates whether or not we have the settings key
-    private boolean mHasSettingsKey;
+    // Indicates whether or not we have the settings key in option of settings
+    private boolean mSettingsKeyEnabledInSettings;
     private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
     private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
             R.string.settings_key_mode_always_show;
@@ -122,77 +122,47 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         prefs.registerOnSharedPreferenceChangeListener(sInstance);
     }
 
-    private void makeSymbolsKeyboardIds() {
-        final Locale locale = mSubtypeSwitcher.getInputLocale();
-        final Resources res = mInputMethodService.getResources();
-        final int orientation = res.getConfiguration().orientation;
-        final int mode = mMode;
-        final int colorScheme = getColorScheme();
-        final boolean hasSettingsKey = mHasSettingsKey;
-        final boolean voiceKeyEnabled = mVoiceKeyEnabled;
-        final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
-        final int imeOptions = mImeOptions;
-        // Note: This comment is only applied for phone number keyboard layout.
-        // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
-        // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
-        // "@integer/key_shift" key code is used for that purpose in order to properly display
-        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
-        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
-        // respectively here for xlarge device's layout switching.
-        int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols;
-        mSymbolsId = new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
-                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
-        xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
-        mSymbolsShiftedId = new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
-                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
-    }
-
-    private boolean hasVoiceKey(boolean isSymbols) {
-        return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
-    }
-
-    public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
+    public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled,
             boolean voiceButtonOnPrimary) {
         mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
         try {
-            if (mInputView == null) return;
-            final Keyboard oldKeyboard = mInputView.getKeyboard();
-            loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
-            final Keyboard newKeyboard = mInputView.getKeyboard();
-            if (newKeyboard.isAlphaKeyboard()) {
-                final boolean localeChanged = (oldKeyboard == null)
-                        || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
-                mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
-            }
+            loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
         } catch (RuntimeException e) {
-            Log.w(TAG, e);
-            LatinImeLogger.logOnException(mode + "," + imeOptions, e);
+            // Get KeyboardId to record which keyboard has been failed to load.
+            final KeyboardId id = getKeyboardId(attribute, false);
+            Log.w(TAG, "loading keyboard failed: " + id, e);
+            LatinImeLogger.logOnException(id.toString(), e);
         }
     }
 
-    private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
+    private void loadKeyboardInternal(EditorInfo attribute, boolean voiceButtonEnabled,
             boolean voiceButtonOnPrimary, boolean isSymbols) {
         if (mInputView == null) return;
 
-        mMode = mode;
-        mImeOptions = imeOptions;
+        mAttribute = attribute;
         mVoiceKeyEnabled = voiceButtonEnabled;
         mVoiceButtonOnPrimary = voiceButtonOnPrimary;
         mIsSymbols = isSymbols;
         // Update the settings key state because number of enabled IMEs could have been changed
-        mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
-        final KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
+        mSettingsKeyEnabledInSettings = getSettingsKeyMode(mPrefs, mInputMethodService);
+        final KeyboardId id = getKeyboardId(attribute, isSymbols);
 
         final Keyboard oldKeyboard = mInputView.getKeyboard();
         if (oldKeyboard != null && oldKeyboard.mId.equals(id))
             return;
 
-        makeSymbolsKeyboardIds();
+        makeSymbolsKeyboardIds(id.mMode, attribute);
         mCurrentId = id;
         mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
-        mInputView.setKeyboard(getKeyboard(id));
+        setKeyboard(getKeyboard(id));
+    }
+
+    private void setKeyboard(final Keyboard newKeyboard) {
+        final Keyboard oldKeyboard = mInputView.getKeyboard();
+        mInputView.setKeyboard(newKeyboard);
+        final boolean localeChanged = (oldKeyboard == null)
+                || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
+        mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
     }
 
     private LatinKeyboard getKeyboard(KeyboardId id) {
@@ -224,11 +194,22 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         // displayed on its spacebar, it might have had arbitrary text fade factor. In such case,
         // we should reset the text fade factor. It is also applicable to shortcut key.
         keyboard.setSpacebarTextFadeFactor(0.0f, null);
-        keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutAvailable(), null);
+        keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady(), null);
         return keyboard;
     }
 
-    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
+    private boolean hasVoiceKey(boolean isSymbols) {
+        return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
+    }
+
+    private boolean hasSettingsKey(EditorInfo attribute) {
+        return mSettingsKeyEnabledInSettings
+            && !Utils.inPrivateImeOptions(mInputMethodService.getPackageName(),
+                    LatinIME.IME_OPTION_NO_SETTINGS_KEY, attribute);
+    }
+
+    private KeyboardId getKeyboardId(EditorInfo attribute, boolean isSymbols) {
+        final int mode = Utils.getKeyboardMode(attribute);
         final boolean hasVoiceKey = hasVoiceKey(isSymbols);
         final int charColorId = getColorScheme();
         final int xmlId;
@@ -256,16 +237,40 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
                 enableShiftLock = true;
             }
         }
+        final boolean hasSettingsKey = hasSettingsKey(attribute);
         final Resources res = mInputMethodService.getResources();
         final int orientation = res.getConfiguration().orientation;
         final Locale locale = mSubtypeSwitcher.getInputLocale();
         return new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, charColorId,
-                mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
+                res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation, mode,
+                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock);
+    }
+
+    private void makeSymbolsKeyboardIds(final int mode, EditorInfo attribute) {
+        final Locale locale = mSubtypeSwitcher.getInputLocale();
+        final Resources res = mInputMethodService.getResources();
+        final int orientation = res.getConfiguration().orientation;
+        final int colorScheme = getColorScheme();
+        final boolean hasVoiceKey = mVoiceKeyEnabled && !mVoiceButtonOnPrimary;
+        final boolean hasSettingsKey = hasSettingsKey(attribute);
+        // Note: This comment is only applied for phone number keyboard layout.
+        // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
+        // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
+        // "@integer/key_shift" key code is used for that purpose in order to properly display
+        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
+        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
+        // respectively here for xlarge device's layout switching.
+        int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols;
+        final String xmlName = res.getResourceEntryName(xmlId);
+        mSymbolsId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
+        xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
+        mSymbolsShiftedId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
     }
 
     public int getKeyboardMode() {
-        return mMode;
+        return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT;
     }
 
     public boolean isAlphabetMode() {
@@ -278,22 +283,19 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
 
     public boolean isKeyboardAvailable() {
         if (mInputView != null)
-            return mInputView.getLatinKeyboard() != null;
+            return mInputView.getKeyboard() != null;
         return false;
     }
 
-    private LatinKeyboard getLatinKeyboard() {
-        if (mInputView != null)
-            return mInputView.getLatinKeyboard();
+    public LatinKeyboard getLatinKeyboard() {
+        if (mInputView != null) {
+            final Keyboard keyboard = mInputView.getKeyboard();
+            if (keyboard instanceof LatinKeyboard)
+                return (LatinKeyboard)keyboard;
+        }
         return null;
     }
 
-    public void setPreferredLetters(int[] frequencies) {
-        LatinKeyboard latinKeyboard = getLatinKeyboard();
-        if (latinKeyboard != null)
-            latinKeyboard.setPreferredLetters(frequencies);
-    }
-
     public void keyReleased() {
         LatinKeyboard latinKeyboard = getLatinKeyboard();
         if (latinKeyboard != null)
@@ -342,7 +344,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             // state when shift key is pressed to go to normal mode.
             // On the other hand, on distinct multi touch panel device, turning off the shift locked
             // state with shift key pressing is handled by onReleaseShift().
-            if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
+            if ((!hasDistinctMultitouch() || isAccessibilityEnabled())
+                    && !shifted && latinKeyboard.isShiftLocked()) {
                 latinKeyboard.setShiftLocked(false);
             }
             if (latinKeyboard.setShifted(shifted)) {
@@ -437,14 +440,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         updateShiftState();
     }
 
-    public void onPressShift() {
+    public void onPressShift(boolean withSliding) {
         if (!isKeyboardAvailable())
             return;
+        // If accessibility is enabled, disable momentary shift lock.
+        if (isAccessibilityEnabled())
+            return;
         ShiftKeyState shiftKeyState = mShiftKeyState;
         if (DEBUG_STATE)
             Log.d(TAG, "onPressShift:"
                     + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
-                    + " shiftKeyState=" + shiftKeyState);
+                    + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding);
         if (isAlphabetMode()) {
             if (isShiftLocked()) {
                 // Shift key is pressed while caps lock state, we will treat this state as shifted
@@ -472,25 +478,30 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         }
     }
 
-    public void onReleaseShift() {
+    public void onReleaseShift(boolean withSliding) {
         if (!isKeyboardAvailable())
             return;
+        // If accessibility is enabled, disable momentary shift lock.
+        if (isAccessibilityEnabled())
+            return;
         ShiftKeyState shiftKeyState = mShiftKeyState;
         if (DEBUG_STATE)
             Log.d(TAG, "onReleaseShift:"
                     + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
-                    + " shiftKeyState=" + shiftKeyState);
+                    + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding);
         if (isAlphabetMode()) {
             if (shiftKeyState.isMomentary()) {
                 // After chording input while normal state.
                 toggleShift();
-            } else if (isShiftLocked() && !shiftKeyState.isIgnoring()) {
+            } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) {
                 // Shift has been pressed without chording while caps lock state.
                 toggleCapsLock();
-            } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
+            } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()
+                    && !withSliding) {
                 // Shift has been pressed without chording while shifted state.
                 toggleShift();
-            } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing()) {
+            } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing()
+                    && !withSliding) {
                 // Shift has been pressed without chording while manual temporary upper case
                 // transited from automatic temporary upper case.
                 toggleShift();
@@ -500,6 +511,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     }
 
     public void onPressSymbol() {
+        // If accessibility is enabled, disable momentary symbol lock.
+        if (isAccessibilityEnabled())
+            return;
         if (DEBUG_STATE)
             Log.d(TAG, "onPressSymbol:"
                     + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
@@ -510,6 +524,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     }
 
     public void onReleaseSymbol() {
+        // If accessibility is enabled, disable momentary symbol lock.
+        if (isAccessibilityEnabled())
+            return;
         if (DEBUG_STATE)
             Log.d(TAG, "onReleaseSymbol:"
                     + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
@@ -522,6 +539,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     }
 
     public void onOtherKeyPressed() {
+        // If accessibility is enabled, disable momentary mode locking.
+        if (isAccessibilityEnabled())
+            return;
         if (DEBUG_STATE)
             Log.d(TAG, "onOtherKeyPressed:"
                     + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
@@ -556,7 +576,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             // indicator, we need to call enableShiftLock() and setShiftLocked(false).
             keyboard.setShifted(false);
         }
-        mInputView.setKeyboard(keyboard);
+        setKeyboard(keyboard);
     }
 
     public boolean isInMomentaryAutoModeSwitchState() {
@@ -572,8 +592,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     }
 
     private void toggleKeyboardMode() {
-        loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
-                !mIsSymbols);
+        loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols);
         if (mIsSymbols) {
             mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
         } else {
@@ -581,6 +600,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         }
     }
 
+    public boolean isAccessibilityEnabled() {
+        return mInputView != null && mInputView.isAccessibilityEnabled();
+    }
+
     public boolean hasDistinctMultitouch() {
         return mInputView != null && mInputView.hasDistinctMultitouch();
     }
@@ -696,7 +719,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             createInputViewInternal(layoutId, false);
             postSetInputView();
         } else if (Settings.PREF_SETTINGS_KEY.equals(key)) {
-            mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService);
+            mSettingsKeyEnabledInSettings = getSettingsKeyMode(sharedPreferences,
+                    mInputMethodService);
             createInputViewInternal(mLayoutId, true);
             postSetInputView();
         }
@@ -728,11 +752,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
                     || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
                             && Utils.hasMultipleEnabledIMEsOrSubtypes(
-                                    ((InputMethodManager) context.getSystemService(
-                                            Context.INPUT_METHOD_SERVICE))))) {
+                                    (InputMethodManagerCompatWrapper.getInstance(context))))) {
                 return true;
             }
+            return false;
         }
-        return false;
+        // If the show settings key option is disabled, we always try showing the settings key.
+        return true;
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d4c5e579bafab1fd5227fb06ebb7bcb9c66abe74..61af15b1d91aad9df1a996d346598f693ecca2be 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -26,6 +26,7 @@ import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Paint.Align;
 import android.graphics.PorterDuff;
@@ -36,6 +37,7 @@ import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
@@ -145,6 +147,9 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
     private final boolean mHasDistinctMultitouch;
     private int mOldPointerCount = 1;
 
+    // Accessibility
+    private boolean mIsAccessibilityEnabled;
+
     protected KeyDetector mKeyDetector = new ProximityKeyDetector();
 
     // Swipe gesture detector
@@ -522,7 +527,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
     }
 
     /**
-     * Return whether the device has distinct multi-touch panel.
+     * Returns whether the device has distinct multi-touch panel.
      * @return true if the device has distinct multi-touch panel.
      */
     @Override
@@ -530,6 +535,28 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
         return mHasDistinctMultitouch;
     }
 
+    /**
+     * Enables or disables accessibility.
+     * @param accessibilityEnabled whether or not to enable accessibility
+     */
+    public void setAccessibilityEnabled(boolean accessibilityEnabled) {
+        mIsAccessibilityEnabled = accessibilityEnabled;
+
+        // Propagate this change to all existing pointer trackers.
+        for (PointerTracker tracker : mPointerTrackers) {
+            tracker.setAccessibilityEnabled(accessibilityEnabled);
+        }
+    }
+
+    /**
+     * Returns whether the device has accessibility enabled.
+     * @return true if the device has accessibility enabled.
+     */
+    @Override
+    public boolean isAccessibilityEnabled() {
+        return mIsAccessibilityEnabled;
+    }
+
     /**
      * Enables or disables the key feedback popup. This is a popup that shows a magnified
      * version of the depressed key. By default the preview is enabled.
@@ -705,8 +732,13 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
                 } else {
                     paint.setColor(mKeyTextColor);
                 }
-                // Set a drop shadow for the text
-                paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
+                if (key.mEnabled) {
+                    // Set a drop shadow for the text
+                    paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
+                } else {
+                    // Make label invisible
+                    paint.setColor(Color.TRANSPARENT);
+                }
                 canvas.drawText(label, positionX, baseline, paint);
                 // Turn off drop shadow
                 paint.setShadowLayer(0, 0, 0, 0);
@@ -756,6 +788,8 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
             canvas.translate(-key.mX - kbdPaddingLeft, -key.mY - kbdPaddingTop);
         }
 
+        // TODO: Move this function to ProximityInfo for getting rid of public declarations for
+        // GRID_WIDTH and GRID_HEIGHT
         if (DEBUG_KEYBOARD_GRID) {
             Paint p = new Paint();
             p.setStyle(Paint.Style.STROKE);
@@ -1022,7 +1056,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
         mKeyboardActionListener.onCodeInput(Keyboard.CODE_CAPSLOCK, null, 0, 0);
     }
 
-    private void onDoubleTapShiftKey(@SuppressWarnings("unused") PointerTracker tracker) {
+    private void onDoubleTapShiftKey(PointerTracker tracker) {
         // When shift key is double tapped, the first tap is correctly processed as usual tap. And
         // the second tap is treated as this double tap event, so that we need not mark tracker
         // calling setAlreadyProcessed() nor remove the tracker from mPointerQueueueue.
@@ -1060,12 +1094,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
                 // Nothing to do.
             }
             @Override
-            public void onPress(int primaryCode) {
-                mKeyboardActionListener.onPress(primaryCode);
+            public void onPress(int primaryCode, boolean withSliding) {
+                mKeyboardActionListener.onPress(primaryCode, withSliding);
             }
             @Override
-            public void onRelease(int primaryCode) {
-                mKeyboardActionListener.onRelease(primaryCode);
+            public void onRelease(int primaryCode, boolean withSliding) {
+                mKeyboardActionListener.onRelease(primaryCode, withSliding);
             }
         });
         // Override default ProximityKeyDetector.
@@ -1204,15 +1238,18 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
         // TODO: cleanup this code into a multi-touch to single-touch event converter class?
         // If the device does not have distinct multi-touch support panel, ignore all multi-touch
         // events except a transition from/to single-touch.
-        if (!mHasDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) {
+        if ((!mHasDistinctMultitouch || mIsAccessibilityEnabled)
+                && pointerCount > 1 && oldPointerCount > 1) {
             return true;
         }
 
         // Track the last few movements to look for spurious swipes.
         mSwipeTracker.addMovement(me);
 
-        // Gesture detector must be enabled only when mini-keyboard is not on the screen.
-        if (mMiniKeyboardView == null
+        // Gesture detector must be enabled only when mini-keyboard is not on the screen and
+        // accessibility is not enabled.
+        // TODO: Reconcile gesture detection and accessibility features.
+        if (mMiniKeyboardView == null && !mIsAccessibilityEnabled
                 && mGestureDetector != null && mGestureDetector.onTouchEvent(me)) {
             dismissKeyPreview();
             mHandler.cancelKeyTimers();
@@ -1257,7 +1294,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
         // TODO: cleanup this code into a multi-touch to single-touch event converter class?
         // Translate mutli-touch event to single-touch events on the device that has no distinct
         // multi-touch panel.
-        if (!mHasDistinctMultitouch) {
+        if (!mHasDistinctMultitouch || mIsAccessibilityEnabled) {
             // Use only main (id=0) pointer tracker.
             PointerTracker tracker = getPointerTracker(0);
             if (pointerCount == 1 && oldPointerCount == 2) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index ffb8d6410e7f817a3b86d84dd84c9c2eb1457045..5820049bb8d0c895fb6d8768e646759a615230ac 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -21,6 +21,7 @@ import com.android.inputmethod.latin.SubtypeSwitcher;
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -31,17 +32,12 @@ import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.util.Log;
 
 import java.util.List;
 import java.util.Locale;
 
 // TODO: We should remove this class
 public class LatinKeyboard extends Keyboard {
-
-    private static final boolean DEBUG_PREFERRED_LETTER = false;
-    private static final String TAG = "LatinKeyboard";
-
     public static final int OPACITY_FULLY_OPAQUE = 255;
     private static final int SPACE_LED_LENGTH_PERCENT = 80;
 
@@ -69,15 +65,7 @@ public class LatinKeyboard extends Keyboard {
     private final Drawable mEnabledShortcutIcon;
     private final Drawable mDisabledShortcutIcon;
 
-    private int[] mPrefLetterFrequencies;
-    private int mPrefLetter;
-    private int mPrefLetterX;
-    private int mPrefLetterY;
-    private int mPrefDistance;
-
     private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
-    private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
-    private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
     // Minimum width of space key preview (proportional to keyboard width)
     private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
     // Height in space key the language name will be drawn. (proportional to space key height)
@@ -167,6 +155,8 @@ public class LatinKeyboard extends Keyboard {
     }
 
     private void updateSpacebarForLocale(boolean isAutoCorrection) {
+        if (mSpaceKey == null)
+            return;
         final Resources res = mContext.getResources();
         // If application locales are explicitly selected.
         if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
@@ -265,7 +255,7 @@ public class LatinKeyboard extends Keyboard {
             final boolean allowVariableTextSize = true;
             final String language = layoutSpacebar(paint, subtypeSwitcher.getInputLocale(),
                     mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
-                    getTextSizeFromTheme(textStyle, defaultTextSize),
+                    getTextSizeFromTheme(mContext.getTheme(), textStyle, defaultTextSize),
                     allowVariableTextSize);
 
             // Draw language text with shadow
@@ -334,18 +324,9 @@ public class LatinKeyboard extends Keyboard {
         return mSpaceDragLastDiff > 0 ? 1 : -1;
     }
 
-    public void setPreferredLetters(int[] frequencies) {
-        mPrefLetterFrequencies = frequencies;
-        mPrefLetter = 0;
-    }
-
     public void keyReleased() {
         mCurrentlyInSpace = false;
         mSpaceDragLastDiff = 0;
-        mPrefLetter = 0;
-        mPrefLetterX = 0;
-        mPrefLetterY = 0;
-        mPrefDistance = Integer.MAX_VALUE;
         if (mSpaceKey != null) {
             updateLocaleDrag(Integer.MAX_VALUE);
         }
@@ -381,80 +362,6 @@ public class LatinKeyboard extends Keyboard {
                     return isOnSpace;
                 }
             }
-        } else if (mPrefLetterFrequencies != null) {
-            // New coordinate? Reset
-            if (mPrefLetterX != x || mPrefLetterY != y) {
-                mPrefLetter = 0;
-                mPrefDistance = Integer.MAX_VALUE;
-            }
-            // Handle preferred next letter
-            final int[] pref = mPrefLetterFrequencies;
-            if (mPrefLetter > 0) {
-                if (DEBUG_PREFERRED_LETTER) {
-                    if (mPrefLetter == code && !key.isOnKey(x, y)) {
-                        Log.d(TAG, "CORRECTED !!!!!!");
-                    }
-                }
-                return mPrefLetter == code;
-            } else {
-                final boolean isOnKey = key.isOnKey(x, y);
-                int[] nearby = getNearestKeys(x, y);
-                List<Key> nearbyKeys = getKeys();
-                if (isOnKey) {
-                    // If it's a preferred letter
-                    if (inPrefList(code, pref)) {
-                        // Check if its frequency is much lower than a nearby key
-                        mPrefLetter = code;
-                        mPrefLetterX = x;
-                        mPrefLetterY = y;
-                        for (int i = 0; i < nearby.length; i++) {
-                            Key k = nearbyKeys.get(nearby[i]);
-                            if (k != key && inPrefList(k.mCode, pref)) {
-                                final int dist = distanceFrom(k, x, y);
-                                if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_LOW_PROB) &&
-                                        (pref[k.mCode] > pref[mPrefLetter] * 3))  {
-                                    mPrefLetter = k.mCode;
-                                    mPrefDistance = dist;
-                                    if (DEBUG_PREFERRED_LETTER) {
-                                        Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-
-                        return mPrefLetter == code;
-                    }
-                }
-
-                // Get the surrounding keys and intersect with the preferred list
-                // For all in the intersection
-                //   if distance from touch point is within a reasonable distance
-                //       make this the pref letter
-                // If no pref letter
-                //   return inside;
-                // else return thiskey == prefletter;
-
-                for (int i = 0; i < nearby.length; i++) {
-                    Key k = nearbyKeys.get(nearby[i]);
-                    if (inPrefList(k.mCode, pref)) {
-                        final int dist = distanceFrom(k, x, y);
-                        if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_HIGH_PROB)
-                                && dist < mPrefDistance)  {
-                            mPrefLetter = k.mCode;
-                            mPrefLetterX = x;
-                            mPrefLetterY = y;
-                            mPrefDistance = dist;
-                        }
-                    }
-                }
-                // Didn't find any
-                if (mPrefLetter == 0) {
-                    return isOnKey;
-                } else {
-                    return mPrefLetter == code;
-                }
-            }
         }
 
         // Lock into the spacebar
@@ -463,19 +370,6 @@ public class LatinKeyboard extends Keyboard {
         return key.isOnKey(x, y);
     }
 
-    private boolean inPrefList(int code, int[] pref) {
-        if (code < pref.length && code >= 0) return pref[code] > 0;
-        return false;
-    }
-
-    private int distanceFrom(Key k, int x, int y) {
-        if (y > k.mY && y < k.mY + k.mHeight) {
-            return Math.abs(k.mX + k.mWidth / 2 - x);
-        } else {
-            return Integer.MAX_VALUE;
-        }
-    }
-
     @Override
     public int[] getNearestKeys(int x, int y) {
         if (mCurrentlyInSpace) {
@@ -487,8 +381,8 @@ public class LatinKeyboard extends Keyboard {
         }
     }
 
-    private int getTextSizeFromTheme(int style, int defValue) {
-        TypedArray array = mContext.getTheme().obtainStyledAttributes(
+    private static int getTextSizeFromTheme(Theme theme, int style, int defValue) {
+        TypedArray array = theme.obtainStyledAttributes(
                 style, new int[] { android.R.attr.textSize });
         int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
         return textSize;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index e7246dd6e03baaa61c0aa583504f927b922ff844..d6c3723fddc50755269308f7360ea8ca553bf12d 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -16,9 +16,9 @@
 
 package com.android.inputmethod.keyboard;
 
+import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.Utils;
-import com.android.inputmethod.voice.VoiceIMEConnector;
 
 import android.content.Context;
 import android.graphics.Canvas;
@@ -66,7 +66,8 @@ public class LatinKeyboardView extends KeyboardView {
         }
     }
 
-    public void setLatinKeyboard(LatinKeyboard newKeyboard) {
+    @Override
+    public void setKeyboard(Keyboard newKeyboard) {
         final LatinKeyboard oldKeyboard = getLatinKeyboard();
         if (oldKeyboard != null) {
             // Reset old keyboard state before switching to new keyboard.
@@ -80,7 +81,7 @@ public class LatinKeyboardView extends KeyboardView {
         mLastRowY = (newKeyboard.getHeight() * 3) / 4;
     }
 
-    public LatinKeyboard getLatinKeyboard() {
+    private LatinKeyboard getLatinKeyboard() {
         Keyboard keyboard = getKeyboard();
         if (keyboard instanceof LatinKeyboard) {
             return (LatinKeyboard)keyboard;
@@ -144,6 +145,10 @@ public class LatinKeyboardView extends KeyboardView {
         // If device has distinct multi touch panel, there is no need to check sudden jump.
         if (hasDistinctMultitouch())
             return false;
+        // If accessibiliy is enabled, stop looking for sudden jumps because it interferes
+        // with touch exploration of the keyboard.
+        if (isAccessibilityEnabled())
+            return false;
         final int action = me.getAction();
         final int x = (int) me.getX();
         final int y = (int) me.getY();
@@ -259,6 +264,6 @@ public class LatinKeyboardView extends KeyboardView {
     @Override
     protected void onAttachedToWindow() {
         // Token is available from here.
-        VoiceIMEConnector.getInstance().onAttachedToWindow();
+        VoiceProxy.getInstance().onAttachedToWindow();
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
index f04991eb74debd16db3326eec7f4783e1275c3ed..a8750d3786e6aa3f79244c0f722e18e703f869d4 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
@@ -35,24 +35,24 @@ public class MiniKeyboardKeyDetector extends KeyDetector {
     }
 
     @Override
-    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+    public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
         final Key[] keys = getKeys();
         final int touchX = getTouchX(x);
         final int touchY = getTouchY(y);
 
-        int closestKeyIndex = NOT_A_KEY;
-        int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
+        int nearestIndex = NOT_A_KEY;
+        int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
         final int keyCount = keys.length;
         for (int index = 0; index < keyCount; index++) {
             final int dist = keys[index].squaredDistanceToEdge(touchX, touchY);
-            if (dist < closestKeyDist) {
-                closestKeyIndex = index;
-                closestKeyDist = dist;
+            if (dist < nearestDist) {
+                nearestIndex = index;
+                nearestDist = dist;
             }
         }
 
-        if (allKeys != null && closestKeyIndex != NOT_A_KEY)
-            allKeys[0] = keys[closestKeyIndex].mCode;
-        return closestKeyIndex;
+        if (allCodes != null && nearestIndex != NOT_A_KEY)
+            allCodes[0] = keys[nearestIndex].mCode;
+        return nearestIndex;
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 4c90e2c3fc5c022cc4bb9f7bcf8521202c8e5b99..7468578199cc040135dd918a22da284e6cd5738e 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -38,6 +38,7 @@ public class PointerTracker {
         public void invalidateKey(Key key);
         public void showPreview(int keyIndex, PointerTracker tracker);
         public boolean hasDistinctMultitouch();
+        public boolean isAccessibilityEnabled();
     }
 
     public final int mPointerId;
@@ -68,6 +69,9 @@ public class PointerTracker {
 
     private final PointerTrackerKeyState mKeyState;
 
+    // true if accessibility is enabled in the parent keyboard
+    private boolean mIsAccessibilityEnabled;
+
     // true if keyboard layout has been changed.
     private boolean mKeyboardLayoutHasBeenChanged;
 
@@ -89,9 +93,9 @@ public class PointerTracker {
     // Empty {@link KeyboardActionListener}
     private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener() {
         @Override
-        public void onPress(int primaryCode) {}
+        public void onPress(int primaryCode, boolean withSliding) {}
         @Override
-        public void onRelease(int primaryCode) {}
+        public void onRelease(int primaryCode, boolean withSliding) {}
         @Override
         public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {}
         @Override
@@ -112,6 +116,7 @@ public class PointerTracker {
         mKeyDetector = keyDetector;
         mKeyboardSwitcher = KeyboardSwitcher.getInstance();
         mKeyState = new PointerTrackerKeyState(keyDetector);
+        mIsAccessibilityEnabled = proxy.isAccessibilityEnabled();
         mHasDistinctMultitouch = proxy.hasDistinctMultitouch();
         mConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled);
         mDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start);
@@ -128,33 +133,47 @@ public class PointerTracker {
         mListener = listener;
     }
 
+    public void setAccessibilityEnabled(boolean accessibilityEnabled) {
+        mIsAccessibilityEnabled = accessibilityEnabled;
+    }
+
     // Returns true if keyboard has been changed by this callback.
-    private boolean callListenerOnPressAndCheckKeyboardLayoutChange(int primaryCode) {
+    private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) {
         if (DEBUG_LISTENER)
-            Log.d(TAG, "onPress    : " + keyCodePrintable(primaryCode));
-        mListener.onPress(primaryCode);
-        final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
-        mKeyboardLayoutHasBeenChanged = false;
-        return keyboardLayoutHasBeenChanged;
+            Log.d(TAG, "onPress    : " + keyCodePrintable(key.mCode) + " sliding=" + withSliding);
+        if (key.mEnabled) {
+            mListener.onPress(key.mCode, withSliding);
+            final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
+            mKeyboardLayoutHasBeenChanged = false;
+            return keyboardLayoutHasBeenChanged;
+        }
+        return false;
     }
 
-    private void callListenerOnCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
+    // Note that we need primaryCode argument because the keyboard may in shifted state and the
+    // primaryCode is different from {@link Key#mCode}.
+    private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) {
         if (DEBUG_LISTENER)
             Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode)
                     + " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y);
-        mListener.onCodeInput(primaryCode, keyCodes, x, y);
+        if (key.mEnabled)
+            mListener.onCodeInput(primaryCode, keyCodes, x, y);
     }
 
-    private void callListenerOnTextInput(CharSequence text) {
+    private void callListenerOnTextInput(Key key) {
         if (DEBUG_LISTENER)
-            Log.d(TAG, "onTextInput: text=" + text);
-        mListener.onTextInput(text);
+            Log.d(TAG, "onTextInput: text=" + key.mOutputText);
+        if (key.mEnabled)
+            mListener.onTextInput(key.mOutputText);
     }
 
-    private void callListenerOnRelease(int primaryCode) {
+    // Note that we need primaryCode argument because the keyboard may in shifted state and the
+    // primaryCode is different from {@link Key#mCode}.
+    private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) {
         if (DEBUG_LISTENER)
-            Log.d(TAG, "onRelease  : " + keyCodePrintable(primaryCode));
-        mListener.onRelease(primaryCode);
+            Log.d(TAG, "onRelease  : " + keyCodePrintable(primaryCode) + " sliding=" + withSliding);
+        if (key.mEnabled)
+            mListener.onRelease(primaryCode, withSliding);
     }
 
     private void callListenerOnCancelInput() {
@@ -302,9 +321,10 @@ public class PointerTracker {
     private void onDownEventInternal(int x, int y, long eventTime) {
         int keyIndex = mKeyState.onDownKey(x, y, eventTime);
         // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
-        // from modifier key, or 3) this pointer is on mini-keyboard.
+        // from modifier key, 3) this pointer is on mini-keyboard, or 4) accessibility is enabled.
         mIsAllowedSlidingKeyInput = mConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex)
-                || mKeyDetector instanceof MiniKeyboardKeyDetector;
+                || mKeyDetector instanceof MiniKeyboardKeyDetector
+                || mIsAccessibilityEnabled;
         mKeyboardLayoutHasBeenChanged = false;
         mKeyAlreadyProcessed = false;
         mIsRepeatableKey = false;
@@ -313,11 +333,13 @@ public class PointerTracker {
             // This onPress call may have changed keyboard layout. Those cases are detected at
             // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new
             // keyboard layout.
-            if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex].mCode))
+            if (callListenerOnPressAndCheckKeyboardLayoutChange(mKeys[keyIndex], false))
                 keyIndex = mKeyState.onDownKey(x, y, eventTime);
         }
         if (isValidKeyIndex(keyIndex)) {
-            if (mKeys[keyIndex].mRepeatable) {
+            // Accessibility disables key repeat because users may need to pause on a key to hear
+            // its spoken description.
+            if (mKeys[keyIndex].mRepeatable && !mIsAccessibilityEnabled) {
                 repeatKey(keyIndex);
                 mHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this);
                 mIsRepeatableKey = true;
@@ -346,7 +368,7 @@ public class PointerTracker {
                 // This onPress call may have changed keyboard layout. Those cases are detected at
                 // {@link #setKeyboard}. In those cases, we should update keyIndex according to the
                 // new keyboard layout.
-                if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
+                if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true))
                     keyIndex = keyState.onMoveKey(x, y);
                 keyState.onMoveToNewKey(keyIndex, x, y);
                 startLongPressTimer(keyIndex);
@@ -355,13 +377,13 @@ public class PointerTracker {
                 // onRelease() first to notify that the previous key has been released, then call
                 // onPress() to notify that the new key is being pressed.
                 mIsInSlidingKeyInput = true;
-                callListenerOnRelease(oldKey.mCode);
+                callListenerOnRelease(oldKey, oldKey.mCode, true);
                 mHandler.cancelLongPressTimers();
                 if (mIsAllowedSlidingKeyInput) {
                     // This onPress call may have changed keyboard layout. Those cases are detected
                     // at {@link #setKeyboard}. In those cases, we should update keyIndex according
                     // to the new keyboard layout.
-                    if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex).mCode))
+                    if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true))
                         keyIndex = keyState.onMoveKey(x, y);
                     keyState.onMoveToNewKey(keyIndex, x, y);
                     startLongPressTimer(keyIndex);
@@ -390,7 +412,7 @@ public class PointerTracker {
                 // The pointer has been slid out from the previous key, we must call onRelease() to
                 // notify that the previous key has been released.
                 mIsInSlidingKeyInput = true;
-                callListenerOnRelease(oldKey.mCode);
+                callListenerOnRelease(oldKey, oldKey.mCode, true);
                 mHandler.cancelLongPressTimers();
                 if (mIsAllowedSlidingKeyInput) {
                     keyState.onMoveToNewKey(keyIndex, x ,y);
@@ -507,8 +529,9 @@ public class PointerTracker {
         updateKeyGraphics(keyIndex);
         // The modifier key, such as shift key, should not be shown as preview when multi-touch is
         // supported. On the other hand, if multi-touch is not supported, the modifier key should
-        // be shown as preview.
-        if (mHasDistinctMultitouch && isModifier()) {
+        // be shown as preview. If accessibility is turned on, the modifier key should be shown as
+        // preview.
+        if (mHasDistinctMultitouch && isModifier() && !mIsAccessibilityEnabled) {
             mProxy.showPreview(NOT_A_KEY, this);
         } else {
             mProxy.showPreview(keyIndex, this);
@@ -516,6 +539,11 @@ public class PointerTracker {
     }
 
     private void startLongPressTimer(int keyIndex) {
+        // Accessibility disables long press because users are likely to need to pause on a key
+        // for an unspecified duration in order to hear the key's spoken description.
+        if (mIsAccessibilityEnabled) {
+            return;
+        }
         Key key = getKey(keyIndex);
         if (key.mCode == Keyboard.CODE_SHIFT) {
             mHandler.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this);
@@ -539,8 +567,8 @@ public class PointerTracker {
             return;
         }
         if (key.mOutputText != null) {
-            callListenerOnTextInput(key.mOutputText);
-            callListenerOnRelease(key.mCode);
+            callListenerOnTextInput(key);
+            callListenerOnRelease(key, key.mCode, false);
         } else {
             int code = key.mCode;
             final int[] codes = mKeyDetector.newCodeArray();
@@ -561,9 +589,8 @@ public class PointerTracker {
                 codes[1] = codes[0];
                 codes[0] = code;
             }
-            if (key.mEnabled)
-                callListenerOnCodeInput(code, codes, x, y);
-            callListenerOnRelease(code);
+            callListenerOnCodeInput(key, code, codes, x, y);
+            callListenerOnRelease(key, code, false);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..80d6de952da01df864285e37b4a0c18d02348615
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import com.android.inputmethod.latin.Utils;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ProximityInfo {
+    public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
+
+    private final int mGridWidth;
+    private final int mGridHeight;
+    private final int mGridSize;
+
+    ProximityInfo(int gridWidth, int gridHeight) {
+        mGridWidth = gridWidth;
+        mGridHeight = gridHeight;
+        mGridSize = mGridWidth * mGridHeight;
+    }
+
+    private int mNativeProximityInfo;
+    static {
+        Utils.loadNativeLibrary();
+    }
+    private native int setProximityInfoNative(int maxProximityCharsSize, int displayWidth,
+            int displayHeight, int gridWidth, int gridHeight, int[] proximityCharsArray);
+    private native void releaseProximityInfoNative(int nativeProximityInfo);
+
+    public final void setProximityInfo(int[][] gridNeighborKeyIndexes, int keyboardWidth,
+            int keyboardHeight, List<Key> keys) {
+        int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
+        Arrays.fill(proximityCharsArray, KeyDetector.NOT_A_CODE);
+        for (int i = 0; i < mGridSize; ++i) {
+            final int proximityCharsLength = gridNeighborKeyIndexes[i].length;
+            for (int j = 0; j < proximityCharsLength; ++j) {
+                proximityCharsArray[i * MAX_PROXIMITY_CHARS_SIZE + j] =
+                        keys.get(gridNeighborKeyIndexes[i][j]).mCode;
+            }
+        }
+        mNativeProximityInfo = setProximityInfoNative(MAX_PROXIMITY_CHARS_SIZE,
+                keyboardWidth, keyboardHeight, mGridWidth, mGridHeight, proximityCharsArray);
+    }
+
+    // TODO: Get rid of this function's input (keyboard).
+    public int getNativeProximityInfo(Keyboard keyboard) {
+        if (mNativeProximityInfo == 0) {
+            // TODO: Move this function to ProximityInfo and make this private.
+            keyboard.computeNearestNeighbors();
+        }
+        return mNativeProximityInfo;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mNativeProximityInfo != 0) {
+                releaseProximityInfoNative(mNativeProximityInfo);
+                mNativeProximityInfo = 0;
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
index 0920da2cba4442e8f4f5a177df72b1a21ec891c5..c3fd1984b05b297f103561b4b4002ae27a7faee2 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
@@ -16,49 +16,106 @@
 
 package com.android.inputmethod.keyboard;
 
+import android.util.Log;
+
 import java.util.Arrays;
 
 public class ProximityKeyDetector extends KeyDetector {
+    private static final String TAG = ProximityKeyDetector.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
     private static final int MAX_NEARBY_KEYS = 12;
 
     // working area
-    private int[] mDistances = new int[MAX_NEARBY_KEYS];
+    private final int[] mDistances = new int[MAX_NEARBY_KEYS];
+    private final int[] mIndices = new int[MAX_NEARBY_KEYS];
 
     @Override
     protected int getMaxNearbyKeys() {
         return MAX_NEARBY_KEYS;
     }
 
+    private void initializeNearbyKeys() {
+        Arrays.fill(mDistances, Integer.MAX_VALUE);
+        Arrays.fill(mIndices, NOT_A_KEY);
+    }
+
+    /**
+     * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
+     *
+     * @param keyIndex index of the key.
+     * @param distance distance between the key's edge and user touched point.
+     * @return order of the key in the nearby buffer, 0 if it is the nearest key.
+     */
+    private int sortNearbyKeys(int keyIndex, int distance) {
+        final int[] distances = mDistances;
+        final int[] indices = mIndices;
+        for (int insertPos = 0; insertPos < distances.length; insertPos++) {
+            if (distance < distances[insertPos]) {
+                final int nextPos = insertPos + 1;
+                if (nextPos < distances.length) {
+                    System.arraycopy(distances, insertPos, distances, nextPos,
+                            distances.length - nextPos);
+                    System.arraycopy(indices, insertPos, indices, nextPos,
+                            indices.length - nextPos);
+                }
+                distances[insertPos] = distance;
+                indices[insertPos] = keyIndex;
+                return insertPos;
+            }
+        }
+        return distances.length;
+    }
+
+    private void getNearbyKeyCodes(final int[] allCodes) {
+        final Key[] keys = getKeys();
+        final int[] indices = mIndices;
+
+        // allCodes[0] should always have the key code even if it is a non-letter key.
+        if (indices[0] == NOT_A_KEY) {
+            allCodes[0] = NOT_A_CODE;
+            return;
+        }
+
+        int numCodes = 0;
+        for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) {
+            final int index = indices[j];
+            if (index == NOT_A_KEY)
+                break;
+            final int code = keys[index].mCode;
+            // filter out a non-letter key from nearby keys
+            if (code < Keyboard.CODE_SPACE)
+                continue;
+            allCodes[numCodes++] = code;
+        }
+    }
+
     @Override
-    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+    public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
         final Key[] keys = getKeys();
         final int touchX = getTouchX(x);
         final int touchY = getTouchY(y);
 
+        initializeNearbyKeys();
         int primaryIndex = NOT_A_KEY;
-        final int[] distances = mDistances;
-        Arrays.fill(distances, Integer.MAX_VALUE);
         for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
             final Key key = keys[index];
             final boolean isInside = key.isInside(touchX, touchY);
-            if (isInside)
-                primaryIndex = index;
-            final int dist = key.squaredDistanceToEdge(touchX, touchY);
-            if (isInside || (mProximityCorrectOn && dist < mProximityThresholdSquare)) {
-                if (allKeys == null) continue;
-                // Find insertion point
-                for (int j = 0; j < distances.length; j++) {
-                    if (distances[j] > dist) {
-                        final int nextPos = j + 1;
-                        System.arraycopy(distances, j, distances, nextPos,
-                                distances.length - nextPos);
-                        System.arraycopy(allKeys, j, allKeys, nextPos,
-                                allKeys.length - nextPos);
-                        distances[j] = dist;
-                        allKeys[j] = key.mCode;
-                        break;
-                    }
-                }
+            final int distance = key.squaredDistanceToEdge(touchX, touchY);
+            if (isInside || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
+                final int insertedPosition = sortNearbyKeys(index, distance);
+                if (insertedPosition == 0 && isInside)
+                    primaryIndex = index;
+            }
+        }
+
+        if (allCodes != null && allCodes.length > 0) {
+            getNearbyKeyCodes(allCodes);
+            if (DEBUG) {
+                Log.d(TAG, "x=" + x + " y=" + y
+                        + " primary="
+                        + (primaryIndex == NOT_A_KEY ? "none" : keys[primaryIndex].mCode)
+                        + " codes=" + Arrays.toString(allCodes));
             }
         }
 
diff --git a/java/src/com/android/inputmethod/latin/AccessibilityUtils.java b/java/src/com/android/inputmethod/latin/AccessibilityUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd3f9e0ad2fd87775b2d1acd16453a5e8bdcd55e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AccessibilityUtils.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility functions for accessibility support.
+ */
+public class AccessibilityUtils {
+    /** Shared singleton instance. */
+    private static final AccessibilityUtils sInstance = new AccessibilityUtils();
+    private /* final */ LatinIME mService;
+    private /* final */ AccessibilityManager mAccessibilityManager;
+    private /* final */ Map<Integer, CharSequence> mDescriptions;
+
+    /**
+     * Returns a shared instance of AccessibilityUtils.
+     *
+     * @return A shared instance of AccessibilityUtils.
+     */
+    public static AccessibilityUtils getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * Initializes (or re-initializes) the shared instance of AccessibilityUtils
+     * with the specified parent service and preferences.
+     *
+     * @param service The parent input method service.
+     * @param prefs The parent preferences.
+     */
+    public static void init(LatinIME service, SharedPreferences prefs) {
+        sInstance.initialize(service, prefs);
+    }
+
+    private AccessibilityUtils() {
+        // This class is not publicly instantiable.
+    }
+
+    /**
+     * Initializes (or re-initializes) with the specified parent service and
+     * preferences.
+     *
+     * @param service The parent input method service.
+     * @param prefs The parent preferences.
+     */
+    private void initialize(LatinIME service, SharedPreferences prefs) {
+        mService = service;
+        mAccessibilityManager = (AccessibilityManager) service.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+        mDescriptions = null;
+    }
+
+    /**
+     * Returns true if accessibility is enabled.
+     *
+     * @return {@code true} if accessibility is enabled.
+     */
+    public boolean isAccessibilityEnabled() {
+        return mAccessibilityManager.isEnabled();
+    }
+
+    /**
+     * Speaks a key's action after it has been released. Does not speak letter
+     * keys since typed keys are already spoken aloud by TalkBack.
+     * <p>
+     * No-op if accessibility is not enabled.
+     * </p>
+     *
+     * @param primaryCode The primary code of the released key.
+     * @param switcher The input method's {@link KeyboardSwitcher}.
+     */
+    public void onRelease(int primaryCode, KeyboardSwitcher switcher) {
+        if (!isAccessibilityEnabled()) {
+            return;
+        }
+
+        int resId = -1;
+
+        switch (primaryCode) {
+            case Keyboard.CODE_SHIFT: {
+                if (switcher.isShiftedOrShiftLocked()) {
+                    resId = R.string.description_shift_on;
+                } else {
+                    resId = R.string.description_shift_off;
+                }
+                break;
+            }
+
+            case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: {
+                if (switcher.isAlphabetMode()) {
+                    resId = R.string.description_symbols_off;
+                } else {
+                    resId = R.string.description_symbols_on;
+                }
+                break;
+            }
+        }
+
+        if (resId >= 0) {
+            speakDescription(mService.getResources().getText(resId));
+        }
+    }
+
+    /**
+     * Speaks a key's description for accessibility. If a key has an explicit
+     * description defined in keycodes.xml, that will be used. Otherwise, if the
+     * key is a Unicode character, then its character will be used.
+     * <p>
+     * No-op if accessibility is not enabled.
+     * </p>
+     *
+     * @param primaryCode The primary code of the pressed key.
+     * @param switcher The input method's {@link KeyboardSwitcher}.
+     */
+    public void onPress(int primaryCode, KeyboardSwitcher switcher) {
+        if (!isAccessibilityEnabled()) {
+            return;
+        }
+
+        // TODO Use the current keyboard state to read "Switch to symbols"
+        // instead of just "Symbols" (and similar for shift key).
+        CharSequence description = describeKey(primaryCode);
+        if (description == null && Character.isDefined((char) primaryCode)) {
+            description = Character.toString((char) primaryCode);
+        }
+
+        if (description != null) {
+            speakDescription(description);
+        }
+    }
+
+    /**
+     * Returns a text description for a given key code. If the key does not have
+     * an explicit description, returns <code>null</code>.
+     *
+     * @param keyCode An integer key code.
+     * @return A {@link CharSequence} describing the key or <code>null</code> if
+     *         no description is available.
+     */
+    private CharSequence describeKey(int keyCode) {
+        // If not loaded yet, load key descriptions from XML file.
+        if (mDescriptions == null) {
+            mDescriptions = loadDescriptions();
+        }
+
+        return mDescriptions.get(keyCode);
+    }
+
+    /**
+     * Loads key descriptions from resources.
+     */
+    private Map<Integer, CharSequence> loadDescriptions() {
+        final Map<Integer, CharSequence> descriptions = new HashMap<Integer, CharSequence>();
+        final TypedArray array = mService.getResources().obtainTypedArray(R.array.key_descriptions);
+
+        // Key descriptions are stored as a key code followed by a string.
+        for (int i = 0; i < array.length() - 1; i += 2) {
+            int code = array.getInteger(i, 0);
+            CharSequence desc = array.getText(i + 1);
+
+            descriptions.put(code, desc);
+        }
+
+        array.recycle();
+
+        return descriptions;
+    }
+
+    /**
+     * Sends a character sequence to be read aloud.
+     *
+     * @param description The {@link CharSequence} to be read aloud.
+     */
+    private void speakDescription(CharSequence description) {
+        // TODO We need to add an AccessibilityEvent type for IMEs.
+        final AccessibilityEvent event = AccessibilityEvent.obtain(
+                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+        event.setPackageName(mService.getPackageName());
+        event.setClassName(getClass().getName());
+        event.setAddedCount(description.length());
+        event.getText().add(description);
+
+        mAccessibilityManager.sendAccessibilityEvent(event);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/AssetFileAddress.java b/java/src/com/android/inputmethod/latin/AssetFileAddress.java
new file mode 100644
index 0000000000000000000000000000000000000000..074ecacc53d22b1afdf55498d25b68aac4d21a94
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AssetFileAddress.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import java.io.File;
+
+/**
+ * Immutable class to hold the address of an asset.
+ * As opposed to a normal file, an asset is usually represented as a contiguous byte array in
+ * the package file. Open it correctly thus requires the name of the package it is in, but
+ * also the offset in the file and the length of this data. This class encapsulates these three.
+ */
+class AssetFileAddress {
+    public final String mFilename;
+    public final long mOffset;
+    public final long mLength;
+
+    public AssetFileAddress(final String filename, final long offset, final long length) {
+        mFilename = filename;
+        mOffset = offset;
+        mLength = length;
+    }
+
+    public static AssetFileAddress makeFromFileName(final String filename) {
+        if (null == filename) return null;
+        File f = new File(filename);
+        if (null == f || !f.isFile()) return null;
+        return new AssetFileAddress(filename, 0l, f.length());
+    }
+
+    public static AssetFileAddress makeFromFileNameAndOffset(final String filename,
+            final long offset, final long length) {
+        if (null == filename) return null;
+        File f = new File(filename);
+        if (null == f || !f.isFile()) return null;
+        return new AssetFileAddress(filename, offset, length);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3119792cd3676137113dae54f438aa651d9ecd4
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public class AutoCorrection {
+    private static final boolean DBG = LatinImeLogger.sDBG;
+    private static final String TAG = AutoCorrection.class.getSimpleName();
+    private boolean mHasAutoCorrection;
+    private CharSequence mAutoCorrectionWord;
+    private double mNormalizedScore;
+
+    public void init() {
+        mHasAutoCorrection = false;
+        mAutoCorrectionWord = null;
+        mNormalizedScore = Integer.MIN_VALUE;
+    }
+
+    public boolean hasAutoCorrection() {
+        return mHasAutoCorrection;
+    }
+
+    public CharSequence getAutoCorrectionWord() {
+        return mAutoCorrectionWord;
+    }
+
+    public double getNormalizedScore() {
+        return mNormalizedScore;
+    }
+
+    public void updateAutoCorrectionStatus(Map<String, Dictionary> dictionaries,
+            WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] sortedScores,
+            CharSequence typedWord, double autoCorrectionThreshold, int correctionMode,
+            CharSequence quickFixedWord, CharSequence whitelistedWord) {
+        if (hasAutoCorrectionForWhitelistedWord(whitelistedWord)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = whitelistedWord;
+        } else if (hasAutoCorrectionForTypedWord(
+                dictionaries, wordComposer, suggestions, typedWord, correctionMode)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = typedWord;
+        } else if (hasAutoCorrectionForQuickFix(quickFixedWord)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = quickFixedWord;
+        } else if (hasAutoCorrectionForBinaryDictionary(wordComposer, suggestions, correctionMode,
+                sortedScores, typedWord, autoCorrectionThreshold)) {
+            mHasAutoCorrection = true;
+            mAutoCorrectionWord = suggestions.get(0);
+        }
+    }
+
+    public static boolean isValidWord(
+            Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) {
+        if (TextUtils.isEmpty(word)) {
+            return false;
+        }
+        final CharSequence lowerCasedWord = word.toString().toLowerCase();
+        for (final String key : dictionaries.keySet()) {
+            if (key.equals(Suggest.DICT_KEY_WHITELIST)) continue;
+            final Dictionary dictionary = dictionaries.get(key);
+            if (dictionary.isValidWord(word)
+                    || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isValidWordForAutoCorrection(
+            Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) {
+        final Dictionary whiteList = dictionaries.get(Suggest.DICT_KEY_WHITELIST);
+        // If "word" is in the whitelist dictionary, it should not be auto corrected.
+        if (whiteList != null && whiteList.isValidWord(word)) {
+            return false;
+        }
+        return isValidWord(dictionaries, word, ignoreCase);
+    }
+
+    private static boolean hasAutoCorrectionForWhitelistedWord(CharSequence whiteListedWord) {
+        return whiteListedWord != null;
+    }
+
+    private boolean hasAutoCorrectionForTypedWord(Map<String, Dictionary> dictionaries,
+            WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord,
+            int correctionMode) {
+        if (TextUtils.isEmpty(typedWord)) return false;
+        boolean isValidWord = isValidWordForAutoCorrection(dictionaries, typedWord, false);
+        return wordComposer.size() > 1 && suggestions.size() > 0 && isValidWord
+                && (correctionMode == Suggest.CORRECTION_FULL
+                || correctionMode == Suggest.CORRECTION_FULL_BIGRAM);
+    }
+
+    private static boolean hasAutoCorrectionForQuickFix(CharSequence quickFixedWord) {
+        return quickFixedWord != null;
+    }
+
+    private boolean hasAutoCorrectionForBinaryDictionary(WordComposer wordComposer,
+            ArrayList<CharSequence> suggestions, int correctionMode, int[] sortedScores,
+            CharSequence typedWord, double autoCorrectionThreshold) {
+        if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL
+                || correctionMode == Suggest.CORRECTION_FULL_BIGRAM)
+                && typedWord != null && suggestions.size() > 0 && sortedScores.length > 0) {
+            final CharSequence autoCorrectionCandidate = suggestions.get(0);
+            final int autoCorrectionCandidateScore = sortedScores[0];
+            // TODO: when the normalized score of the first suggestion is nearly equals to
+            //       the normalized score of the second suggestion, behave less aggressive.
+            mNormalizedScore = Utils.calcNormalizedScore(
+                    typedWord,autoCorrectionCandidate, autoCorrectionCandidateScore);
+            if (DBG) {
+                Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionCandidate + ","
+                        + autoCorrectionCandidateScore + ", " + mNormalizedScore
+                        + "(" + autoCorrectionThreshold + ")");
+            }
+            if (mNormalizedScore >= autoCorrectionThreshold) {
+                if (DBG) {
+                    Log.d(TAG, "Auto corrected by S-threshold.");
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java
index 307b81d43719a613bd2cca41a338a1944e077758..a00b0915cfdc50375c73a1333abbdf47d5ea7d22 100644
--- a/java/src/com/android/inputmethod/latin/AutoDictionary.java
+++ b/java/src/com/android/inputmethod/latin/AutoDictionary.java
@@ -27,6 +27,7 @@ import android.provider.BaseColumns;
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index d87672c0e67253250c8d9848e9d49e195d08073c..fa90fce673110f5527a2661cee3d5526cb781eb2 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -16,29 +16,37 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.ProximityInfo;
+
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.util.Log;
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.Locale;
 
 /**
  * Implements a static, compacted, binary dictionary of standard words.
  */
 public class BinaryDictionary extends Dictionary {
 
+    public static final String DICTIONARY_PACK_AUTHORITY =
+            "com.android.inputmethod.latin.dictionarypack";
+
     /**
-     * There is difference between what java and native code can handle.
+     * There is a difference between what java and native code can handle.
      * This value should only be used in BinaryDictionary.java
      * It is necessary to keep it at this value because some languages e.g. German have
      * really long words.
      */
-    protected static final int MAX_WORD_LENGTH = 48;
+    public static final int MAX_WORD_LENGTH = 48;
+    public static final int MAX_WORDS = 18;
 
     private static final String TAG = "BinaryDictionary";
-    private static final int MAX_ALTERNATIVES = 16;
-    private static final int MAX_WORDS = 18;
+    private static final int MAX_PROXIMITY_CHARS_SIZE = ProximityInfo.MAX_PROXIMITY_CHARS_SIZE;
     private static final int MAX_BIGRAMS = 60;
 
     private static final int TYPED_LETTER_MULTIPLIER = 2;
@@ -47,28 +55,45 @@ public class BinaryDictionary extends Dictionary {
     private int mDicTypeId;
     private int mNativeDict;
     private long mDictLength;
-    private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES];
+    private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_PROXIMITY_CHARS_SIZE];
     private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
     private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
-    private final int[] mFrequencies = new int[MAX_WORDS];
-    private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS];
+    private final int[] mScores = new int[MAX_WORDS];
+    private final int[] mBigramScores = new int[MAX_BIGRAMS];
 
-    static {
-        try {
-            System.loadLibrary("jni_latinime2");
-        } catch (UnsatisfiedLinkError ule) {
-        Log.e(TAG, "Could not load native library jni_latinime");
+    private final KeyboardSwitcher mKeyboardSwitcher = KeyboardSwitcher.getInstance();
+
+    public static class Flag {
+        public final String mName;
+        public final int mValue;
+
+        public Flag(String name, int value) {
+            mName = name;
+            mValue = value;
         }
     }
 
+    public static final Flag FLAG_REQUIRES_GERMAN_UMLAUT_PROCESSING =
+            new Flag("requiresGermanUmlautProcessing", 0x1);
+
+    private static final Flag[] ALL_FLAGS = {
+        // Here should reside all flags that trigger some special processing
+        // These *must* match the definition in UnigramDictionary enum in
+        // unigram_dictionary.h so please update both at the same time.
+        FLAG_REQUIRES_GERMAN_UMLAUT_PROCESSING,
+    };
+
+    private int mFlags = 0;
+
     private BinaryDictionary() {
     }
 
     /**
-     * Initialize a dictionary from a raw resource file
+     * Initializes a dictionary from a raw resource file
      * @param context application context for reading resources
      * @param resId the resource containing the raw binary dictionary
-     * @return initialized instance of BinaryDictionary
+     * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
+     * @return an initialized instance of BinaryDictionary
      */
     public static BinaryDictionary initDictionary(Context context, int resId, int dicTypeId) {
         synchronized (sInstance) {
@@ -93,12 +118,12 @@ public class BinaryDictionary extends Dictionary {
                 return null;
             }
         }
+        sInstance.mFlags = initFlags(ALL_FLAGS, SubtypeSwitcher.getInstance());
         return sInstance;
     }
 
-    // For unit test
-    /* package */ static BinaryDictionary initDictionary(File dictionary, long startOffset,
-            long length, int dicTypeId) {
+    /* package for test */ static BinaryDictionary initDictionary(File dictionary, long startOffset,
+            long length, int dicTypeId, Flag[] flagArray) {
         synchronized (sInstance) {
             sInstance.closeInternal();
             if (dictionary.isFile()) {
@@ -109,6 +134,51 @@ public class BinaryDictionary extends Dictionary {
                 return null;
             }
         }
+        sInstance.mFlags = initFlags(flagArray, null);
+        return sInstance;
+    }
+
+    private static int initFlags(Flag[] flagArray, SubtypeSwitcher switcher) {
+        int flags = 0;
+        for (Flag entry : flagArray) {
+            if (switcher == null || switcher.currentSubtypeContainsExtraValueKey(entry.mName))
+                flags |= entry.mValue;
+        }
+        return flags;
+    }
+
+    static {
+        Utils.loadNativeLibrary();
+    }
+
+    /**
+     * Initializes a dictionary from a dictionary pack.
+     *
+     * This searches for a content provider providing a dictionary pack for the specified
+     * locale. If none is found, it falls back to using the resource passed as fallBackResId
+     * as a dictionary.
+     * @param context application context for reading resources
+     * @param dicTypeId the type of the dictionary being created, out of the list in Suggest.DIC_*
+     * @param locale the locale for which to create the dictionary
+     * @param fallBackResId the id of the resource to use as a fallback if no pack is found
+     * @return an initialized instance of BinaryDictionary
+     */
+    public static BinaryDictionary initDictionaryFromManager(Context context, int dicTypeId,
+            Locale locale, int fallbackResId) {
+        if (null == locale) {
+            Log.e(TAG, "No locale defined for dictionary");
+            return initDictionary(context, fallbackResId, dicTypeId);
+        }
+        synchronized (sInstance) {
+            sInstance.closeInternal();
+
+            final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale,
+                    context, fallbackResId);
+            if (null != dictFile) {
+                sInstance.loadDictionary(dictFile.mFilename, dictFile.mOffset, dictFile.mLength);
+                sInstance.mDicTypeId = dicTypeId;
+            }
+        }
         return sInstance;
     }
 
@@ -117,89 +187,99 @@ public class BinaryDictionary extends Dictionary {
             int maxWords, int maxAlternatives);
     private native void closeNative(int dict);
     private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
-    private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize,
-            char[] outputChars, int[] frequencies,
-            int[] nextLettersFrequencies, int nextLettersSize);
+    private native int getSuggestionsNative(int dict, int proximityInfo, int[] xCoordinates,
+            int[] yCoordinates, int[] inputCodes, int codesSize, int flags, char[] outputChars,
+            int[] scores);
     private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
-            int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
+            int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores,
             int maxWordLength, int maxBigrams, int maxAlternatives);
 
     private final void loadDictionary(String path, long startOffset, long length) {
         mNativeDict = openNative(path, startOffset, length,
-                    TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
-                    MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
+                    TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER,
+                    MAX_WORD_LENGTH, MAX_WORDS, MAX_PROXIMITY_CHARS_SIZE);
         mDictLength = length;
     }
 
     @Override
     public void getBigrams(final WordComposer codes, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         if (mNativeDict == 0) return;
 
         char[] chars = previousWord.toString().toCharArray();
         Arrays.fill(mOutputChars_bigrams, (char) 0);
-        Arrays.fill(mFrequencies_bigrams, 0);
+        Arrays.fill(mBigramScores, 0);
 
         int codesSize = codes.size();
         Arrays.fill(mInputCodes, -1);
         int[] alternatives = codes.getCodesAt(0);
         System.arraycopy(alternatives, 0, mInputCodes, 0,
-                Math.min(alternatives.length, MAX_ALTERNATIVES));
+                Math.min(alternatives.length, MAX_PROXIMITY_CHARS_SIZE));
 
         int count = getBigramsNative(mNativeDict, chars, chars.length, mInputCodes, codesSize,
-                mOutputChars_bigrams, mFrequencies_bigrams, MAX_WORD_LENGTH, MAX_BIGRAMS,
-                MAX_ALTERNATIVES);
+                mOutputChars_bigrams, mBigramScores, MAX_WORD_LENGTH, MAX_BIGRAMS,
+                MAX_PROXIMITY_CHARS_SIZE);
 
         for (int j = 0; j < count; ++j) {
-            if (mFrequencies_bigrams[j] < 1) break;
+            if (mBigramScores[j] < 1) break;
             final int start = j * MAX_WORD_LENGTH;
             int len = 0;
             while (len <  MAX_WORD_LENGTH && mOutputChars_bigrams[start + len] != 0) {
                 ++len;
             }
             if (len > 0) {
-                callback.addWord(mOutputChars_bigrams, start, len, mFrequencies_bigrams[j],
+                callback.addWord(mOutputChars_bigrams, start, len, mBigramScores[j],
                         mDicTypeId, DataType.BIGRAM);
             }
         }
     }
 
     @Override
-    public void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
-        if (mNativeDict == 0) return;
-
-        final int codesSize = codes.size();
-        // Won't deal with really long words.
-        if (codesSize > MAX_WORD_LENGTH - 1) return;
-
-        Arrays.fill(mInputCodes, -1);
-        for (int i = 0; i < codesSize; i++) {
-            int[] alternatives = codes.getCodesAt(i);
-            System.arraycopy(alternatives, 0, mInputCodes, i * MAX_ALTERNATIVES,
-                    Math.min(alternatives.length, MAX_ALTERNATIVES));
-        }
-        Arrays.fill(mOutputChars, (char) 0);
-        Arrays.fill(mFrequencies, 0);
-
-        int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, mOutputChars,
-                mFrequencies, nextLettersFrequencies,
-                nextLettersFrequencies != null ? nextLettersFrequencies.length : 0);
+    public void getWords(final WordComposer codes, final WordCallback callback) {
+        final int count = getSuggestions(codes, mKeyboardSwitcher.getLatinKeyboard(),
+                mOutputChars, mScores);
 
         for (int j = 0; j < count; ++j) {
-            if (mFrequencies[j] < 1) break;
+            if (mScores[j] < 1) break;
             final int start = j * MAX_WORD_LENGTH;
             int len = 0;
             while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) {
                 ++len;
             }
             if (len > 0) {
-                callback.addWord(mOutputChars, start, len, mFrequencies[j], mDicTypeId,
+                callback.addWord(mOutputChars, start, len, mScores[j], mDicTypeId,
                         DataType.UNIGRAM);
             }
         }
     }
 
+    /* package for test */ boolean isValidDictionary() {
+        return mNativeDict != 0;
+    }
+
+    /* package for test */ int getSuggestions(final WordComposer codes, final Keyboard keyboard,
+            char[] outputChars, int[] scores) {
+        if (!isValidDictionary()) return -1;
+
+        final int codesSize = codes.size();
+        // Won't deal with really long words.
+        if (codesSize > MAX_WORD_LENGTH - 1) return -1;
+
+        Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE);
+        for (int i = 0; i < codesSize; i++) {
+            int[] alternatives = codes.getCodesAt(i);
+            System.arraycopy(alternatives, 0, mInputCodes, i * MAX_PROXIMITY_CHARS_SIZE,
+                    Math.min(alternatives.length, MAX_PROXIMITY_CHARS_SIZE));
+        }
+        Arrays.fill(outputChars, (char) 0);
+        Arrays.fill(scores, 0);
+
+        return getSuggestionsNative(
+                mNativeDict, keyboard.getProximityInfo(),
+                codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize,
+                mFlags, outputChars, scores);
+    }
+
     @Override
     public boolean isValidWord(CharSequence word) {
         if (word == null) return false;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0464dd944890d5e925f90c4fb5f02e25cfcef69
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+/**
+ * Group class for static methods to help with creation and getting of the binary dictionary
+ * file from the dictionary provider
+ */
+public class BinaryDictionaryFileDumper {
+    /**
+     * The size of the temporary buffer to copy files.
+     */
+    static final int FILE_READ_BUFFER_SIZE = 1024;
+
+    // Prevents this class to be accidentally instantiated.
+    private BinaryDictionaryFileDumper() {
+    }
+
+    /**
+     * Generates a file name that matches the locale passed as an argument.
+     * The file name is basically the result of the .toString() method, except we replace
+     * any @File.separator with an underscore to avoid generating a file name that may not
+     * be created.
+     * @param locale the locale for which to get the file name
+     * @param context the context to use for getting the directory
+     * @return the name of the file to be created
+     */
+    private static String getCacheFileNameForLocale(Locale locale, Context context) {
+        // The following assumes two things :
+        // 1. That File.separator is not the same character as "_"
+        //    I don't think any android system will ever use "_" as a path separator
+        // 2. That no two locales differ by only a File.separator versus a "_"
+        //    Since "_" can't be part of locale components this should be safe.
+        // Examples:
+        // en -> en
+        // en_US_POSIX -> en_US_POSIX
+        // en__foo/bar -> en__foo_bar
+        final String[] separator = { File.separator };
+        final String[] empty = { "_" };
+        final CharSequence basename = TextUtils.replace(locale.toString(), separator, empty);
+        return context.getFilesDir() + File.separator + basename;
+    }
+
+    /**
+     * Return for a given locale the provider URI to query to get the dictionary.
+     */
+    public static Uri getProviderUri(Locale locale) {
+        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(BinaryDictionary.DICTIONARY_PACK_AUTHORITY).appendPath(
+                        locale.toString()).build();
+    }
+
+    /**
+     * Queries a content provider for dictionary data for some locale and returns it as a file name.
+     *
+     * This will query a content provider for dictionary data for a given locale, and return
+     * the name of a file suitable to be mmap'ed. It will copy it to local storage if needed.
+     * It should also check the dictionary version to avoid unnecessary copies but this is
+     * still in TODO state.
+     * This will make the data from the content provider the cached dictionary for this locale,
+     * overwriting any previous cached data.
+     * @returns the name of the file, or null if no data could be obtained.
+     * @throw FileNotFoundException if the provider returns non-existent data.
+     * @throw IOException if the provider-returned data could not be read.
+     */
+    public static String getDictionaryFileFromContentProvider(Locale locale, Context context)
+            throws FileNotFoundException, IOException {
+        // TODO: check whether the dictionary is the same or not and if it is, return the cached
+        // file.
+        final ContentResolver resolver = context.getContentResolver();
+        final Uri dictionaryPackUri = getProviderUri(locale);
+        final InputStream stream = resolver.openInputStream(dictionaryPackUri);
+        if (null == stream) return null;
+        return copyFileTo(stream, getCacheFileNameForLocale(locale, context));
+    }
+
+    /**
+     * Accepts a file as dictionary data for some locale and returns the name of a file.
+     *
+     * This will make the data in the input file the cached dictionary for this locale, overwriting
+     * any previous cached data.
+     */
+    public static String getDictionaryFileFromFile(String fileName, Locale locale,
+            Context context) throws FileNotFoundException, IOException {
+        return copyFileTo(new FileInputStream(fileName), getCacheFileNameForLocale(locale,
+                context));
+    }
+
+    /**
+     * Accepts a resource number as dictionary data for some locale and returns the name of a file.
+     *
+     * This will make the resource the cached dictionary for this locale, overwriting any previous
+     * cached data.
+     */
+    public static String getDictionaryFileFromResource(int resource, Locale locale,
+            Context context) throws FileNotFoundException, IOException {
+        return copyFileTo(context.getResources().openRawResource(resource),
+                getCacheFileNameForLocale(locale, context));
+    }
+
+    /**
+     * Copies the data in an input stream to a target file, creating the file if necessary and
+     * overwriting it if it already exists.
+     */
+    private static String copyFileTo(final InputStream input, final String outputFileName)
+            throws FileNotFoundException, IOException {
+        final byte[] buffer = new byte[FILE_READ_BUFFER_SIZE];
+        final FileOutputStream output = new FileOutputStream(outputFileName);
+        for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer))
+            output.write(buffer, 0, readBytes);
+        input.close();
+        return outputFileName;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
new file mode 100644
index 0000000000000000000000000000000000000000..72512c7e167ec4010fc23530cae3baa678912af0
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * Helper class to get the address of a mmap'able dictionary file.
+ */
+class BinaryDictionaryGetter {
+
+    /**
+     * Used for Log actions from this class
+     */
+    private static final String TAG = BinaryDictionaryGetter.class.getSimpleName();
+
+    // Prevents this from being instantiated
+    private BinaryDictionaryGetter() {}
+
+    /**
+     * Returns a file address from a resource, or null if it cannot be opened.
+     */
+    private static AssetFileAddress loadFallbackResource(Context context, int fallbackResId) {
+        final AssetFileDescriptor afd = context.getResources().openRawResourceFd(fallbackResId);
+        if (afd == null) {
+            Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId="
+                    + fallbackResId);
+            return null;
+        }
+        return AssetFileAddress.makeFromFileNameAndOffset(
+                context.getApplicationInfo().sourceDir, afd.getStartOffset(), afd.getLength());
+    }
+
+    /**
+     * Returns a file address for a given locale, trying relevant methods in order.
+     *
+     * Tries to get a binary dictionary from various sources, in order:
+     * - Uses a private method of getting a private dictionary, as implemented by the
+     *   PrivateBinaryDictionaryGetter class.
+     * If that fails:
+     * - Uses a content provider to get a public dictionary, as per the protocol described
+     *   in BinaryDictionaryFileDumper.
+     * If that fails:
+     * - Gets a file name from the fallback resource passed as an argument.
+     * If that fails:
+     * - Returns null.
+     * @return The address of a valid file, or null.
+     * @throws FileNotFoundException if a dictionary provider returned a file name, but the
+     *                               file cannot be found.
+     * @throws IOException if there was an I/O problem reading or copying a file.
+     */
+    public static AssetFileAddress getDictionaryFile(Locale locale, Context context,
+            int fallbackResId) {
+        // Try first to query a private file signed the same way.
+        final AssetFileAddress privateFile =
+                PrivateBinaryDictionaryGetter.getDictionaryFile(locale, context);
+        if (null != privateFile) {
+            return privateFile;
+        } else {
+            try {
+                // If that was no-go, try to find a publicly exported dictionary.
+                final String fileName = BinaryDictionaryFileDumper.
+                        getDictionaryFileFromContentProvider(locale, context);
+                return AssetFileAddress.makeFromFileName(fileName);
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, "Unable to create dictionary file from provider for locale "
+                        + locale.toString() + ": falling back to internal dictionary");
+                return loadFallbackResource(context, fallbackResId);
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to read source data for locale "
+                        + locale.toString() + ": falling back to internal dictionary");
+                return loadFallbackResource(context, fallbackResId);
+            }
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index 9699ad136d7efc530ca3c4439665114a3baa1d5a..5719b90125c82e0eab9ad8ccc26189c0f3248476 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -347,9 +347,6 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
         if (mShowingAddToDictionary && index == 0) {
             addToDictionary(word);
         } else {
-            if (!mSuggestions.mIsApplicationSpecifiedCompletions) {
-                TextEntryState.acceptedSuggestion(mSuggestions.getWord(0), word);
-            }
             mService.pickSuggestionManually(index, word);
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 74933595c1299b27266e0b252dd6e0c56767cb34..ac43d6477b4f89d7272b6bac61996fd733a76e07 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -29,7 +29,7 @@ public abstract class Dictionary {
     /**
      * The weight to give to a word if it's length is the same as the number of typed characters.
      */
-    protected static final int FULL_WORD_FREQ_MULTIPLIER = 2;
+    protected static final int FULL_WORD_SCORE_MULTIPLIER = 2;
 
     public static enum DataType {
         UNIGRAM, BIGRAM
@@ -42,17 +42,17 @@ public abstract class Dictionary {
     public interface WordCallback {
         /**
          * Adds a word to a list of suggestions. The word is expected to be ordered based on
-         * the provided frequency.
+         * the provided score.
          * @param word the character array containing the word
          * @param wordOffset starting offset of the word in the character array
          * @param wordLength length of valid characters in the character array
-         * @param frequency the frequency of occurrence. This is normalized between 1 and 255, but
+         * @param score the score of occurrence. This is normalized between 1 and 255, but
          * can exceed those limits
          * @param dicTypeId of the dictionary where word was from
          * @param dataType tells type of this data
          * @return true if the word was added, false if no more words are required
          */
-        boolean addWord(char[] word, int wordOffset, int wordLength, int frequency, int dicTypeId,
+        boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId,
                 DataType dataType);
     }
 
@@ -61,14 +61,9 @@ public abstract class Dictionary {
      * words are added through the callback object.
      * @param composer the key sequence to match
      * @param callback the callback object to send matched words to as possible candidates
-     * @param nextLettersFrequencies array of frequencies of next letters that could follow the
-     *        word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
-     *        a non-zero value on returning from this method. 
-     *        Pass in null if you don't want the dictionary to look up next letters.
      * @see WordCallback#addWord(char[], int, int)
      */
-    abstract public void getWords(final WordComposer composer, final WordCallback callback,
-            int[] nextLettersFrequencies);
+    abstract public void getWords(final WordComposer composer, final WordCallback callback);
 
     /**
      * Searches for pairs in the bigram dictionary that matches the previous word and all the
@@ -76,13 +71,9 @@ public abstract class Dictionary {
      * @param composer the key sequence to match
      * @param previousWord the word before
      * @param callback the callback object to send possible word following previous word
-     * @param nextLettersFrequencies array of frequencies of next letters that could follow the
-     *        word so far. For instance, "bracke" can be followed by "t", so array['t'] will have
-     *        a non-zero value on returning from this method.
-     *        Pass in null if you don't want the dictionary to look up next letters.
      */
     public void getBigrams(final WordComposer composer, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         // empty base implementation
     }
 
diff --git a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7864621d6de0df76e7d57f4b144a1c3b78ddd0c
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.net.Uri;
+
+/**
+ * Takes action to reload the necessary data when a dictionary pack was added/removed.
+ */
+public class DictionaryPackInstallBroadcastReceiver extends BroadcastReceiver {
+
+    final LatinIME mService;
+
+    public DictionaryPackInstallBroadcastReceiver(final LatinIME service) {
+        mService = service;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        final PackageManager manager = context.getPackageManager();
+
+        // We need to reread the dictionary if a new dictionary package is installed.
+        if (action.equals(Intent.ACTION_PACKAGE_ADDED)) {
+            final Uri packageUri = intent.getData();
+            if (null == packageUri) return; // No package name : we can't do anything
+            final String packageName = packageUri.getSchemeSpecificPart();
+            if (null == packageName) return;
+            final PackageInfo packageInfo;
+            try {
+                packageInfo = manager.getPackageInfo(packageName, PackageManager.GET_PROVIDERS);
+            } catch (android.content.pm.PackageManager.NameNotFoundException e) {
+                return; // No package info : we can't do anything
+            }
+            final ProviderInfo[] providers = packageInfo.providers;
+            if (null == providers) return; // No providers : it is not a dictionary.
+
+            // Search for some dictionary pack in the just-installed package. If found, reread.
+            for (ProviderInfo info : providers) {
+                if (BinaryDictionary.DICTIONARY_PACK_AUTHORITY.equals(info.authority)) {
+                    mService.resetSuggestMainDict();
+                    return;
+                }
+            }
+            // If we come here none of the authorities matched the one we searched for.
+            // We can exit safely.
+            return;
+        } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+                && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+            // When the dictionary package is removed, we need to reread dictionary (to use the
+            // next-priority one, or stop using a dictionary at all if this was the only one,
+            // since this is the user request).
+            // If we are replacing the package, we will receive ADDED right away so no need to
+            // remove the dictionary at the moment, since we will do it when we receive the
+            // ADDED broadcast.
+
+            // TODO: Only reload dictionary on REMOVED when the removed package is the one we
+            // read dictionary from?
+            mService.resetSuggestMainDict();
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 0fc86c335288f0e03659f6943ac34c42dd40651a..d87fbce515ea56349f82d528f0d5c0d04d089fd5 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -37,7 +37,6 @@ public class ExpandableDictionary extends Dictionary {
     private int mDicTypeId;
     private int mMaxDepth;
     private int mInputLength;
-    private int[] mNextLettersFrequencies;
     private StringBuilder sb = new StringBuilder(MAX_WORD_LENGTH);
 
     private static final char QUOTE = '\'';
@@ -191,8 +190,7 @@ public class ExpandableDictionary extends Dictionary {
     }
 
     @Override
-    public void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
+    public void getWords(final WordComposer codes, final WordCallback callback) {
         synchronized (mUpdatingLock) {
             // If we need to update, start off a background task
             if (mRequiresReload) startDictionaryLoadingTaskLocked();
@@ -201,7 +199,6 @@ public class ExpandableDictionary extends Dictionary {
         }
 
         mInputLength = codes.size();
-        mNextLettersFrequencies = nextLettersFrequencies;
         if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
         // Cache the codes so that we don't have to lookup an array list
         for (int i = 0; i < mInputLength; i++) {
@@ -228,11 +225,21 @@ public class ExpandableDictionary extends Dictionary {
     /**
      * Returns the word's frequency or -1 if not found
      */
-    public int getWordFrequency(CharSequence word) {
+    protected int getWordFrequency(CharSequence word) {
         Node node = searchNode(mRoots, word, 0, word.length());
         return (node == null) ? -1 : node.mFrequency;
     }
 
+    private static int computeSkippedWordFinalFreq(int freq, int snr, int inputLength) {
+        // The computation itself makes sense for >= 2, but the == 2 case returns 0
+        // anyway so we may as well test against 3 instead and return the constant
+        if (inputLength >= 3) {
+            return (freq * snr * (inputLength - 2)) / (inputLength - 1);
+        } else {
+            return 0;
+        }
+    }
+
     /**
      * Recursively traverse the tree for words that match the input. Input consists of
      * a list of arrays. Each item in the list is one input character position. An input
@@ -246,13 +253,14 @@ public class ExpandableDictionary extends Dictionary {
      * @param completion whether the traversal is now in completion mode - meaning that we've
      * exhausted the input and we're looking for all possible suffixes.
      * @param snr current weight of the word being formed
-     * @param inputIndex position in the input characters. This can be off from the depth in 
+     * @param inputIndex position in the input characters. This can be off from the depth in
      * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type
      * "wouldve", it could be matching "would've", so the depth will be one more than the
      * inputIndex
      * @param callback the callback class for adding a word
      */
-    protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word, 
+    // TODO: Share this routine with the native code for BinaryDictionary
+    protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word,
             final int depth, boolean completion, int snr, int inputIndex, int skipPos,
             WordCallback callback) {
         final int count = roots.mLength;
@@ -278,14 +286,15 @@ public class ExpandableDictionary extends Dictionary {
             if (completion) {
                 word[depth] = c;
                 if (terminal) {
-                    if (!callback.addWord(word, 0, depth + 1, freq * snr, mDicTypeId,
-                                DataType.UNIGRAM)) {
-                        return;
+                    final int finalFreq;
+                    if (skipPos < 0) {
+                        finalFreq = freq * snr;
+                    } else {
+                        finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength);
                     }
-                    // Add to frequency of next letters for predictive correction
-                    if (mNextLettersFrequencies != null && depth >= inputIndex && skipPos < 0
-                            && mNextLettersFrequencies.length > word[inputIndex]) {
-                        mNextLettersFrequencies[word[inputIndex]]++;
+                    if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId,
+                            DataType.UNIGRAM)) {
+                        return;
                     }
                 }
                 if (children != null) {
@@ -296,7 +305,7 @@ public class ExpandableDictionary extends Dictionary {
                 // Skip the ' and continue deeper
                 word[depth] = c;
                 if (children != null) {
-                    getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, 
+                    getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex,
                             skipPos, callback);
                 }
             } else {
@@ -313,10 +322,16 @@ public class ExpandableDictionary extends Dictionary {
 
                         if (codeSize == inputIndex + 1) {
                             if (terminal) {
-                                if (INCLUDE_TYPED_WORD_IF_VALID 
+                                if (INCLUDE_TYPED_WORD_IF_VALID
                                         || !same(word, depth + 1, codes.getTypedWord())) {
-                                    int finalFreq = freq * snr * addedAttenuation;
-                                    if (skipPos < 0) finalFreq *= FULL_WORD_FREQ_MULTIPLIER;
+                                    final int finalFreq;
+                                    if (skipPos < 0) {
+                                        finalFreq = freq * snr * addedAttenuation
+                                                * FULL_WORD_SCORE_MULTIPLIER;
+                                    } else {
+                                        finalFreq = computeSkippedWordFinalFreq(freq,
+                                                snr * addedAttenuation, mInputLength);
+                                    }
                                     callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId,
                                             DataType.UNIGRAM);
                                 }
@@ -327,7 +342,7 @@ public class ExpandableDictionary extends Dictionary {
                                         skipPos, callback);
                             }
                         } else if (children != null) {
-                            getWordsRec(children, codes, word, depth + 1, 
+                            getWordsRec(children, codes, word, depth + 1,
                                     false, snr * addedAttenuation, inputIndex + 1,
                                     skipPos, callback);
                         }
@@ -427,7 +442,7 @@ public class ExpandableDictionary extends Dictionary {
 
     @Override
     public void getBigrams(final WordComposer codes, final CharSequence previousWord,
-            final WordCallback callback, int[] nextLettersFrequencies) {
+            final WordCallback callback) {
         if (!reloadDictionaryIfRequired()) {
             runReverseLookUp(previousWord, callback);
         }
@@ -516,7 +531,7 @@ public class ExpandableDictionary extends Dictionary {
         }
     }
 
-    static char toLowerCase(char c) {
+    private static char toLowerCase(char c) {
         char baseChar = c;
         if (c < BASE_CHARS.length) {
             baseChar = BASE_CHARS[c];
@@ -535,7 +550,7 @@ public class ExpandableDictionary extends Dictionary {
      * if c is not a combined character, or the base character if it
      * is combined.
      */
-    static final char BASE_CHARS[] = {
+    private static final char BASE_CHARS[] = {
         0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 
         0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 
         0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 
diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
index a9f2c2c22df54edfeda8c8ec5f33a2adc8f37b5d..be5e015aac627bf9b1ec20bd578fec8936350aa7 100644
--- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -106,8 +106,8 @@ public class InputLanguageSelection extends PreferenceActivity {
         conf.locale = locale;
         res.updateConfiguration(conf, res.getDisplayMetrics());
 
-        int mainDicResId = LatinIME.getMainDictionaryResourceId(res);
-        BinaryDictionary bd = BinaryDictionary.initDictionary(this, mainDicResId, Suggest.DIC_MAIN);
+        BinaryDictionary bd = BinaryDictionary.initDictionaryFromManager(this, Suggest.DIC_MAIN,
+                locale, Utils.getMainDictionaryResourceId(res));
 
         // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
         // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index acbccf6e61c4b4184e0eba852e7fb3f0e3a62eab..ae2315437c3efd20ff775e35dbcdb74add510f38 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -16,16 +16,21 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.compat.InputMethodSubtype;
+import com.android.inputmethod.compat.CompatUtils;
+import com.android.inputmethod.compat.EditorInfoCompatUtils;
+import com.android.inputmethod.compat.InputConnectionCompatUtils;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+import com.android.inputmethod.compat.VibratorCompatWrapper;
+import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
-import com.android.inputmethod.keyboard.KeyboardId;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.LatinKeyboard;
 import com.android.inputmethod.keyboard.LatinKeyboardView;
 import com.android.inputmethod.latin.Utils.RingCharBuffer;
-import com.android.inputmethod.voice.VoiceIMEConnector;
 
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
@@ -41,9 +46,9 @@ import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.SystemClock;
-import android.os.Vibrator;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceManager;
 import android.text.InputType;
@@ -62,13 +67,10 @@ import android.view.ViewParent;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
-// @@@ import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
-// @@@ import android.view.inputmethod.InputMethodSubtype;
 import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.LinearLayout;
@@ -82,13 +84,35 @@ import java.util.Locale;
 /**
  * Input method implementation for Qwerty'ish keyboard.
  */
-public class LatinIME extends InputMethodService implements KeyboardActionListener,
-        SharedPreferences.OnSharedPreferenceChangeListener {
-    private static final String TAG = "LatinIME";
+public class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener {
+    private static final String TAG = LatinIME.class.getSimpleName();
     private static final boolean PERF_DEBUG = false;
     private static final boolean TRACE = false;
     private static boolean DEBUG = LatinImeLogger.sDBG;
 
+    /**
+     * The private IME option used to indicate that no microphone should be
+     * shown for a given text field. For instance, this is specified by the
+     * search dialog when the dialog is already showing a voice search button.
+     *
+     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
+     */
+    @SuppressWarnings("dep-ann")
+    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
+
+    /**
+     * The private IME option used to indicate that no microphone should be
+     * shown for a given text field. For instance, this is specified by the
+     * search dialog when the dialog is already showing a voice search button.
+     */
+    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
+
+    /**
+     * The private IME option used to indicate that no settings key should be
+     * shown for a given text field.
+     */
+    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
+
     private static final int DELAY_UPDATE_SUGGESTIONS = 180;
     private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
     private static final int DELAY_UPDATE_SHIFT_STATE = 300;
@@ -99,6 +123,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     // Key events coming any faster than this are long-presses.
     private static final int QUICK_PRESS = 200;
 
+    /**
+     * The name of the scheme used by the Package Manager to warn of a new package installation,
+     * replacement or removal.
+     */
+    private static final String SCHEME_PACKAGE = "package";
+
     private int mSuggestionVisibility;
     private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
             = R.string.prefs_suggestion_visibility_show_value;
@@ -120,13 +150,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     private AlertDialog mOptionsDialog;
 
-    private InputMethodManager mImm;
+    private InputMethodManagerCompatWrapper mImm;
     private Resources mResources;
     private SharedPreferences mPrefs;
     private String mInputMethodId;
     private KeyboardSwitcher mKeyboardSwitcher;
     private SubtypeSwitcher mSubtypeSwitcher;
-    private VoiceIMEConnector mVoiceConnector;
+    private VoiceProxy mVoiceProxy;
 
     private UserDictionary mUserDictionary;
     private UserBigramDictionary mUserBigramDictionary;
@@ -139,6 +169,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private boolean mIsSettingsSuggestionStripOn;
     private boolean mApplicationSpecifiedCompletionOn;
 
+    private AccessibilityUtils mAccessibilityUtils;
+
     private final StringBuilder mComposing = new StringBuilder();
     private WordComposer mWord = new WordComposer();
     private CharSequence mBestWord;
@@ -146,7 +178,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private boolean mHasDictionary;
     private boolean mJustAddedAutoSpace;
     private boolean mAutoCorrectEnabled;
-    private boolean mReCorrectionEnabled;
+    private boolean mRecorrectionEnabled;
     private boolean mBigramSuggestionEnabled;
     private boolean mAutoCorrectOn;
     private boolean mVibrateOn;
@@ -159,6 +191,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
     private int mConfigDurationOfFadeoutLanguageOnSpacebar;
     private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
+    private long mConfigDoubleSpacesTurnIntoPeriodTimeout;
 
     private int mCorrectionMode;
     private int mCommittedLength;
@@ -170,7 +203,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     // Indicates whether the suggestion strip is to be on in landscape
     private boolean mJustAccepted;
-    private boolean mJustReverted;
     private int mDeleteCount;
     private long mLastKeyTime;
 
@@ -182,60 +214,47 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     /* package */ String mWordSeparators;
     private String mSentenceSeparators;
     private String mSuggestPuncs;
-    // TODO: Move this flag to VoiceIMEConnector
+    // TODO: Move this flag to VoiceProxy
     private boolean mConfigurationChanging;
 
+    // Object for reacting to adding/removing a dictionary pack.
+    private BroadcastReceiver mDictionaryPackInstallReceiver =
+            new DictionaryPackInstallBroadcastReceiver(this);
+
     // Keeps track of most recently inserted text (multi-character key) for reverting
     private CharSequence mEnteredText;
-    private boolean mRefreshKeyboardRequired;
 
     private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
 
-    public abstract static class WordAlternatives {
-        protected CharSequence mChosenWord;
+    public class WordAlternatives {
+        private final CharSequence mChosenWord;
+        private final WordComposer mWordComposer;
 
-        public WordAlternatives() {
-            // Nothing
-        }
-
-        public WordAlternatives(CharSequence chosenWord) {
+        public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
             mChosenWord = chosenWord;
+            mWordComposer = wordComposer;
         }
 
-        @Override
-        public int hashCode() {
-            return mChosenWord.hashCode();
-        }
-
-        public abstract CharSequence getOriginalWord();
-
         public CharSequence getChosenWord() {
             return mChosenWord;
         }
 
-        public abstract SuggestedWords.Builder getAlternatives();
-    }
-
-    public class TypedWordAlternatives extends WordAlternatives {
-        private WordComposer word;
-
-        public TypedWordAlternatives() {
-            // Nothing
+        public CharSequence getOriginalWord() {
+            return mWordComposer.getTypedWord();
         }
 
-        public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
-            super(chosenWord);
-            word = wordComposer;
+        public SuggestedWords.Builder getAlternatives() {
+            return getTypedSuggestions(mWordComposer);
         }
 
         @Override
-        public CharSequence getOriginalWord() {
-            return word.getTypedWord();
+        public int hashCode() {
+            return mChosenWord.hashCode();
         }
 
         @Override
-        public SuggestedWords.Builder getAlternatives() {
-            return getTypedSuggestions(word);
+        public boolean equals(Object o) {
+            return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o);
         }
     }
 
@@ -248,6 +267,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         private static final int MSG_VOICE_RESULTS = 3;
         private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
         private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
+        private static final int MSG_SPACE_TYPED = 6;
 
         @Override
         public void handleMessage(Message msg) {
@@ -264,7 +284,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 switcher.updateShiftState();
                 break;
             case MSG_VOICE_RESULTS:
-                mVoiceConnector.handleVoiceResults(preferCapitalization()
+                mVoiceProxy.handleVoiceResults(preferCapitalization()
                         || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
                 break;
             case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
@@ -324,7 +344,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
             final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
             if (inputView != null) {
-                final LatinKeyboard keyboard = inputView.getLatinKeyboard();
+                final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
                 // The language is never displayed when the delay is zero.
                 if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
                     inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
@@ -336,6 +356,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 }
             }
         }
+
+        public void startDoubleSpacesTimer() {
+            removeMessages(MSG_SPACE_TYPED);
+            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
+                    mConfigDoubleSpacesTurnIntoPeriodTimeout);
+        }
+
+        public void cancelDoubleSpacesTimer() {
+            removeMessages(MSG_SPACE_TYPED);
+        }
+
+        public boolean isAcceptingDoubleSpaces() {
+            return hasMessages(MSG_SPACE_TYPED);
+        }
     }
 
     @Override
@@ -345,13 +379,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         LatinImeLogger.init(this, prefs);
         SubtypeSwitcher.init(this, prefs);
         KeyboardSwitcher.init(this, prefs);
+        AccessibilityUtils.init(this, prefs);
 
         super.onCreate();
 
-        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
-        mInputMethodId = Utils.getInputMethodId(mImm, getApplicationInfo().packageName);
+        mImm = InputMethodManagerCompatWrapper.getInstance(this);
+        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mKeyboardSwitcher = KeyboardSwitcher.getInstance();
+        mAccessibilityUtils = AccessibilityUtils.getInstance();
 
         final Resources res = getResources();
         mResources = res;
@@ -359,10 +395,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         // If the option should not be shown, do not read the recorrection preference
         // but always use the default setting defined in the resources.
         if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
-            mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
+            mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
                     res.getBoolean(R.bool.config_default_recorrection_enabled));
         } else {
-            mReCorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
+            mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
         }
 
         mConfigEnableShowSubtypeSettings = res.getBoolean(
@@ -375,6 +411,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 R.integer.config_duration_of_fadeout_language_on_spacebar);
         mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
                 R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
+        mConfigDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
+                R.integer.config_double_spaces_turn_into_period_timeout);
 
         Utils.GCUtils.getInstance().reset();
         boolean tryGC = true;
@@ -390,30 +428,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mOrientation = res.getConfiguration().orientation;
         initSuggestPuncList();
 
-        // register to receive ringer mode change and network state change.
+        // Register to receive ringer mode change and network state change.
+        // Also receive installation and removal of a dictionary pack.
         final IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         registerReceiver(mReceiver, filter);
-        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
-        prefs.registerOnSharedPreferenceChangeListener(this);
-    }
+        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
 
-    /**
-     * Returns a main dictionary resource id
-     * @return main dictionary resource id
-     */
-    public static int getMainDictionaryResourceId(Resources res) {
-        final String MAIN_DIC_NAME = "main";
-        String packageName = LatinIME.class.getPackage().getName();
-        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
+        final IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageFilter.addDataScheme(SCHEME_PACKAGE);
+        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
     }
 
     private void initSuggest() {
-        updateAutoTextEnabled();
-        String locale = mSubtypeSwitcher.getInputLocaleStr();
+        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
+        final Locale keyboardLocale = new Locale(localeStr);
 
-        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
+        final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(keyboardLocale);
         if (mSuggest != null) {
             mSuggest.close();
         }
@@ -421,20 +455,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mQuickFixes = isQuickFixesEnabled(prefs);
 
         final Resources res = mResources;
-        int mainDicResId = getMainDictionaryResourceId(res);
-        mSuggest = new Suggest(this, mainDicResId);
+        int mainDicResId = Utils.getMainDictionaryResourceId(res);
+        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
         loadAndSetAutoCorrectionThreshold(prefs);
+        updateAutoTextEnabled();
 
-        mUserDictionary = new UserDictionary(this, locale);
+        mUserDictionary = new UserDictionary(this, localeStr);
         mSuggest.setUserDictionary(mUserDictionary);
 
         mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
         mSuggest.setContactsDictionary(mContactsDictionary);
 
-        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
+        mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
         mSuggest.setAutoDictionary(mAutoDictionary);
 
-        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
+        mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
         mSuggest.setUserBigramDictionary(mUserBigramDictionary);
 
         updateCorrectionMode();
@@ -444,6 +479,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mSubtypeSwitcher.changeSystemLocale(savedLocale);
     }
 
+    /* package private */ void resetSuggestMainDict() {
+        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
+        final Locale keyboardLocale = new Locale(localeStr);
+        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
+        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
+    }
+
     @Override
     public void onDestroy() {
         if (mSuggest != null) {
@@ -451,7 +493,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mSuggest = null;
         }
         unregisterReceiver(mReceiver);
-        mVoiceConnector.destroy();
+        unregisterReceiver(mDictionaryPackInstallReceiver);
+        mVoiceProxy.destroy();
         LatinImeLogger.commit();
         LatinImeLogger.onDestroy();
         super.onDestroy();
@@ -472,7 +515,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         mConfigurationChanging = true;
         super.onConfigurationChanged(conf);
-        mVoiceConnector.onConfigurationChanged(conf);
+        mVoiceProxy.onConfigurationChanged(conf);
         mConfigurationChanging = false;
     }
 
@@ -489,7 +532,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (container.getPaddingRight() != 0) {
             HorizontalScrollView scrollView =
                     (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view);
-            // @@@ scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+            setOverScrollModeNever(scrollView);
             container.setGravity(Gravity.CENTER_HORIZONTAL);
         }
         mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
@@ -498,17 +541,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         return container;
     }
 
-    private static boolean isPasswordVariation(int variation) {
-        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
-                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
-        // @@@ || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
-    }
-
-    private static boolean isEmailVariation(int variation) {
-        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
-        // @@@ || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
-    }
-
     @Override
     public void onStartInputView(EditorInfo attribute, boolean restarting) {
         final KeyboardSwitcher switcher = mKeyboardSwitcher;
@@ -524,20 +556,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         mSubtypeSwitcher.updateParametersOnStartInputView();
 
-        if (mRefreshKeyboardRequired) {
-            mRefreshKeyboardRequired = false;
-            onRefreshKeyboard();
-        }
-
-        TextEntryState.newSession(this);
+        TextEntryState.reset();
 
         // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
         // know now whether this is a password text field, because we need to know now whether we
         // want to enable the voice button.
-        mVoiceConnector.resetVoiceStates(isPasswordVariation(
-                attribute.inputType & InputType.TYPE_MASK_VARIATION));
+        final VoiceProxy voiceIme = mVoiceProxy;
+        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(attribute.inputType)
+                || InputTypeCompatUtils.isVisiblePasswordInputType(attribute.inputType));
 
-        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+        initializeInputAttributes(attribute);
 
         inputView.closing();
         mEnteredText = null;
@@ -548,9 +576,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         loadSettings(attribute);
         if (mSubtypeSwitcher.isKeyboardMode()) {
-            switcher.loadKeyboard(mode, attribute.imeOptions,
-                    mVoiceConnector.isVoiceButtonEnabled(),
-                    mVoiceConnector.isVoiceButtonOnPrimary());
+            switcher.loadKeyboard(attribute,
+                    mSubtypeSwitcher.isShortcutImeEnabled() && voiceIme.isVoiceButtonEnabled(),
+                    voiceIme.isVoiceButtonOnPrimary());
             switcher.updateShiftState();
         }
 
@@ -561,18 +589,24 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         updateCorrectionMode();
 
+        final boolean accessibilityEnabled = mAccessibilityUtils.isAccessibilityEnabled();
+
         inputView.setPreviewEnabled(mPopupOn);
         inputView.setProximityCorrectionEnabled(true);
+        inputView.setAccessibilityEnabled(accessibilityEnabled);
         // If we just entered a text field, maybe it has some old text that requires correction
-        checkReCorrectionOnStart();
+        checkRecorrectionOnStart();
         inputView.setForeground(true);
 
-        mVoiceConnector.onStartInputView(inputView.getWindowToken());
+        voiceIme.onStartInputView(inputView.getWindowToken());
 
         if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
     }
 
-    private int initializeInputAttributesAndGetMode(int inputType) {
+    private void initializeInputAttributes(EditorInfo attribute) {
+        if (attribute == null)
+            return;
+        final int inputType = attribute.inputType;
         final int variation = inputType & InputType.TYPE_MASK_VARIATION;
         mAutoSpace = false;
         mInputTypeNoAutoCorrect = false;
@@ -580,73 +614,52 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mApplicationSpecifiedCompletionOn = false;
         mApplicationSpecifiedCompletions = null;
 
-        final int mode;
-        switch (inputType & InputType.TYPE_MASK_CLASS) {
-            case InputType.TYPE_CLASS_NUMBER:
-            case InputType.TYPE_CLASS_DATETIME:
-                mode = KeyboardId.MODE_NUMBER;
-                break;
-            case InputType.TYPE_CLASS_PHONE:
-                mode = KeyboardId.MODE_PHONE;
-                break;
-            case InputType.TYPE_CLASS_TEXT:
-                mIsSettingsSuggestionStripOn = true;
-                // Make sure that passwords are not displayed in candidate view
-                if (isPasswordVariation(variation)) {
-                    mIsSettingsSuggestionStripOn = false;
-                }
-                if (isEmailVariation(variation)
-                        || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
-                    mAutoSpace = false;
-                } else {
-                    mAutoSpace = true;
-                }
-                if (isEmailVariation(variation)) {
-                    mIsSettingsSuggestionStripOn = false;
-                    mode = KeyboardId.MODE_EMAIL;
-                } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
-                    mIsSettingsSuggestionStripOn = false;
-                    mode = KeyboardId.MODE_URL;
-                } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
-                    mode = KeyboardId.MODE_IM;
-                } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
-                    mIsSettingsSuggestionStripOn = false;
-                    mode = KeyboardId.MODE_TEXT;
-                } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
-                    mode = KeyboardId.MODE_WEB;
-                    // If it's a browser edit field and auto correct is not ON explicitly, then
-                    // disable auto correction, but keep suggestions on.
-                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
-                        mInputTypeNoAutoCorrect = true;
-                    }
-                } else {
-                    mode = KeyboardId.MODE_TEXT;
-                }
-
-                // If NO_SUGGESTIONS is set, don't do prediction.
-                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
-                    mIsSettingsSuggestionStripOn = false;
-                    mInputTypeNoAutoCorrect = true;
-                }
-                // If it's not multiline and the autoCorrect flag is not set, then don't correct
-                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
-                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
+            mIsSettingsSuggestionStripOn = true;
+            // Make sure that passwords are not displayed in candidate view
+            if (InputTypeCompatUtils.isPasswordInputType(inputType)
+                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
+                mIsSettingsSuggestionStripOn = false;
+            }
+            if (InputTypeCompatUtils.isEmailVariation(variation)
+                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
+                mAutoSpace = false;
+            } else {
+                mAutoSpace = true;
+            }
+            if (InputTypeCompatUtils.isEmailVariation(variation)) {
+                mIsSettingsSuggestionStripOn = false;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
+                mIsSettingsSuggestionStripOn = false;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+                mIsSettingsSuggestionStripOn = false;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
+                // If it's a browser edit field and auto correct is not ON explicitly, then
+                // disable auto correction, but keep suggestions on.
+                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
                     mInputTypeNoAutoCorrect = true;
                 }
-                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
-                    mIsSettingsSuggestionStripOn = false;
-                    mApplicationSpecifiedCompletionOn = isFullscreenMode();
-                }
-                break;
-            default:
-                mode = KeyboardId.MODE_TEXT;
-                break;
+            }
+
+            // If NO_SUGGESTIONS is set, don't do prediction.
+            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
+                mIsSettingsSuggestionStripOn = false;
+                mInputTypeNoAutoCorrect = true;
+            }
+            // If it's not multiline and the autoCorrect flag is not set, then don't correct
+            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
+                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
+                mInputTypeNoAutoCorrect = true;
+            }
+            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+                mIsSettingsSuggestionStripOn = false;
+                mApplicationSpecifiedCompletionOn = isFullscreenMode();
+            }
         }
-        return mode;
     }
 
-    private void checkReCorrectionOnStart() {
-        if (!mReCorrectionEnabled) return;
+    private void checkRecorrectionOnStart() {
+        if (!mRecorrectionEnabled) return;
 
         final InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
@@ -680,7 +693,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         LatinImeLogger.commit();
         mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
 
-        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
+        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
 
         KeyboardView inputView = mKeyboardSwitcher.getInputView();
         if (inputView != null) inputView.closing();
@@ -701,7 +714,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     @Override
     public void onUpdateExtractedText(int token, ExtractedText text) {
         super.onUpdateExtractedText(token, text);
-        mVoiceConnector.showPunctuationHintIfNecessary();
+        mVoiceProxy.showPunctuationHintIfNecessary();
     }
 
     @Override
@@ -714,19 +727,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (DEBUG) {
             Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
                     + ", ose=" + oldSelEnd
+                    + ", lss=" + mLastSelectionStart
+                    + ", lse=" + mLastSelectionEnd
                     + ", nss=" + newSelStart
                     + ", nse=" + newSelEnd
                     + ", cs=" + candidatesStart
                     + ", ce=" + candidatesEnd);
         }
 
-        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
+        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
 
         // If the current selection in the text view changes, we should
         // clear whatever candidate text we have.
-        if ((((mComposing.length() > 0 && mHasValidSuggestions)
-                || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd
-                        || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) {
+        final boolean selectionChanged = (newSelStart != candidatesEnd
+                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
+        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
+        if (((mComposing.length() > 0 && mHasValidSuggestions)
+                || mVoiceProxy.isVoiceInputHighlighted())
+                && (selectionChanged || candidatesCleared)) {
+            if (candidatesCleared) {
+                // If the composing span has been cleared, save the typed word in the history for
+                // recorrection before we reset the candidate strip.  Then, we'll be able to show
+                // suggestions for recorrection right away.
+                saveWordInHistory(mComposing);
+            }
             mComposing.setLength(0);
             mHasValidSuggestions = false;
             mHandler.postUpdateSuggestions();
@@ -735,17 +759,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             if (ic != null) {
                 ic.finishComposingText();
             }
-            mVoiceConnector.setVoiceInputHighlighted(false);
+            mVoiceProxy.setVoiceInputHighlighted(false);
         } else if (!mHasValidSuggestions && !mJustAccepted) {
-            switch (TextEntryState.getState()) {
-            case ACCEPTED_DEFAULT:
-                TextEntryState.reset();
-                // $FALL-THROUGH$
-            case SPACE_AFTER_PICKED:
+            if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) {
+                if (TextEntryState.isAcceptedDefault())
+                    TextEntryState.reset();
                 mJustAddedAutoSpace = false; // The user moved the cursor.
-                break;
-            default:
-                break;
             }
         }
         mJustAccepted = false;
@@ -755,18 +774,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mLastSelectionStart = newSelStart;
         mLastSelectionEnd = newSelEnd;
 
-        if (mReCorrectionEnabled && isShowingSuggestionsStrip()) {
+        if (mRecorrectionEnabled && isShowingSuggestionsStrip()) {
             // Don't look for corrections if the keyboard is not visible
             if (mKeyboardSwitcher.isInputViewShown()) {
                 // Check if we should go in or out of correction mode.
-                if (isSuggestionsRequested() && !mJustReverted
+                if (isSuggestionsRequested()
                         && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
-                                || TextEntryState.isCorrecting())
+                                || TextEntryState.isRecorrecting())
                                 && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
                     if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
                         mHandler.postUpdateOldSuggestions();
                     } else {
-                        abortCorrection(false);
+                        abortRecorrection(false);
                         // Show the punctuation suggestions list if the current one is not
                         // and if not showing "Touch again to save".
                         if (mCandidateView != null && !isShowingPunctuationList()
@@ -789,7 +808,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
      */
     @Override
     public void onExtractedTextClicked() {
-        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
+        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
 
         super.onExtractedTextClicked();
     }
@@ -805,7 +824,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
      */
     @Override
     public void onExtractedCursorMovement(int dx, int dy) {
-        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
+        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
 
         super.onExtractedCursorMovement(dx, dy);
     }
@@ -820,20 +839,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mOptionsDialog.dismiss();
             mOptionsDialog = null;
         }
-        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
+        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
         mWordHistory.clear();
         super.hideWindow();
-        TextEntryState.endSession();
     }
 
     @Override
     public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
         if (DEBUG) {
             Log.i(TAG, "Received completions:");
-            final int count = (applicationSpecifiedCompletions != null)
-                    ? applicationSpecifiedCompletions.length : 0;
-            for (int i = 0; i < count; i++) {
-                Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
+            if (applicationSpecifiedCompletions != null) {
+                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
+                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
+                }
             }
         }
         if (mApplicationSpecifiedCompletionOn) {
@@ -898,8 +916,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             if (DEBUG) {
                 Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height);
             }
-            //@@@outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
-            //@@@outInsets.touchableRegion.set(x, y, width, height);
+            setTouchableRegionCompat(outInsets, x, y, width, height);
         }
     }
 
@@ -964,7 +981,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 }
                 mCommittedLength = mComposing.length();
                 TextEntryState.acceptedTyped(mComposing);
-                addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
+                addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
             }
             updateSuggestions();
         }
@@ -1012,7 +1029,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void doubleSpace() {
-        //if (!mAutoPunctuate) return;
         if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
         final InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
@@ -1020,13 +1036,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (lastThree != null && lastThree.length() == 3
                 && Character.isLetterOrDigit(lastThree.charAt(0))
                 && lastThree.charAt(1) == Keyboard.CODE_SPACE
-                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
+                && lastThree.charAt(2) == Keyboard.CODE_SPACE
+                && mHandler.isAcceptingDoubleSpaces()) {
+            mHandler.cancelDoubleSpacesTimer();
             ic.beginBatchEdit();
             ic.deleteSurroundingText(2, 0);
             ic.commitText(". ", 1);
             ic.endBatchEdit();
             mKeyboardSwitcher.updateShiftState();
             mJustAddedAutoSpace = true;
+        } else {
+            mHandler.startDoubleSpacesTimer();
         }
     }
 
@@ -1106,6 +1126,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         }
         mLastKeyTime = when;
         KeyboardSwitcher switcher = mKeyboardSwitcher;
+        final boolean accessibilityEnabled = switcher.isAccessibilityEnabled();
         final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
         switch (primaryCode) {
         case Keyboard.CODE_DELETE:
@@ -1115,12 +1136,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             break;
         case Keyboard.CODE_SHIFT:
             // Shift key is handled in onPress() when device has distinct multi-touch panel.
-            if (!distinctMultiTouch)
+            if (!distinctMultiTouch || accessibilityEnabled)
                 switcher.toggleShift();
             break;
         case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
             // Symbol key is handled in onPress() when device has distinct multi-touch panel.
-            if (!distinctMultiTouch)
+            if (!distinctMultiTouch || accessibilityEnabled)
                 switcher.changeKeyboardMode();
             break;
         case Keyboard.CODE_CANCEL:
@@ -1158,10 +1179,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             if (isWordSeparator(primaryCode)) {
                 handleSeparator(primaryCode);
             } else {
-                handleCharacter(primaryCode, keyCodes);
+                handleCharacter(primaryCode, keyCodes, x, y);
             }
-            // Cancel the just reverted state
-            mJustReverted = false;
         }
         switcher.onKey(primaryCode);
         // Reset after any single keystroke
@@ -1170,10 +1189,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     @Override
     public void onTextInput(CharSequence text) {
-        mVoiceConnector.commitVoiceInput();
+        mVoiceProxy.commitVoiceInput();
         InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
-        abortCorrection(false);
+        abortRecorrection(false);
         ic.beginBatchEdit();
         commitTyped(ic);
         maybeRemovePreviousPeriod(text);
@@ -1181,7 +1200,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         ic.endBatchEdit();
         mKeyboardSwitcher.updateShiftState();
         mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
-        mJustReverted = false;
         mJustAddedAutoSpace = false;
         mEnteredText = text;
     }
@@ -1193,13 +1211,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void handleBackspace() {
-        if (mVoiceConnector.logAndRevertVoiceInput()) return;
+        if (mVoiceProxy.logAndRevertVoiceInput()) return;
 
         final InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
         ic.beginBatchEdit();
 
-        mVoiceConnector.handleBackspace();
+        mVoiceProxy.handleBackspace();
 
         boolean deleteChar = false;
         if (mHasValidSuggestions) {
@@ -1221,7 +1239,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mHandler.postUpdateShiftKeyState();
 
         TextEntryState.backspace();
-        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
+        if (TextEntryState.isUndoCommit()) {
             revertLastWord(deleteChar);
             ic.endBatchEdit();
             return;
@@ -1246,16 +1264,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 }
             }
         }
-        mJustReverted = false;
         ic.endBatchEdit();
     }
 
     private void handleTab() {
         final int imeOptions = getCurrentInputEditorInfo().imeOptions;
-        final int navigationFlags = 0;
-        // @@@ final int navigationFlags =
-        // @@@ EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
-        if ((imeOptions & navigationFlags) == 0) {
+        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
+                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
             sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
             return;
         }
@@ -1264,33 +1279,32 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (ic == null)
             return;
 
-        /* @@@
         // True if keyboard is in either chording shift or manual temporary upper case mode.
         final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
-        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
+        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
                 && !isManualTemporaryUpperCase) {
+            EditorInfoCompatUtils.performEditorActionNext(ic);
             ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
-        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
+        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
                 && isManualTemporaryUpperCase) {
-            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
+            EditorInfoCompatUtils.performEditorActionPrevious(ic);
         }
-        */
     }
 
-    private void abortCorrection(boolean force) {
-        if (force || TextEntryState.isCorrecting()) {
-            TextEntryState.onAbortCorrection();
+    private void abortRecorrection(boolean force) {
+        if (force || TextEntryState.isRecorrecting()) {
+            TextEntryState.onAbortRecorrection();
             setCandidatesViewShown(isCandidateStripVisible());
             getCurrentInputConnection().finishComposingText();
             clearSuggestions();
         }
     }
 
-    private void handleCharacter(int primaryCode, int[] keyCodes) {
-        mVoiceConnector.handleCharacter();
+    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
+        mVoiceProxy.handleCharacter();
 
-        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) {
-            abortCorrection(false);
+        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isRecorrecting()) {
+            abortRecorrection(false);
         }
 
         int code = primaryCode;
@@ -1300,6 +1314,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 mComposing.setLength(0);
                 saveWordInHistory(mBestWord);
                 mWord.reset();
+                clearSuggestions();
             }
         }
         KeyboardSwitcher switcher = mKeyboardSwitcher;
@@ -1327,7 +1342,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 mWord.setFirstCharCapitalized(true);
             }
             mComposing.append((char) code);
-            mWord.add(code, keyCodes);
+            mWord.add(code, keyCodes, x, y);
             InputConnection ic = getCurrentInputConnection();
             if (ic != null) {
                 // If it's the first letter, make note of auto-caps state
@@ -1346,7 +1361,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void handleSeparator(int primaryCode) {
-        mVoiceConnector.handleSeparator();
+        mVoiceProxy.handleSeparator();
 
         // Should dismiss the "Touch again to save" message when handling separator
         if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
@@ -1358,14 +1373,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         final InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
             ic.beginBatchEdit();
-            abortCorrection(false);
+            abortRecorrection(false);
         }
         if (mHasValidSuggestions) {
             // In certain languages where single quote is a separator, it's better
             // not to auto correct, but accept the typed word. For instance,
             // in Italian dov' should not be expanded to dove' because the elision
             // requires the last vowel to be removed.
-            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
+            if (mAutoCorrectOn && primaryCode != '\'') {
                 pickedDefault = pickDefaultSuggestion();
                 // Picked the suggestion by the space key.  We consider this
                 // as "added an auto space".
@@ -1384,14 +1399,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         // Handle the case of ". ." -> " .." with auto-space if necessary
         // before changing the TextEntryState.
-        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
-                && primaryCode == Keyboard.CODE_PERIOD) {
+        if (TextEntryState.isPunctuationAfterAccepted() && primaryCode == Keyboard.CODE_PERIOD) {
             reswapPeriodAndSpace();
         }
 
         TextEntryState.typedCharacter((char) primaryCode, true);
-        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
-                && primaryCode != Keyboard.CODE_ENTER) {
+        if (TextEntryState.isPunctuationAfterAccepted() && primaryCode != Keyboard.CODE_ENTER) {
             swapPunctuationAndSpace();
         } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
             doubleSpace();
@@ -1400,13 +1413,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             CharSequence typedWord = mWord.getTypedWord();
             TextEntryState.backToAcceptedDefault(typedWord);
             if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
-                if (ic != null) {
-                    /* @@@
-                    CorrectionInfo correctionInfo = new CorrectionInfo(
-                            mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
-                    ic.commitCorrection(correctionInfo);
-                    */
-                }
+                InputConnectionCompatUtils.commitCorrection(
+                        ic,  mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
                 if (mCandidateView != null)
                     mCandidateView.onAutoCorrectionInverted(mBestWord);
             }
@@ -1420,17 +1428,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     private void handleClose() {
         commitTyped(getCurrentInputConnection());
-        mVoiceConnector.handleClose();
+        mVoiceProxy.handleClose();
         requestHideSelf(0);
         LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
         if (inputView != null)
             inputView.closing();
-        TextEntryState.endSession();
     }
 
     private void saveWordInHistory(CharSequence result) {
         if (mWord.size() <= 1) {
-            mWord.reset();
             return;
         }
         // Skip if result is null. It happens in some edge case.
@@ -1440,7 +1446,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
         final String resultCopy = result.toString();
-        TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy,
+        WordAlternatives entry = new WordAlternatives(resultCopy,
                 new WordComposer(mWord));
         mWordHistory.add(entry);
     }
@@ -1463,7 +1469,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private boolean isCandidateStripVisible() {
         if (mCandidateView == null)
             return false;
-        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isCorrecting())
+        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
             return true;
         if (!isShowingSuggestionsStrip())
             return false;
@@ -1473,26 +1479,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     public void switchToKeyboardView() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (DEBUG) {
-                    Log.d(TAG, "Switch to keyboard view.");
-                }
-                View v = mKeyboardSwitcher.getInputView();
-                if (v != null) {
-                    // Confirms that the keyboard view doesn't have parent view.
-                    ViewParent p = v.getParent();
-                    if (p != null && p instanceof ViewGroup) {
-                        ((ViewGroup) p).removeView(v);
-                    }
-                    setInputView(v);
-                }
-                setCandidatesViewShown(isCandidateStripVisible());
-                updateInputViewShown();
-                mHandler.postUpdateSuggestions();
+        if (DEBUG) {
+            Log.d(TAG, "Switch to keyboard view.");
+        }
+        View v = mKeyboardSwitcher.getInputView();
+        if (v != null) {
+            // Confirms that the keyboard view doesn't have parent view.
+            ViewParent p = v.getParent();
+            if (p != null && p instanceof ViewGroup) {
+                ((ViewGroup) p).removeView(v);
             }
-        });
+            setInputView(v);
+        }
+        setCandidatesViewShown(isCandidateStripVisible());
+        updateInputViewShown();
+        mHandler.postUpdateSuggestions();
     }
 
     public void clearSuggestions() {
@@ -1500,7 +1501,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     public void setSuggestions(SuggestedWords words) {
-        if (mVoiceConnector.getAndResetIsShowingHint()) {
+        if (mVoiceProxy.getAndResetIsShowingHint()) {
              setCandidatesView(mCandidateViewContainer);
         }
 
@@ -1514,11 +1515,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     public void updateSuggestions() {
-        mKeyboardSwitcher.setPreferredLetters(null);
-
         // Check if we have a suggestion engine attached.
         if ((mSuggest == null || !isSuggestionsRequested())
-                && !mVoiceConnector.isVoiceInputHighlighted()) {
+                && !mVoiceProxy.isVoiceInputHighlighted()) {
             return;
         }
 
@@ -1534,36 +1533,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void showCorrections(WordAlternatives alternatives) {
-        mKeyboardSwitcher.setPreferredLetters(null);
         SuggestedWords.Builder builder = alternatives.getAlternatives();
         builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
         showSuggestions(builder.build(), alternatives.getOriginalWord());
     }
 
     private void showSuggestions(WordComposer word) {
-        // TODO Maybe need better way of retrieving previous word
+        // TODO: May need a better way of retrieving previous word
         CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
                 mWordSeparators);
         SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
                 mKeyboardSwitcher.getInputView(), word, prevWord);
 
-        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
-        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
-
-        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
-                && mSuggest.hasAutoCorrection();
+        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
         final CharSequence typedWord = word.getTypedWord();
-        // If we're in basic correct
-        final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
-                (preferCapitalization()
-                        && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
+        // Here, we want to promote a whitelisted word if exists.
+        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
+                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
         if (mCorrectionMode == Suggest.CORRECTION_FULL
                 || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
             correctionAvailable |= typedWordValid;
         }
         // Don't auto-correct words with multiple capital letter
         correctionAvailable &= !word.isMostlyCaps();
-        correctionAvailable &= !TextEntryState.isCorrecting();
+        correctionAvailable &= !TextEntryState.isRecorrecting();
 
         // Basically, we update the suggestion strip only when suggestion count > 1.  However,
         // there is an exception: We update the suggestion strip whenever typed word's length
@@ -1610,7 +1603,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mJustAccepted = true;
             pickSuggestion(mBestWord);
             // Add the word to the auto dictionary if it's not a known word
-            addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
+            addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
             return true;
 
         }
@@ -1619,9 +1612,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     public void pickSuggestionManually(int index, CharSequence suggestion) {
         SuggestedWords suggestions = mCandidateView.getSuggestions();
-        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
+        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
 
-        final boolean correcting = TextEntryState.isCorrecting();
+        final boolean recorrecting = TextEntryState.isRecorrecting();
         InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
             ic.beginBatchEdit();
@@ -1663,24 +1656,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         pickSuggestion(suggestion);
         // Add the word to the auto dictionary if it's not a known word
         if (index == 0) {
-            addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
+            addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
         } else {
-            addToBigramDictionary(suggestion, 1);
+            addToOnlyBigramDictionary(suggestion, 1);
         }
         LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
                 index, suggestions.mWords);
         TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
         // Follow it with a space
-        if (mAutoSpace && !correcting) {
+        if (mAutoSpace && !recorrecting) {
             sendSpace();
             mJustAddedAutoSpace = true;
         }
 
-        final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0
-                && !mSuggest.isValidWord(suggestion)
-                && !mSuggest.isValidWord(suggestion.toString().toLowerCase());
-
-        if (!correcting) {
+        // We should show the hint if the user pressed the first entry AND either:
+        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
+        //   AND mHasDictionary is false)
+        // - There is a dictionary and the word is not in it
+        // Please note that if mSuggest is null, it means that everything is off: suggestion
+        // and correction, so we shouldn't try to show the hint
+        // We used to look at mCorrectionMode here, but showing the hint should have nothing
+        // to do with the autocorrection setting.
+        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
+                // If there is no dictionary the hint should be shown.
+                && (!mHasDictionary
+                        // If "suggestion" is not in the dictionary, the hint should be shown.
+                        || !AutoCorrection.isValidWord(
+                                mSuggest.getUnigramDictionaries(), suggestion, true));
+
+        if (!recorrecting) {
             // Fool the state watcher so that a subsequent backspace will not do a revert, unless
             // we just did a correction, in which case we need to stay in
             // TextEntryState.State.PICKED_SUGGESTION state.
@@ -1712,13 +1716,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             return;
         InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
-            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
+            mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators);
             ic.commitText(suggestion, 1);
         }
         saveWordInHistory(suggestion);
         mHasValidSuggestions = false;
         mCommittedLength = suggestion.length();
-        switcher.setPreferredLetters(null);
     }
 
     /**
@@ -1731,31 +1734,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         // If we didn't find a match, search for result in typed word history
         WordComposer foundWord = null;
         WordAlternatives alternatives = null;
+        // Search old suggestions to suggest re-corrected suggestions.
         for (WordAlternatives entry : mWordHistory) {
             if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
-                if (entry instanceof TypedWordAlternatives) {
-                    foundWord = ((TypedWordAlternatives) entry).word;
-                }
+                foundWord = entry.mWordComposer;
                 alternatives = entry;
                 break;
             }
         }
-        // If we didn't find a match, at least suggest corrections.
+        // If we didn't find a match, at least suggest corrections as re-corrected suggestions.
         if (foundWord == null
-                && (mSuggest.isValidWord(touching.mWord)
-                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
+                && (AutoCorrection.isValidWord(
+                        mSuggest.getUnigramDictionaries(), touching.mWord, true))) {
             foundWord = new WordComposer();
             for (int i = 0; i < touching.mWord.length(); i++) {
                 foundWord.add(touching.mWord.charAt(i), new int[] {
                     touching.mWord.charAt(i)
-                });
+                }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
             }
             foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
         }
         // Found a match, show suggestions
         if (foundWord != null || alternatives != null) {
             if (alternatives == null) {
-                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
+                alternatives = new WordAlternatives(touching.mWord, foundWord);
             }
             showCorrections(alternatives);
             if (foundWord != null) {
@@ -1769,7 +1771,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void setOldSuggestions() {
-        mVoiceConnector.setShowingVoiceSuggestions(false);
+        mVoiceProxy.setShowingVoiceSuggestions(false);
         if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
             return;
         }
@@ -1783,21 +1785,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             if (touching != null && touching.mWord.length() > 1) {
                 ic.beginBatchEdit();
 
-                if (!mVoiceConnector.applyVoiceAlternatives(touching)
+                if (!mVoiceProxy.applyVoiceAlternatives(touching)
                         && !applyTypedAlternatives(touching)) {
-                    abortCorrection(true);
+                    abortRecorrection(true);
                 } else {
-                    TextEntryState.selectedForCorrection();
+                    TextEntryState.selectedForRecorrection();
                     EditingUtils.underlineWord(ic, touching);
                 }
 
                 ic.endBatchEdit();
             } else {
-                abortCorrection(true);
+                abortRecorrection(true);
                 setPunctuationSuggestions();  // Show the punctuation suggestions list
             }
         } else {
-            abortCorrection(true);
+            abortRecorrection(true);
         }
     }
 
@@ -1806,21 +1808,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         setCandidatesViewShown(isCandidateStripVisible());
     }
 
-    private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
+    private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
         checkAddToDictionary(suggestion, frequencyDelta, false);
     }
 
-    private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
+    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
         checkAddToDictionary(suggestion, frequencyDelta, true);
     }
 
     /**
      * Adds to the UserBigramDictionary and/or AutoDictionary
-     * @param addToBigramDictionary true if it should be added to bigram dictionary if possible
+     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
      */
     private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
-            boolean addToBigramDictionary) {
+            boolean selectedANotTypedWord) {
         if (suggestion == null || suggestion.length() < 1) return;
+
         // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
         // adding words in situations where the user or application really didn't
         // want corrections enabled or learned.
@@ -1828,9 +1831,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
             return;
         }
-        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
-                || (!mSuggest.isValidWord(suggestion.toString())
-                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
+
+        final boolean selectedATypedWordAndItsInAutoDic =
+                !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
+        final boolean isValidWord = AutoCorrection.isValidWord(
+                mSuggest.getUnigramDictionaries(), suggestion, true);
+        final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
+                || !isValidWord;
+        if (needsToAddToAutoDictionary) {
             mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
         }
 
@@ -1870,7 +1878,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         final int length = mComposing.length();
         if (!mHasValidSuggestions && length > 0) {
             final InputConnection ic = getCurrentInputConnection();
-            mJustReverted = true;
             final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
             if (deleteChar) ic.deleteSurroundingText(1, 0);
             int toDelete = mCommittedLength;
@@ -1898,7 +1905,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mHandler.postUpdateSuggestions();
         } else {
             sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
-            mJustReverted = false;
         }
     }
 
@@ -1936,28 +1942,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mSubtypeSwitcher.toggleLanguage(reset, next);
         }
         // Reload keyboard because the current language has been changed.
-        KeyboardSwitcher switcher = mKeyboardSwitcher;
-        final EditorInfo attribute = getCurrentInputEditorInfo();
-        final int mode = initializeInputAttributesAndGetMode((attribute != null)
-                ? attribute.inputType : 0);
-        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
-        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
-                mVoiceConnector.isVoiceButtonOnPrimary());
+        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
+                mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
+                mVoiceProxy.isVoiceButtonOnPrimary());
         initSuggest();
-        switcher.updateShiftState();
-    }
-
-    @Override
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
-            String key) {
-        mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
-        if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
-            mRefreshKeyboardRequired = true;
-        } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
-            mReCorrectionEnabled = sharedPreferences.getBoolean(
-                    Settings.PREF_RECORRECTION_ENABLED,
-                    mResources.getBoolean(R.bool.config_default_recorrection_enabled));
-        }
+        mKeyboardSwitcher.updateShiftState();
     }
 
     @Override
@@ -1967,7 +1956,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     @Override
-    public void onPress(int primaryCode) {
+    public void onPress(int primaryCode, boolean withSliding) {
         if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
             vibrate();
             playKeyClick(primaryCode);
@@ -1975,25 +1964,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         KeyboardSwitcher switcher = mKeyboardSwitcher;
         final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
         if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
-            switcher.onPressShift();
+            switcher.onPressShift(withSliding);
         } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
             switcher.onPressSymbol();
         } else {
             switcher.onOtherKeyPressed();
         }
+        mAccessibilityUtils.onPress(primaryCode, switcher);
     }
 
     @Override
-    public void onRelease(int primaryCode) {
+    public void onRelease(int primaryCode, boolean withSliding) {
         KeyboardSwitcher switcher = mKeyboardSwitcher;
         // Reset any drag flags in the keyboard
         switcher.keyReleased();
         final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
         if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
-            switcher.onReleaseShift();
+            switcher.onReleaseShift(withSliding);
         } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
             switcher.onReleaseSymbol();
         }
+        mAccessibilityUtils.onRelease(primaryCode, switcher);
     }
 
 
@@ -2073,6 +2064,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     }
 
     private void updateCorrectionMode() {
+        // TODO: cleanup messy flags
         mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
         mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
                 && !mInputTypeNoAutoCorrect && mHasDictionary;
@@ -2124,10 +2116,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private void loadSettings(EditorInfo attribute) {
         // Get the settings preferences
         final SharedPreferences prefs = mPrefs;
-        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
-        // @@@ mVibrateOn = vibrator != null && vibrator.hasVibrator()
-        mVibrateOn = vibrator != null
-                && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
+        final boolean hasVibrator = VibratorCompatWrapper.getInstance(this).hasVibrator();
+        mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
         mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
                 mResources.getBoolean(R.bool.config_default_sound_enabled));
 
@@ -2139,7 +2129,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
         loadAndSetAutoCorrectionThreshold(prefs);
 
-        mVoiceConnector.loadSettings(attribute, prefs);
+        mVoiceProxy.loadSettings(attribute, prefs);
 
         updateCorrectionMode();
         updateAutoTextEnabled();
@@ -2250,13 +2240,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 di.dismiss();
                 switch (position) {
                 case 0:
-                    Intent intent = new Intent(
-                            android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
+                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
                             | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                             | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                    intent.putExtra(android.provider.Settings.EXTRA_INPUT_METHOD_ID,
-                            mInputMethodId);
                     startActivity(intent);
                     break;
                 case 1:
@@ -2293,6 +2280,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
     private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
             DialogInterface.OnClickListener listener) {
+        final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken();
+        if (windowToken == null) return;
         AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setCancelable(true);
         builder.setIcon(R.drawable.ic_dialog_keyboard);
@@ -2303,7 +2292,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mOptionsDialog.setCanceledOnTouchOutside(true);
         Window window = mOptionsDialog.getWindow();
         WindowManager.LayoutParams lp = window.getAttributes();
-        lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
+        lp.token = windowToken;
         lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
         window.setAttributes(lp);
         window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
@@ -2347,8 +2336,4 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
         System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
     }
-
-    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
-        SubtypeSwitcher.getInstance().updateSubtype(subtype);
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/PrivateBinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/PrivateBinaryDictionaryGetter.java
new file mode 100644
index 0000000000000000000000000000000000000000..90726b0d8e5bfe2fda2df469115dedb43b5d1a6e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/PrivateBinaryDictionaryGetter.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+
+import java.util.Locale;
+
+class PrivateBinaryDictionaryGetter {
+    private PrivateBinaryDictionaryGetter() {}
+    public static AssetFileAddress getDictionaryFile(Locale locale, Context context) {
+        return null;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 59c68f20863a81498558276faa9b1de9adbe5182..488ab09c3dd02ea98b4c2e726b33a8d190800290 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -16,17 +16,17 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.voice.VoiceIMEConnector;
-import com.android.inputmethod.voice.VoiceInputLogger;
+import com.android.inputmethod.compat.CompatUtils;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.deprecated.VoiceProxy;
+import com.android.inputmethod.compat.VibratorCompatWrapper;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.backup.BackupManager;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
-import android.os.Vibrator;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.Preference;
@@ -82,7 +82,7 @@ public class Settings extends PreferenceActivity
 
     private AlertDialog mDialog;
 
-    private VoiceInputLogger mLogger;
+    private VoiceProxy.VoiceLoggerWrapper mVoiceLogger;
 
     private boolean mOkClicked = false;
     private String mVoiceModeOff;
@@ -111,7 +111,7 @@ public class Settings extends PreferenceActivity
         mVoiceModeOff = getString(R.string.voice_mode_off);
         mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
                 .equals(mVoiceModeOff));
-        mLogger = VoiceInputLogger.getLogger(this);
+        mVoiceLogger = VoiceProxy.VoiceLoggerWrapper.getInstance(this);
 
         mAutoCorrectionThreshold = (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
         mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
@@ -134,10 +134,7 @@ public class Settings extends PreferenceActivity
             generalSettings.removePreference(mVoicePreference);
         }
 
-        Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
-        if (vibrator == null
-        // @@@    || !vibrator.hasVibrator()
-        ) {
+        if (!VibratorCompatWrapper.getInstance(this).hasVibrator()) {
             generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
         }
 
@@ -186,7 +183,7 @@ public class Settings extends PreferenceActivity
             ((PreferenceGroup) findPreference(PREF_PREDICTION_SETTINGS_KEY))
                     .removePreference(mQuickFixes);
         }
-        if (!VoiceIMEConnector.VOICE_INSTALLED
+        if (!VoiceProxy.VOICE_INSTALLED
                 || !SpeechRecognizer.isRecognitionAvailable(this)) {
             getPreferenceScreen().removePreference(mVoicePreference);
         } else {
@@ -224,16 +221,9 @@ public class Settings extends PreferenceActivity
     @Override
     public boolean onPreferenceClick(Preference pref) {
         if (pref == mInputLanguageSelection) {
-            final String action;
-            if (android.os.Build.VERSION.SDK_INT
-                    >= /* android.os.Build.VERSION_CODES.HONEYCOMB */ 11) {
-                // Refer to android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS
-                // TODO: Can this be a constant instead of literal String constant?
-                action = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
-            } else {
-                action = "com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION";
-            }
-            startActivity(new Intent(action));
+            startActivity(CompatUtils.getInputLanguageSelectionIntent(
+                    Utils.getInputMethodId(InputMethodManagerCompatWrapper.getInstance(this),
+                            getApplicationInfo().packageName), 0));
             return true;
         }
         return false;
@@ -279,10 +269,10 @@ public class Settings extends PreferenceActivity
                     public void onClick(DialogInterface dialog, int whichButton) {
                         if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
                             mVoicePreference.setValue(mVoiceModeOff);
-                            mLogger.settingsWarningDialogCancel();
+                            mVoiceLogger.settingsWarningDialogCancel();
                         } else if (whichButton == DialogInterface.BUTTON_POSITIVE) {
                             mOkClicked = true;
-                            mLogger.settingsWarningDialogOk();
+                            mVoiceLogger.settingsWarningDialogOk();
                         }
                         updateVoicePreference();
                     }
@@ -313,7 +303,7 @@ public class Settings extends PreferenceActivity
                 AlertDialog dialog = builder.create();
                 mDialog = dialog;
                 dialog.setOnDismissListener(this);
-                mLogger.settingsWarningDialogShown();
+                mVoiceLogger.settingsWarningDialogShown();
                 return dialog;
             default:
                 Log.e(TAG, "unknown dialog " + id);
@@ -323,7 +313,7 @@ public class Settings extends PreferenceActivity
 
     @Override
     public void onDismiss(DialogInterface dialog) {
-        mLogger.settingsWarningDialogDismissed();
+        mVoiceLogger.settingsWarningDialogDismissed();
         if (!mOkClicked) {
             // This assumes that onPreferenceClick gets called first, and this if the user
             // agreed after the warning, we set the mOkClicked value to true.
@@ -333,10 +323,6 @@ public class Settings extends PreferenceActivity
 
     private void updateVoicePreference() {
         boolean isChecked = !mVoicePreference.getValue().equals(mVoiceModeOff);
-        if (isChecked) {
-            mLogger.voiceInputSettingEnabled();
-        } else {
-            mLogger.voiceInputSettingDisabled();
-        }
+        mVoiceLogger.voiceInputSettingEnabled(isChecked);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index f45c2b7f8e836f5d1cb3ea81bce0231856577a82..6610a65ef915a3a3159a9ad97b894fce7611371b 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -16,13 +16,12 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.compat.InputMethodSubtype;
+import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
+import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.keyboard.LatinKeyboard;
-import com.android.inputmethod.keyboard.LatinKeyboardView;
-import com.android.inputmethod.voice.SettingsUtil;
-import com.android.inputmethod.voice.VoiceIMEConnector;
-import com.android.inputmethod.voice.VoiceInput;
 
 import android.content.Context;
 import android.content.Intent;
@@ -33,11 +32,10 @@ import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.os.AsyncTask;
 import android.os.IBinder;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -47,7 +45,7 @@ import java.util.Map;
 
 public class SubtypeSwitcher {
     private static boolean DBG = LatinImeLogger.sDBG;
-    private static final String TAG = "SubtypeSwitcher";
+    private static final String TAG = SubtypeSwitcher.class.getSimpleName();
 
     private static final char LOCALE_SEPARATER = '_';
     private static final String KEYBOARD_MODE = "keyboard";
@@ -60,26 +58,27 @@ public class SubtypeSwitcher {
     private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
     private /* final */ LatinIME mService;
     private /* final */ SharedPreferences mPrefs;
-    private /* final */ InputMethodManager mImm;
+    private /* final */ InputMethodManagerCompatWrapper mImm;
     private /* final */ Resources mResources;
     private /* final */ ConnectivityManager mConnectivityManager;
     private /* final */ boolean mConfigUseSpacebarLanguageSwitcher;
-    private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod =
-            new ArrayList<InputMethodSubtype>();
+    private final ArrayList<InputMethodSubtypeCompatWrapper>
+            mEnabledKeyboardSubtypesOfCurrentInputMethod =
+                    new ArrayList<InputMethodSubtypeCompatWrapper>();
     private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
 
     /*-----------------------------------------------------------*/
     // Variants which should be changed only by reload functions.
     private boolean mNeedsToDisplayLanguage;
     private boolean mIsSystemLanguageSameAsInputLanguage;
-    private InputMethodInfo mShortcutInputMethodInfo;
-    private InputMethodSubtype mShortcutSubtype;
-    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
+    private InputMethodInfoCompatWrapper mShortcutInputMethodInfo;
+    private InputMethodSubtypeCompatWrapper mShortcutSubtype;
+    private List<InputMethodSubtypeCompatWrapper> mAllEnabledSubtypesOfCurrentInputMethod;
+    private InputMethodSubtypeCompatWrapper mCurrentSubtype;
     private Locale mSystemLocale;
     private Locale mInputLocale;
     private String mInputLocaleStr;
-    private String mMode;
-    private VoiceInput mVoiceInput;
+    private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper;
     /*-----------------------------------------------------------*/
 
     private boolean mIsNetworkConnected;
@@ -103,7 +102,7 @@ public class SubtypeSwitcher {
         mService = service;
         mPrefs = prefs;
         mResources = service.getResources();
-        mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mImm = InputMethodManagerCompatWrapper.getInstance(service);
         mConnectivityManager = (ConnectivityManager) service.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
@@ -111,11 +110,10 @@ public class SubtypeSwitcher {
         mSystemLocale = null;
         mInputLocale = null;
         mInputLocaleStr = null;
-        // Mode is initialized to KEYBOARD_MODE, in case that LatinIME can't obtain currentSubtype
-        mMode = KEYBOARD_MODE;
+        mCurrentSubtype = null;
         mAllEnabledSubtypesOfCurrentInputMethod = null;
         // TODO: Voice input should be created here
-        mVoiceInput = null;
+        mVoiceInputWrapper = null;
         mConfigUseSpacebarLanguageSwitcher = mResources.getBoolean(
                 R.bool.config_use_spacebar_language_switcher);
         if (mConfigUseSpacebarLanguageSwitcher)
@@ -129,7 +127,7 @@ public class SubtypeSwitcher {
     // Only configuration changed event is allowed to call this because this is heavy.
     private void updateAllParameters() {
         mSystemLocale = mResources.getConfiguration().locale;
-        // @@@ updateSubtype(mImm.getCurrentInputMethodSubtype());
+        updateSubtype(mImm.getCurrentInputMethodSubtype());
         updateParametersOnStartInputView();
     }
 
@@ -146,19 +144,20 @@ public class SubtypeSwitcher {
 
     // Reload enabledSubtypes from the framework.
     private void updateEnabledSubtypes() {
+        final String currentMode = getCurrentSubtypeMode();
         boolean foundCurrentSubtypeBecameDisabled = true;
-        // @@@ mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
-        //        null, true);
+        mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(
+                null, true);
         mEnabledLanguagesOfCurrentInputMethod.clear();
         mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
-        for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
+        for (InputMethodSubtypeCompatWrapper ims: mAllEnabledSubtypesOfCurrentInputMethod) {
             final String locale = ims.getLocale();
             final String mode = ims.getMode();
             mLocaleSplitter.setString(locale);
             if (mLocaleSplitter.hasNext()) {
                 mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next());
             }
-            if (locale.equals(mInputLocaleStr) && mode.equals(mMode)) {
+            if (locale.equals(mInputLocaleStr) && mode.equals(currentMode)) {
                 foundCurrentSubtypeBecameDisabled = false;
             }
             if (KEYBOARD_MODE.equals(ims.getMode())) {
@@ -169,10 +168,10 @@ public class SubtypeSwitcher {
                 && mIsSystemLanguageSameAsInputLanguage);
         if (foundCurrentSubtypeBecameDisabled) {
             if (DBG) {
-                Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + mMode);
+                Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + currentMode);
                 Log.w(TAG, "Last subtype was disabled. Update to the current one.");
             }
-            // @@@ updateSubtype(mImm.getCurrentInputMethodSubtype());
+            updateSubtype(mImm.getCurrentInputMethodSubtype());
         }
     }
 
@@ -185,11 +184,10 @@ public class SubtypeSwitcher {
                             + ", " + mShortcutSubtype.getMode())));
         }
         // TODO: Update an icon for shortcut IME
-        /*
-        Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts =
+        final Map<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>> shortcuts =
                 mImm.getShortcutInputMethodsAndSubtypes();
-        for (InputMethodInfo imi: shortcuts.keySet()) {
-            List<InputMethodSubtype> subtypes = shortcuts.get(imi);
+        for (InputMethodInfoCompatWrapper imi : shortcuts.keySet()) {
+            List<InputMethodSubtypeCompatWrapper> subtypes = shortcuts.get(imi);
             // TODO: Returns the first found IMI for now. Should handle all shortcuts as
             // appropriate.
             mShortcutInputMethodInfo = imi;
@@ -197,17 +195,24 @@ public class SubtypeSwitcher {
             // as appropriate.
             mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null;
             break;
-            }
-        */
+        }
+        if (DBG) {
+            Log.d(TAG, "Update shortcut IME to : "
+                    + (mShortcutInputMethodInfo == null
+                            ? "<null>" : mShortcutInputMethodInfo.getId()) + ", "
+                    + (mShortcutSubtype == null ? "<null>" : (mShortcutSubtype.getLocale()
+                            + ", " + mShortcutSubtype.getMode())));
+        }
     }
 
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
-    public void updateSubtype(InputMethodSubtype newSubtype) {
+    public void updateSubtype(InputMethodSubtypeCompatWrapper newSubtype) {
         final String newLocale;
         final String newMode;
-        if (newSubtype == null) {
+        final String oldMode = getCurrentSubtypeMode();
+        if (newSubtype == null || newSubtype.getOriginalObject() == null) {
             // Normally, newSubtype shouldn't be null. But just in case newSubtype was null,
-            // fallback to the default locale and mode.
+            // fallback to the default locale.
             Log.w(TAG, "Couldn't get the current subtype.");
             newLocale = "en_US";
             newMode = KEYBOARD_MODE;
@@ -217,7 +222,7 @@ public class SubtypeSwitcher {
         }
         if (DBG) {
             Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode
-                    + ", from: " + mInputLocaleStr + ", " + mMode);
+                    + ", from: " + mInputLocaleStr + ", " + oldMode);
         }
         boolean languageChanged = false;
         if (!newLocale.equals(mInputLocaleStr)) {
@@ -227,42 +232,41 @@ public class SubtypeSwitcher {
             updateInputLocale(newLocale);
         }
         boolean modeChanged = false;
-        String oldMode = mMode;
-        if (!newMode.equals(mMode)) {
-            if (mMode != null) {
+        if (!newMode.equals(oldMode)) {
+            if (oldMode != null) {
                 modeChanged = true;
             }
-            mMode = newMode;
         }
+        mCurrentSubtype = newSubtype;
 
         // If the old mode is voice input, we need to reset or cancel its status.
         // We cancel its status when we change mode, while we reset otherwise.
         if (isKeyboardMode()) {
             if (modeChanged) {
-                if (VOICE_MODE.equals(oldMode) && mVoiceInput != null) {
-                    mVoiceInput.cancel();
+                if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) {
+                    mVoiceInputWrapper.cancel();
                 }
             }
             if (modeChanged || languageChanged) {
                 updateShortcutIME();
                 mService.onRefreshKeyboard();
             }
-        } else if (isVoiceMode() && mVoiceInput != null) {
+        } else if (isVoiceMode() && mVoiceInputWrapper != null) {
             if (VOICE_MODE.equals(oldMode)) {
-                mVoiceInput.reset();
+                mVoiceInputWrapper.reset();
             }
             // If needsToShowWarningDialog is true, voice input need to show warning before
             // show recognition view.
             if (languageChanged || modeChanged
-                    || VoiceIMEConnector.getInstance().needsToShowWarningDialog()) {
+                    || VoiceProxy.getInstance().needsToShowWarningDialog()) {
                 triggerVoiceIME();
             }
         } else {
-            Log.w(TAG, "Unknown subtype mode: " + mMode);
-            if (VOICE_MODE.equals(oldMode) && mVoiceInput != null) {
+            Log.w(TAG, "Unknown subtype mode: " + newMode);
+            if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) {
                 // We need to reset the voice input to release the resources and to reset its status
                 // as it is not the current input mode.
-                mVoiceInput.reset();
+                mVoiceInputWrapper.reset();
             }
         }
     }
@@ -303,15 +307,34 @@ public class SubtypeSwitcher {
         if (token == null || mShortcutInputMethodInfo == null) {
             return;
         }
-        // @@@ mImm.setInputMethodAndSubtype(token, mShortcutInfo.getId(), mShortcutSubtype);
+        final String imiId = mShortcutInputMethodInfo.getId();
+        final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype;
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                mImm.setInputMethodAndSubtype(token, imiId, subtype);
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void result) {
+                // Calls in this method need to be done in the same thread as the thread which
+                // called switchToShortcutIME().
+
+                // Notify an event that the current subtype was changed. This event will be
+                // handled if "onCurrentInputMethodSubtypeChanged" can't be implemented
+                // when the API level is 10 or previous.
+                mService.notifyOnCurrentInputMethodSubtypeChanged(subtype);
+            }
+        }.execute();
     }
 
     public Drawable getShortcutIcon() {
         return getSubtypeIcon(mShortcutInputMethodInfo, mShortcutSubtype);
     }
 
-    private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
-        /*
+    private Drawable getSubtypeIcon(
+            InputMethodInfoCompatWrapper imi, InputMethodSubtypeCompatWrapper subtype) {
         final PackageManager pm = mService.getPackageManager();
         if (imi != null) {
             final String imiPackageName = imi.getPackageName();
@@ -333,8 +356,7 @@ public class SubtypeSwitcher {
                     Log.w(TAG, "IME can't be found: " + imiPackageName);
                 }
             }
-            }
-        */
+        }
         return null;
     }
 
@@ -346,11 +368,28 @@ public class SubtypeSwitcher {
         return false;
     }
 
-    public boolean isShortcutAvailable() {
+    public boolean isShortcutImeEnabled() {
+        if (mShortcutInputMethodInfo == null)
+            return false;
+        if (mShortcutSubtype == null)
+            return true;
+        final boolean allowsImplicitlySelectedSubtypes = true;
+        for (final InputMethodSubtypeCompatWrapper enabledSubtype :
+                mImm.getEnabledInputMethodSubtypeList(
+                        mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) {
+            if (enabledSubtype.equals(mShortcutSubtype))
+                return true;
+        }
+        return false;
+    }
+
+    public boolean isShortcutImeReady() {
         if (mShortcutInputMethodInfo == null)
             return false;
-        if (mShortcutSubtype != null && contains(mShortcutSubtype.getExtraValue().split(","),
-                    SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) {
+        if (mShortcutSubtype == null)
+            return true;
+        if (contains(mShortcutSubtype.getExtraValue().split(","),
+                SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) {
             return mIsNetworkConnected;
         }
         return true;
@@ -361,12 +400,10 @@ public class SubtypeSwitcher {
                 ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
         mIsNetworkConnected = !noConnection;
 
-        final LatinKeyboardView inputView = KeyboardSwitcher.getInstance().getInputView();
-        if (inputView != null) {
-            final LatinKeyboard keyboard = inputView.getLatinKeyboard();
-            if (keyboard != null) {
-                keyboard.updateShortcutKey(isShortcutAvailable(), inputView);
-            }
+        final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
+        final LatinKeyboard keyboard = switcher.getLatinKeyboard();
+        if (keyboard != null) {
+            keyboard.updateShortcutKey(isShortcutImeReady(), switcher.getInputView());
         }
     }
 
@@ -462,14 +499,6 @@ public class SubtypeSwitcher {
         }
     }
 
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-        if (mConfigUseSpacebarLanguageSwitcher) {
-            if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
-                mLanguageSwitcher.loadLocales(sharedPreferences);
-            }
-        }
-    }
-
     /**
      * Change system locale for this application
      * @param newLocale
@@ -484,7 +513,7 @@ public class SubtypeSwitcher {
     }
 
     public boolean isKeyboardMode() {
-        return KEYBOARD_MODE.equals(mMode);
+        return KEYBOARD_MODE.equals(getCurrentSubtypeMode());
     }
 
 
@@ -492,9 +521,9 @@ public class SubtypeSwitcher {
     // Voice Input functions //
     ///////////////////////////
 
-    public boolean setVoiceInput(VoiceInput vi) {
-        if (mVoiceInput == null && vi != null) {
-            mVoiceInput = vi;
+    public boolean setVoiceInputWrapper(VoiceProxy.VoiceInputWrapper vi) {
+        if (mVoiceInputWrapper == null && vi != null) {
+            mVoiceInputWrapper = vi;
             if (isVoiceMode()) {
                 if (DBG) {
                     Log.d(TAG, "Set and call voice input.: " + getInputLocaleStr());
@@ -507,12 +536,12 @@ public class SubtypeSwitcher {
     }
 
     public boolean isVoiceMode() {
-        return VOICE_MODE.equals(mMode);
+        return null == mCurrentSubtype ? false : VOICE_MODE.equals(getCurrentSubtypeMode());
     }
 
     private void triggerVoiceIME() {
         if (!mService.isInputViewShown()) return;
-        VoiceIMEConnector.getInstance().startListening(false,
+        VoiceProxy.getInstance().startListening(false,
                 KeyboardSwitcher.getInstance().getInputView().getWindowToken());
     }
 
@@ -573,19 +602,29 @@ public class SubtypeSwitcher {
         }
     }
 
-    // A list of locales which are supported by default for voice input, unless we get a
-    // different list from Gservices.
-    private static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
-            "en " +
-            "en_US " +
-            "en_GB " +
-            "en_AU " +
-            "en_CA " +
-            "en_IE " +
-            "en_IN " +
-            "en_NZ " +
-            "en_SG " +
-            "en_ZA ";
+    /////////////////////////////
+    // Other utility functions //
+    /////////////////////////////
+
+    public String getCurrentSubtypeExtraValue() {
+        // If null, return what an empty ExtraValue would return : the empty string.
+        return null != mCurrentSubtype ? mCurrentSubtype.getExtraValue() : "";
+    }
+
+    public boolean currentSubtypeContainsExtraValueKey(String key) {
+        // If null, return what an empty ExtraValue would return : false.
+        return null != mCurrentSubtype ? mCurrentSubtype.containsExtraValueKey(key) : false;
+    }
+
+    public String getCurrentSubtypeExtraValueOf(String key) {
+        // If null, return what an empty ExtraValue would return : null.
+        return null != mCurrentSubtype ? mCurrentSubtype.getExtraValueOf(key) : null;
+    }
+
+    public String getCurrentSubtypeMode() {
+        return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE;
+    }
+
 
     public boolean isVoiceSupported(String locale) {
         // Get the current list of supported locales and check the current locale against that
@@ -593,10 +632,8 @@ public class SubtypeSwitcher {
         // input. Because this method is called by onStartInputView, this should mean that as
         // long as the locale doesn't change while the user is keeping the IME open, the
         // value should never be stale.
-        String supportedLocalesString = SettingsUtil.getSettingsString(
-                mService.getContentResolver(),
-                SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
-                DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
+        String supportedLocalesString = VoiceProxy.getSupportedLocalesString(
+                mService.getContentResolver());
         List<String> voiceInputSupportedLocales = Arrays.asList(
                 supportedLocalesString.split("\\s+"));
         return voiceInputSupportedLocales.contains(locale);
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index c9e57d0a5dc45c1993968692ec38efe8a7cacd8e..0cc9d4198f343545ee9ee4dccfd62a3db9bf9cde 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -25,6 +25,11 @@ import android.view.View;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * This class loads a dictionary and provides a list of suggestions for a given sequence of
@@ -43,7 +48,7 @@ public class Suggest implements Dictionary.WordCallback {
 
     /**
      * Words that appear in both bigram and unigram data gets multiplier ranging from
-     * BIGRAM_MULTIPLIER_MIN to BIGRAM_MULTIPLIER_MAX depending on the frequency score from
+     * BIGRAM_MULTIPLIER_MIN to BIGRAM_MULTIPLIER_MAX depending on the score from
      * bigram data.
      */
     public static final double BIGRAM_MULTIPLIER_MIN = 1.2;
@@ -63,19 +68,23 @@ public class Suggest implements Dictionary.WordCallback {
     // If you add a type of dictionary, increment DIC_TYPE_LAST_ID
     public static final int DIC_TYPE_LAST_ID = 4;
 
+    public static final String DICT_KEY_MAIN = "main";
+    public static final String DICT_KEY_CONTACTS = "contacts";
+    public static final String DICT_KEY_AUTO = "auto";
+    public static final String DICT_KEY_USER = "user";
+    public static final String DICT_KEY_USER_BIGRAM = "user_bigram";
+    public static final String DICT_KEY_WHITELIST ="whitelist";
+
     static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
 
     private static final boolean DBG = LatinImeLogger.sDBG;
 
-    private BinaryDictionary mMainDict;
-
-    private Dictionary mUserDictionary;
-
-    private Dictionary mAutoDictionary;
-
-    private Dictionary mContactsDictionary;
+    private AutoCorrection mAutoCorrection;
 
-    private Dictionary mUserBigramDictionary;
+    private BinaryDictionary mMainDict;
+    private WhitelistDictionary mWhiteListDictionary;
+    private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>();
+    private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>();
 
     private int mPrefMaxSuggestions = 12;
 
@@ -84,20 +93,13 @@ public class Suggest implements Dictionary.WordCallback {
     private boolean mQuickFixesEnabled;
 
     private double mAutoCorrectionThreshold;
-    private int[] mPriorities = new int[mPrefMaxSuggestions];
-    private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS];
-
-    // Handle predictive correction for only the first 1280 characters for performance reasons
-    // If we support scripts that need latin characters beyond that, we should probably use some
-    // kind of a sparse array or language specific list with a mapping lookup table.
-    // 1280 is the size of the BASE_CHARS array in ExpandableDictionary, which is a basic set of
-    // latin characters.
-    private int[] mNextLettersFrequencies = new int[1280];
+    private int[] mScores = new int[mPrefMaxSuggestions];
+    private int[] mBigramScores = new int[PREF_MAX_BIGRAMS];
+
     private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
     ArrayList<CharSequence> mBigramSuggestions  = new ArrayList<CharSequence>();
     private ArrayList<CharSequence> mStringPool = new ArrayList<CharSequence>();
-    private boolean mHasAutoCorrection;
-    private String mLowerOriginalWord;
+    private CharSequence mTypedWord;
 
     // TODO: Remove these member variables by passing more context to addWord() callback method
     private boolean mIsFirstCharCapitalized;
@@ -105,17 +107,44 @@ public class Suggest implements Dictionary.WordCallback {
 
     private int mCorrectionMode = CORRECTION_BASIC;
 
-    public Suggest(Context context, int dictionaryResId) {
-        mMainDict = BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN);
-        initPool();
+    public Suggest(Context context, int dictionaryResId, Locale locale) {
+        init(context, BinaryDictionary.initDictionaryFromManager(context, DIC_MAIN, locale,
+                dictionaryResId));
+    }
+
+    /* package for test */ Suggest(File dictionary, long startOffset, long length,
+            BinaryDictionary.Flag[] flagArray) {
+        init(null, BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN,
+                flagArray));
     }
 
-    // For unit test
-    /* package */ Suggest(File dictionary, long startOffset, long length) {
-        mMainDict = BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN);
+    private void init(Context context, BinaryDictionary mainDict) {
+        if (mainDict != null) {
+            mMainDict = mainDict;
+            mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict);
+            mBigramDictionaries.put(DICT_KEY_MAIN, mainDict);
+        }
+        mWhiteListDictionary = WhitelistDictionary.init(context);
+        if (mWhiteListDictionary != null) {
+            mUnigramDictionaries.put(DICT_KEY_WHITELIST, mWhiteListDictionary);
+        }
+        mAutoCorrection = new AutoCorrection();
         initPool();
     }
 
+    public void resetMainDict(Context context, int dictionaryResId, Locale locale) {
+        final BinaryDictionary newMainDict = BinaryDictionary.initDictionaryFromManager(context,
+                DIC_MAIN, locale, dictionaryResId);
+        mMainDict = newMainDict;
+        if (null == newMainDict) {
+            mUnigramDictionaries.remove(DICT_KEY_MAIN);
+            mBigramDictionaries.remove(DICT_KEY_MAIN);
+        } else {
+            mUnigramDictionaries.put(DICT_KEY_MAIN, newMainDict);
+            mBigramDictionaries.put(DICT_KEY_MAIN, newMainDict);
+        }
+    }
+
     private void initPool() {
         for (int i = 0; i < mPrefMaxSuggestions; i++) {
             StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
@@ -139,6 +168,10 @@ public class Suggest implements Dictionary.WordCallback {
         return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
     }
 
+    public Map<String, Dictionary> getUnigramDictionaries() {
+        return mUnigramDictionaries;
+    }
+
     public int getApproxMaxWordLength() {
         return APPROX_MAX_WORD_LENGTH;
     }
@@ -148,22 +181,28 @@ public class Suggest implements Dictionary.WordCallback {
      * before the main dictionary, if set.
      */
     public void setUserDictionary(Dictionary userDictionary) {
-        mUserDictionary = userDictionary;
+        if (userDictionary != null)
+            mUnigramDictionaries.put(DICT_KEY_USER, userDictionary);
     }
 
     /**
      * Sets an optional contacts dictionary resource to be loaded.
      */
-    public void setContactsDictionary(Dictionary userDictionary) {
-        mContactsDictionary = userDictionary;
+    public void setContactsDictionary(Dictionary contactsDictionary) {
+        if (contactsDictionary != null) {
+            mUnigramDictionaries.put(DICT_KEY_CONTACTS, contactsDictionary);
+            mBigramDictionaries.put(DICT_KEY_CONTACTS, contactsDictionary);
+        }
     }
 
     public void setAutoDictionary(Dictionary autoDictionary) {
-        mAutoDictionary = autoDictionary;
+        if (autoDictionary != null)
+            mUnigramDictionaries.put(DICT_KEY_AUTO, autoDictionary);
     }
 
     public void setUserBigramDictionary(Dictionary userBigramDictionary) {
-        mUserBigramDictionary = userBigramDictionary;
+        if (userBigramDictionary != null)
+            mBigramDictionaries.put(DICT_KEY_USER_BIGRAM, userBigramDictionary);
     }
 
     public void setAutoCorrectionThreshold(double threshold) {
@@ -185,8 +224,8 @@ public class Suggest implements Dictionary.WordCallback {
             throw new IllegalArgumentException("maxSuggestions must be between 1 and 100");
         }
         mPrefMaxSuggestions = maxSuggestions;
-        mPriorities = new int[mPrefMaxSuggestions];
-        mBigramPriorities = new int[PREF_MAX_BIGRAMS];
+        mScores = new int[mPrefMaxSuggestions];
+        mBigramScores = new int[PREF_MAX_BIGRAMS];
         collectGarbage(mSuggestions, mPrefMaxSuggestions);
         while (mStringPool.size() < mPrefMaxSuggestions) {
             StringBuilder sb = new StringBuilder(getApproxMaxWordLength());
@@ -207,35 +246,50 @@ public class Suggest implements Dictionary.WordCallback {
         return getSuggestedWordBuilder(view, wordComposer, prevWordForBigram).build();
     }
 
+    private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) {
+        if (TextUtils.isEmpty(word) || !(all || first)) return word;
+        final int wordLength = word.length();
+        final int poolSize = mStringPool.size();
+        final StringBuilder sb =
+                poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
+                        : new StringBuilder(getApproxMaxWordLength());
+        sb.setLength(0);
+        if (all) {
+            sb.append(word.toString().toUpperCase());
+        } else if (first) {
+            sb.append(Character.toUpperCase(word.charAt(0)));
+            if (wordLength > 1) {
+                sb.append(word.subSequence(1, wordLength));
+            }
+        }
+        return sb;
+    }
+
     // TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
     public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
             CharSequence prevWordForBigram) {
         LatinImeLogger.onStartSuggestion(prevWordForBigram);
-        mHasAutoCorrection = false;
+        mAutoCorrection.init();
         mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
         mIsAllUpperCase = wordComposer.isAllUpperCase();
         collectGarbage(mSuggestions, mPrefMaxSuggestions);
-        Arrays.fill(mPriorities, 0);
-        Arrays.fill(mNextLettersFrequencies, 0);
+        Arrays.fill(mScores, 0);
 
         // Save a lowercase version of the original word
         CharSequence typedWord = wordComposer.getTypedWord();
         if (typedWord != null) {
             final String typedWordString = typedWord.toString();
             typedWord = typedWordString;
-            mLowerOriginalWord = typedWordString.toLowerCase();
             // Treating USER_TYPED as UNIGRAM suggestion for logging now.
             LatinImeLogger.onAddSuggestedWord(typedWordString, Suggest.DIC_USER_TYPED,
                     Dictionary.DataType.UNIGRAM);
-        } else {
-            mLowerOriginalWord = "";
         }
+        mTypedWord = typedWord;
 
-        double normalizedScore = Integer.MIN_VALUE;
         if (wordComposer.size() == 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
                 || mCorrectionMode == CORRECTION_BASIC)) {
             // At first character typed, search only the bigrams
-            Arrays.fill(mBigramPriorities, 0);
+            Arrays.fill(mBigramScores, 0);
             collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS);
 
             if (!TextUtils.isEmpty(prevWordForBigram)) {
@@ -243,17 +297,8 @@ public class Suggest implements Dictionary.WordCallback {
                 if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) {
                     prevWordForBigram = lowerPrevWord;
                 }
-                if (mUserBigramDictionary != null) {
-                    mUserBigramDictionary.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
-                }
-                if (mContactsDictionary != null) {
-                    mContactsDictionary.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
-                }
-                if (mMainDict != null) {
-                    mMainDict.getBigrams(wordComposer, prevWordForBigram, this,
-                            mNextLettersFrequencies);
+                for (final Dictionary dictionary : mBigramDictionaries.values()) {
+                    dictionary.getBigrams(wordComposer, prevWordForBigram, this);
                 }
                 char currentChar = wordComposer.getTypedWord().charAt(0);
                 char currentCharUpper = Character.toUpperCase(currentChar);
@@ -276,120 +321,85 @@ public class Suggest implements Dictionary.WordCallback {
 
         } else if (wordComposer.size() > 1) {
             // At second character typed, search the unigrams (scores being affected by bigrams)
-            if (mUserDictionary != null || mContactsDictionary != null) {
-                if (mUserDictionary != null) {
-                    mUserDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
-                }
-                if (mContactsDictionary != null) {
-                    mContactsDictionary.getWords(wordComposer, this, mNextLettersFrequencies);
-                }
-
-                if (mSuggestions.size() > 0 && isValidWord(typedWord)
-                        && (mCorrectionMode == CORRECTION_FULL
-                        || mCorrectionMode == CORRECTION_FULL_BIGRAM)) {
-                    if (DBG) {
-                        Log.d(TAG, "Auto corrected by CORRECTION_FULL.");
-                    }
-                    mHasAutoCorrection = true;
-                }
-            }
-            if (mMainDict != null) mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
-            if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
-                    && mSuggestions.size() > 0 && mPriorities.length > 0) {
-                // TODO: when the normalized score of the first suggestion is nearly equals to
-                //       the normalized score of the second suggestion, behave less aggressive.
-                normalizedScore = Utils.calcNormalizedScore(
-                        typedWord, mSuggestions.get(0), mPriorities[0]);
-                if (DBG) {
-                    Log.d(TAG, "Normalized " + typedWord + "," + mSuggestions.get(0) + ","
-                            + mPriorities[0] + ", " + normalizedScore
-                            + "(" + mAutoCorrectionThreshold + ")");
-                }
-                if (normalizedScore >= mAutoCorrectionThreshold) {
-                    if (DBG) {
-                        Log.d(TAG, "Auto corrected by S-threthhold.");
-                    }
-                    mHasAutoCorrection = true;
-                }
+            for (final String key : mUnigramDictionaries.keySet()) {
+                // Skip AutoDictionary and WhitelistDictionary to lookup
+                if (key.equals(DICT_KEY_AUTO) || key.equals(DICT_KEY_WHITELIST))
+                    continue;
+                final Dictionary dictionary = mUnigramDictionaries.get(key);
+                dictionary.getWords(wordComposer, this);
             }
         }
+        CharSequence autoText = null;
+        final String typedWordString = typedWord == null ? null : typedWord.toString();
         if (typedWord != null) {
-            mSuggestions.add(0, typedWord.toString());
-        }
-        if (mQuickFixesEnabled) {
-            int i = 0;
-            int max = 6;
-            // Don't autotext the suggestions from the dictionaries
-            if (mCorrectionMode == CORRECTION_BASIC) max = 1;
-            while (i < mSuggestions.size() && i < max) {
-                String suggestedWord = mSuggestions.get(i).toString().toLowerCase();
-                CharSequence autoText =
-                        AutoText.get(suggestedWord, 0, suggestedWord.length(), view);
+            // Apply quick fix only for the typed word.
+            if (mQuickFixesEnabled) {
+                final String lowerCaseTypedWord = typedWordString.toLowerCase();
+                CharSequence tempAutoText = capitalizeWord(
+                        mIsAllUpperCase, mIsFirstCharCapitalized, AutoText.get(
+                                lowerCaseTypedWord, 0, lowerCaseTypedWord.length(), view));
+                // TODO: cleanup canAdd
                 // Is there an AutoText (also known as Quick Fixes) correction?
-                boolean canAdd = autoText != null;
                 // Capitalize as needed
-                final int autoTextLength = autoText != null ? autoText.length() : 0;
-                if (autoTextLength > 0 && (mIsAllUpperCase || mIsFirstCharCapitalized)) {
-                    int poolSize = mStringPool.size();
-                    StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(
-                            poolSize - 1) : new StringBuilder(getApproxMaxWordLength());
-                    sb.setLength(0);
-                    if (mIsAllUpperCase) {
-                        sb.append(autoText.toString().toUpperCase());
-                    } else if (mIsFirstCharCapitalized) {
-                        sb.append(Character.toUpperCase(autoText.charAt(0)));
-                        if (autoTextLength > 1) {
-                            sb.append(autoText.subSequence(1, autoTextLength));
-                        }
-                    }
-                    autoText = sb.toString();
-                }
+                boolean canAdd = tempAutoText != null;
                 // Is that correction already the current prediction (or original word)?
-                canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i));
+                canAdd &= !TextUtils.equals(tempAutoText, typedWord);
                 // Is that correction already the next predicted word?
-                if (canAdd && i + 1 < mSuggestions.size() && mCorrectionMode != CORRECTION_BASIC) {
-                    canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i + 1));
+                if (canAdd && mSuggestions.size() > 0 && mCorrectionMode != CORRECTION_BASIC) {
+                    canAdd &= !TextUtils.equals(tempAutoText, mSuggestions.get(0));
                 }
                 if (canAdd) {
                     if (DBG) {
                         Log.d(TAG, "Auto corrected by AUTOTEXT.");
                     }
-                    mHasAutoCorrection = true;
-                    mSuggestions.add(i + 1, autoText);
-                    i++;
+                    autoText = tempAutoText;
                 }
-                i++;
             }
         }
+
+        CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized,
+                mWhiteListDictionary.getWhiteListedWord(typedWordString));
+
+        mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
+                mSuggestions, mScores, typedWord, mAutoCorrectionThreshold, mCorrectionMode,
+                autoText, whitelistedWord);
+
+        if (autoText != null) {
+            mSuggestions.add(0, autoText);
+        }
+
+        if (whitelistedWord != null) {
+            mSuggestions.add(0, whitelistedWord);
+        }
+
+        if (typedWord != null) {
+            mSuggestions.add(0, typedWordString);
+        }
         removeDupes();
+
         if (DBG) {
-            ArrayList<SuggestedWords.SuggestedWordInfo> frequencyInfoList =
+            double normalizedScore = mAutoCorrection.getNormalizedScore();
+            ArrayList<SuggestedWords.SuggestedWordInfo> scoreInfoList =
                     new ArrayList<SuggestedWords.SuggestedWordInfo>();
-            frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("+", false));
-            final int priorityLength = mPriorities.length;
-            for (int i = 0; i < priorityLength; ++i) {
+            scoreInfoList.add(new SuggestedWords.SuggestedWordInfo("+", false));
+            for (int i = 0; i < mScores.length; ++i) {
                 if (normalizedScore > 0) {
-                    final String priorityThreshold = Integer.toString(mPriorities[i]) + " (" +
-                            normalizedScore + ")";
-                    frequencyInfoList.add(
-                            new SuggestedWords.SuggestedWordInfo(priorityThreshold, false));
+                    final String scoreThreshold = String.format("%d (%4.2f)", mScores[i],
+                            normalizedScore);
+                    scoreInfoList.add(
+                            new SuggestedWords.SuggestedWordInfo(scoreThreshold, false));
                     normalizedScore = 0.0;
                 } else {
-                    final String priority = Integer.toString(mPriorities[i]);
-                    frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo(priority, false));
+                    final String score = Integer.toString(mScores[i]);
+                    scoreInfoList.add(new SuggestedWords.SuggestedWordInfo(score, false));
                 }
             }
-            for (int i = priorityLength; i < mSuggestions.size(); ++i) {
-                frequencyInfoList.add(new SuggestedWords.SuggestedWordInfo("--", false));
+            for (int i = mScores.length; i < mSuggestions.size(); ++i) {
+                scoreInfoList.add(new SuggestedWords.SuggestedWordInfo("--", false));
             }
-            return new SuggestedWords.Builder().addWords(mSuggestions, frequencyInfoList);
-        } else {
-            return new SuggestedWords.Builder().addWords(mSuggestions, null);
+            return new SuggestedWords.Builder().addWords(mSuggestions, scoreInfoList);
         }
-    }
-
-    public int[] getNextLettersFrequencies() {
-        return mNextLettersFrequencies;
+        return new SuggestedWords.Builder().addWords(mSuggestions, null);
     }
 
     private void removeDupes() {
@@ -420,45 +430,43 @@ public class Suggest implements Dictionary.WordCallback {
     }
 
     public boolean hasAutoCorrection() {
-        return mHasAutoCorrection;
-    }
-
-    private static boolean compareCaseInsensitive(final String lowerOriginalWord,
-            final char[] word, final int offset, final int length) {
-        final int originalLength = lowerOriginalWord.length();
-        if (originalLength == length && Character.isUpperCase(word[offset])) {
-            for (int i = 0; i < originalLength; i++) {
-                if (lowerOriginalWord.charAt(i) != Character.toLowerCase(word[offset+i])) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
+        return mAutoCorrection.hasAutoCorrection();
     }
 
     @Override
-    public boolean addWord(final char[] word, final int offset, final int length, int freq,
+    public boolean addWord(final char[] word, final int offset, final int length, int score,
             final int dicTypeId, final Dictionary.DataType dataType) {
         Dictionary.DataType dataTypeForLog = dataType;
-        ArrayList<CharSequence> suggestions;
-        int[] priorities;
-        int prefMaxSuggestions;
+        final ArrayList<CharSequence> suggestions;
+        final int[] sortedScores;
+        final int prefMaxSuggestions;
         if(dataType == Dictionary.DataType.BIGRAM) {
             suggestions = mBigramSuggestions;
-            priorities = mBigramPriorities;
+            sortedScores = mBigramScores;
             prefMaxSuggestions = PREF_MAX_BIGRAMS;
         } else {
             suggestions = mSuggestions;
-            priorities = mPriorities;
+            sortedScores = mScores;
             prefMaxSuggestions = mPrefMaxSuggestions;
         }
 
         int pos = 0;
 
         // Check if it's the same word, only caps are different
-        if (compareCaseInsensitive(mLowerOriginalWord, word, offset, length)) {
-            pos = 0;
+        if (Utils.equalsIgnoreCase(mTypedWord, word, offset, length)) {
+            // TODO: remove this surrounding if clause and move this logic to
+            // getSuggestedWordBuilder.
+            if (suggestions.size() > 0) {
+                final String currentHighestWord = suggestions.get(0).toString();
+                // If the current highest word is also equal to typed word, we need to compare
+                // frequency to determine the insertion position. This does not ensure strictly
+                // correct ordering, but ensures the top score is on top which is enough for
+                // removing duplicates correctly.
+                if (Utils.equalsIgnoreCase(currentHighestWord, word, offset, length)
+                        && score <= sortedScores[0]) {
+                    pos = 1;
+                }
+            }
         } else {
             if (dataType == Dictionary.DataType.UNIGRAM) {
                 // Check if the word was already added before (by bigram data)
@@ -466,24 +474,24 @@ public class Suggest implements Dictionary.WordCallback {
                 if(bigramSuggestion >= 0) {
                     dataTypeForLog = Dictionary.DataType.BIGRAM;
                     // turn freq from bigram into multiplier specified above
-                    double multiplier = (((double) mBigramPriorities[bigramSuggestion])
+                    double multiplier = (((double) mBigramScores[bigramSuggestion])
                             / MAXIMUM_BIGRAM_FREQUENCY)
                             * (BIGRAM_MULTIPLIER_MAX - BIGRAM_MULTIPLIER_MIN)
                             + BIGRAM_MULTIPLIER_MIN;
                     /* Log.d(TAG,"bigram num: " + bigramSuggestion
                             + "  wordB: " + mBigramSuggestions.get(bigramSuggestion).toString()
-                            + "  currentPriority: " + freq + "  bigramPriority: "
-                            + mBigramPriorities[bigramSuggestion]
+                            + "  currentScore: " + score + "  bigramScore: "
+                            + mBigramScores[bigramSuggestion]
                             + "  multiplier: " + multiplier); */
-                    freq = (int)Math.round((freq * multiplier));
+                    score = (int)Math.round((score * multiplier));
                 }
             }
 
-            // Check the last one's priority and bail
-            if (priorities[prefMaxSuggestions - 1] >= freq) return true;
+            // Check the last one's score and bail
+            if (sortedScores[prefMaxSuggestions - 1] >= score) return true;
             while (pos < prefMaxSuggestions) {
-                if (priorities[pos] < freq
-                        || (priorities[pos] == freq && length < suggestions.get(pos).length())) {
+                if (sortedScores[pos] < score
+                        || (sortedScores[pos] == score && length < suggestions.get(pos).length())) {
                     break;
                 }
                 pos++;
@@ -493,8 +501,8 @@ public class Suggest implements Dictionary.WordCallback {
             return true;
         }
 
-        System.arraycopy(priorities, pos, priorities, pos + 1, prefMaxSuggestions - pos - 1);
-        priorities[pos] = freq;
+        System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1);
+        sortedScores[pos] = score;
         int poolSize = mStringPool.size();
         StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
                 : new StringBuilder(getApproxMaxWordLength());
@@ -541,16 +549,6 @@ public class Suggest implements Dictionary.WordCallback {
         return -1;
     }
 
-    public boolean isValidWord(final CharSequence word) {
-        if (word == null || word.length() == 0 || mMainDict == null) {
-            return false;
-        }
-        return mMainDict.isValidWord(word)
-                || (mUserDictionary != null && mUserDictionary.isValidWord(word))
-                || (mAutoDictionary != null && mAutoDictionary.isValidWord(word))
-                || (mContactsDictionary != null && mContactsDictionary.isValidWord(word));
-    }
-
     private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) {
         int poolSize = mStringPool.size();
         int garbageSize = suggestions.size();
@@ -569,25 +567,12 @@ public class Suggest implements Dictionary.WordCallback {
     }
 
     public void close() {
-        if (mMainDict != null) {
-            mMainDict.close();
-            mMainDict = null;
-        }
-        if (mUserDictionary != null) {
-            mUserDictionary.close();
-            mUserDictionary = null;
-        }
-        if (mUserBigramDictionary != null) {
-            mUserBigramDictionary.close();
-            mUserBigramDictionary = null;
-        }
-        if (mContactsDictionary != null) {
-            mContactsDictionary.close();
-            mContactsDictionary = null;
-        }
-        if (mAutoDictionary != null) {
-            mAutoDictionary.close();
-            mAutoDictionary = null;
+        final Set<Dictionary> dictionaries = new HashSet<Dictionary>();
+        dictionaries.addAll(mUnigramDictionaries.values());
+        dictionaries.addAll(mBigramDictionaries.values());
+        for (final Dictionary dictionary : dictionaries) {
+            dictionary.close();
         }
+        mMainDict = null;
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index f774ce3a5ac6597cd92e4a1c2db5355ac8c5fb1f..fe7aac7c2a6fb9976650665fa88bd4648329220f 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -24,23 +24,20 @@ import java.util.HashSet;
 import java.util.List;
 
 public class SuggestedWords {
-    public static final SuggestedWords EMPTY = new SuggestedWords(null, false, false, false, null);
+    public static final SuggestedWords EMPTY = new SuggestedWords(null, false, false, null);
 
     public final List<CharSequence> mWords;
-    public final boolean mIsApplicationSpecifiedCompletions;
     public final boolean mTypedWordValid;
     public final boolean mHasMinimalSuggestion;
     public final List<SuggestedWordInfo> mSuggestedWordInfoList;
 
-    private SuggestedWords(List<CharSequence> words, boolean isApplicationSpecifiedCompletions,
-            boolean typedWordValid, boolean hasMinamlSuggestion,
-            List<SuggestedWordInfo> suggestedWordInfoList) {
+    private SuggestedWords(List<CharSequence> words, boolean typedWordValid,
+            boolean hasMinamlSuggestion, List<SuggestedWordInfo> suggestedWordInfoList) {
         if (words != null) {
             mWords = words;
         } else {
             mWords = Collections.emptyList();
         }
-        mIsApplicationSpecifiedCompletions = isApplicationSpecifiedCompletions;
         mTypedWordValid = typedWordValid;
         mHasMinimalSuggestion = hasMinamlSuggestion;
         mSuggestedWordInfoList = suggestedWordInfoList;
@@ -64,7 +61,6 @@ public class SuggestedWords {
 
     public static class Builder {
         private List<CharSequence> mWords = new ArrayList<CharSequence>();
-        private boolean mIsCompletions;
         private boolean mTypedWordValid;
         private boolean mHasMinimalSuggestion;
         private List<SuggestedWordInfo> mSuggestedWordInfoList =
@@ -109,7 +105,6 @@ public class SuggestedWords {
         public Builder setApplicationSpecifiedCompletions(CompletionInfo[] infos) {
             for (CompletionInfo info : infos)
                 addWord(info.getText());
-            mIsCompletions = true;
             return this;
         }
 
@@ -141,15 +136,14 @@ public class SuggestedWords {
                     alreadySeen.add(prevWord);
                 }
             }
-            mIsCompletions = false;
             mTypedWordValid = false;
             mHasMinimalSuggestion = false;
             return this;
         }
 
         public SuggestedWords build() {
-            return new SuggestedWords(mWords, mIsCompletions, mTypedWordValid,
-                    mHasMinimalSuggestion, mSuggestedWordInfoList);
+            return new SuggestedWords(mWords, mTypedWordValid, mHasMinimalSuggestion,
+                    mSuggestedWordInfoList);
         }
 
         public int size() {
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index f571f26d5ea921af3c5f8bcac572ccaaf772a384..63196430b70c7d7dbc93c4888dc909e0a5efc78c 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -16,117 +16,39 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.keyboard.Key;
-
-import android.content.Context;
-import android.text.format.DateFormat;
 import android.util.Log;
 
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Calendar;
-
 public class TextEntryState {
-    
-    private static final boolean DBG = false;
-
-    private static final String TAG = "TextEntryState";
-
-    private static boolean LOGGING = false;
-
-    private static int sBackspaceCount = 0;
-    
-    private static int sAutoSuggestCount = 0;
-    
-    private static int sAutoSuggestUndoneCount = 0;
-    
-    private static int sManualSuggestCount = 0;
-    
-    private static int sWordNotInDictionaryCount = 0;
-    
-    private static int sSessionCount = 0;
-    
-    private static int sTypedChars;
-
-    private static int sActualChars;
-
-    public enum State {
-        UNKNOWN,
-        START,
-        IN_WORD,
-        ACCEPTED_DEFAULT,
-        PICKED_SUGGESTION,
-        PUNCTUATION_AFTER_WORD,
-        PUNCTUATION_AFTER_ACCEPTED,
-        SPACE_AFTER_ACCEPTED,
-        SPACE_AFTER_PICKED,
-        UNDO_COMMIT,
-        CORRECTING,
-        PICKED_CORRECTION,
+    private static final String TAG = TextEntryState.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private static final int UNKNOWN = 0;
+    private static final int START = 1;
+    private static final int IN_WORD = 2;
+    private static final int ACCEPTED_DEFAULT = 3;
+    private static final int PICKED_SUGGESTION = 4;
+    private static final int PUNCTUATION_AFTER_WORD = 5;
+    private static final int PUNCTUATION_AFTER_ACCEPTED = 6;
+    private static final int SPACE_AFTER_ACCEPTED = 7;
+    private static final int SPACE_AFTER_PICKED = 8;
+    private static final int UNDO_COMMIT = 9;
+    private static final int RECORRECTING = 10;
+    private static final int PICKED_RECORRECTION = 11;
+
+    private static int sState = UNKNOWN;
+    private static int sPreviousState = UNKNOWN;
+
+    private static void setState(final int newState) {
+        sPreviousState = sState;
+        sState = newState;
     }
 
-    private static State sState = State.UNKNOWN;
-
-    private static FileOutputStream sKeyLocationFile;
-    private static FileOutputStream sUserActionFile;
-    
-    public static void newSession(Context context) {
-        sSessionCount++;
-        sAutoSuggestCount = 0;
-        sBackspaceCount = 0;
-        sAutoSuggestUndoneCount = 0;
-        sManualSuggestCount = 0;
-        sWordNotInDictionaryCount = 0;
-        sTypedChars = 0;
-        sActualChars = 0;
-        sState = State.START;
-        
-        if (LOGGING) {
-            try {
-                sKeyLocationFile = context.openFileOutput("key.txt", Context.MODE_APPEND);
-                sUserActionFile = context.openFileOutput("action.txt", Context.MODE_APPEND);
-            } catch (IOException ioe) {
-                Log.e("TextEntryState", "Couldn't open file for output: " + ioe);
-            }
-        }
-    }
-    
-    public static void endSession() {
-        if (sKeyLocationFile == null) {
-            return;
-        }
-        try {
-            sKeyLocationFile.close();
-            // Write to log file
-            // Write timestamp, settings,
-            String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime())
-                    .toString()
-                    + " BS: " + sBackspaceCount
-                    + " auto: " + sAutoSuggestCount
-                    + " manual: " + sManualSuggestCount
-                    + " typed: " + sWordNotInDictionaryCount
-                    + " undone: " + sAutoSuggestUndoneCount
-                    + " saved: " + ((float) (sActualChars - sTypedChars) / sActualChars)
-                    + "\n";
-            sUserActionFile.write(out.getBytes());
-            sUserActionFile.close();
-            sKeyLocationFile = null;
-            sUserActionFile = null;
-        } catch (IOException ioe) {
-            // ignore
-        }
-    }
-    
     public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord) {
         if (typedWord == null) return;
-        if (!typedWord.equals(actualWord)) {
-            sAutoSuggestCount++;
-        }
-        sTypedChars += typedWord.length();
-        sActualChars += actualWord.length();
-        sState = State.ACCEPTED_DEFAULT;
+        setState(ACCEPTED_DEFAULT);
         LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString());
-        displayState();
+        if (DEBUG)
+            displayState("acceptedDefault", "typedWord", typedWord, "actualWord", actualWord);
     }
 
     // State.ACCEPTED_DEFAULT will be changed to other sub-states
@@ -138,151 +60,167 @@ public class TextEntryState {
         case SPACE_AFTER_ACCEPTED:
         case PUNCTUATION_AFTER_ACCEPTED:
         case IN_WORD:
-            sState = State.ACCEPTED_DEFAULT;
+            setState(ACCEPTED_DEFAULT);
             break;
         default:
             break;
         }
-        displayState();
+        if (DEBUG) displayState("backToAcceptedDefault", "typedWord", typedWord);
     }
 
-    public static void acceptedTyped(@SuppressWarnings("unused") CharSequence typedWord) {
-        sWordNotInDictionaryCount++;
-        sState = State.PICKED_SUGGESTION;
-        displayState();
+    public static void acceptedTyped(CharSequence typedWord) {
+        setState(PICKED_SUGGESTION);
+        if (DEBUG) displayState("acceptedTyped", "typedWord", typedWord);
     }
 
     public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
-        sManualSuggestCount++;
-        State oldState = sState;
-        if (typedWord.equals(actualWord)) {
-            acceptedTyped(typedWord);
-        }
-        if (oldState == State.CORRECTING || oldState == State.PICKED_CORRECTION) {
-            sState = State.PICKED_CORRECTION;
+        if (sState == RECORRECTING || sState == PICKED_RECORRECTION) {
+            setState(PICKED_RECORRECTION);
         } else {
-            sState = State.PICKED_SUGGESTION;
+            setState(PICKED_SUGGESTION);
         }
-        displayState();
+        if (DEBUG)
+            displayState("acceptedSuggestion", "typedWord", typedWord, "actualWord", actualWord);
     }
 
-    public static void selectedForCorrection() {
-        sState = State.CORRECTING;
-        displayState();
+    public static void selectedForRecorrection() {
+        setState(RECORRECTING);
+        if (DEBUG) displayState("selectedForRecorrection");
     }
 
-    public static void onAbortCorrection() {
-        if (isCorrecting()) {
-            sState = State.START;
+    public static void onAbortRecorrection() {
+        if (sState == RECORRECTING || sState == PICKED_RECORRECTION) {
+            setState(START);
         }
-        displayState();
+        if (DEBUG) displayState("onAbortRecorrection");
     }
 
     public static void typedCharacter(char c, boolean isSeparator) {
-        boolean isSpace = c == ' ';
+        final boolean isSpace = (c == ' ');
         switch (sState) {
-            case IN_WORD:
-                if (isSpace || isSeparator) {
-                    sState = State.START;
-                } else {
-                    // State hasn't changed.
-                }
-                break;
-            case ACCEPTED_DEFAULT:
-            case SPACE_AFTER_PICKED:
-                if (isSpace) {
-                    sState = State.SPACE_AFTER_ACCEPTED;
-                } else if (isSeparator) {
-                    sState = State.PUNCTUATION_AFTER_ACCEPTED;
-                } else {
-                    sState = State.IN_WORD;
-                }
-                break;
-            case PICKED_SUGGESTION:
-            case PICKED_CORRECTION:
-                if (isSpace) {
-                    sState = State.SPACE_AFTER_PICKED;
-                } else if (isSeparator) {
-                    // Swap 
-                    sState = State.PUNCTUATION_AFTER_ACCEPTED;
-                } else {
-                    sState = State.IN_WORD;
-                }
-                break;
-            case START:
-            case UNKNOWN:
-            case SPACE_AFTER_ACCEPTED:
-            case PUNCTUATION_AFTER_ACCEPTED:
-            case PUNCTUATION_AFTER_WORD:
-                if (!isSpace && !isSeparator) {
-                    sState = State.IN_WORD;
-                } else {
-                    sState = State.START;
-                }
-                break;
-            case UNDO_COMMIT:
-                if (isSpace || isSeparator) {
-                    sState = State.ACCEPTED_DEFAULT;
-                } else {
-                    sState = State.IN_WORD;
-                }
-                break;
-            case CORRECTING:
-                sState = State.START;
-                break;
+        case IN_WORD:
+            if (isSpace || isSeparator) {
+                setState(START);
+            } else {
+                // State hasn't changed.
+            }
+            break;
+        case ACCEPTED_DEFAULT:
+        case SPACE_AFTER_PICKED:
+        case PUNCTUATION_AFTER_ACCEPTED:
+            if (isSpace) {
+                setState(SPACE_AFTER_ACCEPTED);
+            } else if (isSeparator) {
+                // Swap
+                setState(PUNCTUATION_AFTER_ACCEPTED);
+            } else {
+                setState(IN_WORD);
+            }
+            break;
+        case PICKED_SUGGESTION:
+        case PICKED_RECORRECTION:
+            if (isSpace) {
+                setState(SPACE_AFTER_PICKED);
+            } else if (isSeparator) {
+                // Swap
+                setState(PUNCTUATION_AFTER_ACCEPTED);
+            } else {
+                setState(IN_WORD);
+            }
+            break;
+        case START:
+        case UNKNOWN:
+        case SPACE_AFTER_ACCEPTED:
+        case PUNCTUATION_AFTER_WORD:
+            if (!isSpace && !isSeparator) {
+                setState(IN_WORD);
+            } else {
+                setState(START);
+            }
+            break;
+        case UNDO_COMMIT:
+            if (isSpace || isSeparator) {
+                setState(ACCEPTED_DEFAULT);
+            } else {
+                setState(IN_WORD);
+            }
+            break;
+        case RECORRECTING:
+            setState(START);
+            break;
         }
-        displayState();
+        if (DEBUG) displayState("typedCharacter", "char", c, "isSeparator", isSeparator);
     }
     
     public static void backspace() {
-        if (sState == State.ACCEPTED_DEFAULT) {
-            sState = State.UNDO_COMMIT;
-            sAutoSuggestUndoneCount++;
+        if (sState == ACCEPTED_DEFAULT) {
+            setState(UNDO_COMMIT);
             LatinImeLogger.logOnAutoSuggestionCanceled();
-        } else if (sState == State.UNDO_COMMIT) {
-            sState = State.IN_WORD;
+        } else if (sState == UNDO_COMMIT) {
+            setState(IN_WORD);
         }
-        sBackspaceCount++;
-        displayState();
+        if (DEBUG) displayState("backspace");
     }
 
     public static void reset() {
-        sState = State.START;
-        displayState();
+        setState(START);
+        if (DEBUG) displayState("reset");
     }
 
-    public static State getState() {
-        if (DBG) {
-            Log.d(TAG, "Returning state = " + sState);
-        }
-        return sState;
+    public static boolean isAcceptedDefault() {
+        return sState == ACCEPTED_DEFAULT;
     }
 
-    public static boolean isCorrecting() {
-        return sState == State.CORRECTING || sState == State.PICKED_CORRECTION;
+    public static boolean isSpaceAfterPicked() {
+        return sState == SPACE_AFTER_PICKED;
     }
 
-    public static void keyPressedAt(Key key, int x, int y) {
-        if (LOGGING && sKeyLocationFile != null && key.mCode >= 32) {
-            String out =
-                    "KEY: " + (char) key.mCode
-                    + " X: " + x
-                    + " Y: " + y
-                    + " MX: " + (key.mX + key.mWidth / 2)
-                    + " MY: " + (key.mY + key.mHeight / 2)
-                    + "\n";
-            try {
-                sKeyLocationFile.write(out.getBytes());
-            } catch (IOException ioe) {
-                // TODO: May run out of space
-            }
+    public static boolean isUndoCommit() {
+        return sState == UNDO_COMMIT;
+    }
+
+    public static boolean isPunctuationAfterAccepted() {
+        return sState == PUNCTUATION_AFTER_ACCEPTED;
+    }
+
+    public static boolean isRecorrecting() {
+        return sState == RECORRECTING || sState == PICKED_RECORRECTION;
+    }
+
+    public static String getState() {
+        return stateName(sState);
+    }
+
+    private static String stateName(int state) {
+        switch (state) {
+        case START: return "START";
+        case IN_WORD: return "IN_WORD";
+        case ACCEPTED_DEFAULT: return "ACCEPTED_DEFAULT";
+        case PICKED_SUGGESTION: return "PICKED_SUGGESTION";
+        case PUNCTUATION_AFTER_WORD: return "PUNCTUATION_AFTER_WORD";
+        case PUNCTUATION_AFTER_ACCEPTED: return "PUNCTUATION_AFTER_ACCEPTED";
+        case SPACE_AFTER_ACCEPTED: return "SPACE_AFTER_ACCEPTED";
+        case SPACE_AFTER_PICKED: return "SPACE_AFTER_PICKED";
+        case UNDO_COMMIT: return "UNDO_COMMIT";
+        case RECORRECTING: return "RECORRECTING";
+        case PICKED_RECORRECTION: return "PICKED_RECORRECTION";
+        default: return "UNKNOWN";
         }
     }
 
-    private static void displayState() {
-        if (DBG) {
-            Log.d(TAG, "State = " + sState);
+    private static void displayState(String title, Object ... args) {
+        final StringBuilder sb = new StringBuilder(title);
+        sb.append(':');
+        for (int i = 0; i < args.length; i += 2) {
+            sb.append(' ');
+            sb.append(args[i]);
+            sb.append('=');
+            sb.append(args[i+1].toString());
         }
+        sb.append(" state=");
+        sb.append(stateName(sState));
+        sb.append(" previous=");
+        sb.append(stateName(sPreviousState));
+        Log.d(TAG, sb.toString());
     }
 }
-
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index 56ee5b9e78f87dc8ce004c5809878f7899638c3a..c06bd736e83cff9d094f1d180bfe29a0663f0d0e 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -126,9 +126,8 @@ public class UserDictionary extends ExpandableDictionary {
     }
 
     @Override
-    public synchronized void getWords(final WordComposer codes, final WordCallback callback,
-            int[] nextLettersFrequencies) {
-        super.getWords(codes, callback, nextLettersFrequencies);
+    public synchronized void getWords(final WordComposer codes, final WordCallback callback) {
+        super.getWords(codes, callback);
     }
 
     @Override
@@ -138,7 +137,7 @@ public class UserDictionary extends ExpandableDictionary {
 
     private void addWords(Cursor cursor) {
         clearDictionary();
-
+        if (cursor == null) return;
         final int maxWordLength = getMaxWordLength();
         if (cursor.moveToFirst()) {
             final int indexWord = cursor.getColumnIndex(Words.WORD);
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index d33d962c0ae2b01f5fe734bf48ed9a80600be1e5..35b2b123ccdf90a3d278538e5c687ac24838edbc 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -16,15 +16,21 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+import com.android.inputmethod.keyboard.KeyboardId;
+
+import android.content.res.Resources;
 import android.inputmethodservice.InputMethodService;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
+import android.text.InputType;
 import android.text.format.DateUtils;
 import android.util.Log;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -41,6 +47,10 @@ public class Utils {
     private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4;
     private static boolean DBG = LatinImeLogger.sDBG;
 
+    private Utils() {
+        // Intentional empty constructor for utility class.
+    }
+
     /**
      * Cancel an {@link AsyncTask}.
      *
@@ -55,7 +65,7 @@ public class Utils {
     }
 
     public static class GCUtils {
-        private static final String TAG = "GCUtils";
+        private static final String GC_TAG = GCUtils.class.getSimpleName();
         public static final int GC_TRY_COUNT = 2;
         // GC_TRY_LOOP_MAX is used for the hard limit of GC wait,
         // GC_TRY_LOOP_MAX should be greater than GC_TRY_COUNT.
@@ -84,7 +94,7 @@ public class Utils {
                     Thread.sleep(GC_INTERVAL);
                     return true;
                 } catch (InterruptedException e) {
-                    Log.e(TAG, "Sleep was interrupted.");
+                    Log.e(GC_TAG, "Sleep was interrupted.");
                     LatinImeLogger.logOnException(metaData, t);
                     return false;
                 }
@@ -92,16 +102,15 @@ public class Utils {
         }
     }
 
-    public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm) {
-        return imm.getEnabledInputMethodList().size() > 1;
-        // @@@ return imm.getEnabledInputMethodList().size() > 1
+    public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm) {
+        return imm.getEnabledInputMethodList().size() > 1
         // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
         // input method subtype (The current IME should be LatinIME.)
-        // || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
+                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
     }
 
-    public static String getInputMethodId(InputMethodManager imm, String packageName) {
-        for (final InputMethodInfo imi : imm.getEnabledInputMethodList()) {
+    public static String getInputMethodId(InputMethodManagerCompatWrapper imm, String packageName) {
+        for (final InputMethodInfoCompatWrapper imi : imm.getEnabledInputMethodList()) {
             if (imi.getPackageName().equals(packageName))
                 return imi.getId();
         }
@@ -262,20 +271,42 @@ public class Utils {
         return dp[sl][tl];
     }
 
+    // Get the current stack trace
+    public static String getStackTrace() {
+        StringBuilder sb = new StringBuilder();
+        try {
+            throw new RuntimeException();
+        } catch (RuntimeException e) {
+            StackTraceElement[] frames = e.getStackTrace();
+            // Start at 1 because the first frame is here and we don't care about it
+            for (int j = 1; j < frames.length; ++j) sb.append(frames[j].toString() + "\n");
+        }
+        return sb.toString();
+    }
+
     // In dictionary.cpp, getSuggestion() method,
     // suggestion scores are computed using the below formula.
-    // original score (called 'frequency')
+    // original score
     //  := pow(mTypedLetterMultiplier (this is defined 2),
     //         (the number of matched characters between typed word and suggested word))
     //     * (individual word's score which defined in the unigram dictionary,
     //         and this score is defined in range [0, 255].)
-    //     * (when before.length() == after.length(),
-    //         mFullWordMultiplier (this is defined 2))
-    // So, maximum original score is pow(2, before.length()) * 255 * 2
-    // So, we can normalize original score by dividing this value.
+    // Then, the following processing is applied.
+    //     - If the dictionary word is matched up to the point of the user entry
+    //       (full match up to min(before.length(), after.length())
+    //       => Then multiply by FULL_MATCHED_WORDS_PROMOTION_RATE (this is defined 1.2)
+    //     - If the word is a true full match except for differences in accents or
+    //       capitalization, then treat it as if the score was 255.
+    //     - If before.length() == after.length()
+    //       => multiply by mFullWordMultiplier (this is defined 2))
+    // So, maximum original score is pow(2, min(before.length(), after.length())) * 255 * 2 * 1.2
+    // For historical reasons we ignore the 1.2 modifier (because the measure for a good
+    // autocorrection threshold was done at a time when it didn't exist). This doesn't change
+    // the result.
+    // So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2.
     private static final int MAX_INITIAL_SCORE = 255;
     private static final int TYPED_LETTER_MULTIPLIER = 2;
-    private static final int FULL_WORD_MULTIPLYER = 2;
+    private static final int FULL_WORD_MULTIPLIER = 2;
     public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
         final int beforeLength = before.length();
         final int afterLength = after.length();
@@ -285,7 +316,7 @@ public class Utils {
         // correction.
         final double maximumScore = MAX_INITIAL_SCORE
                 * Math.pow(TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength))
-                * FULL_WORD_MULTIPLYER;
+                * FULL_WORD_MULTIPLIER;
         // add a weight based on edit distance.
         // distance <= max(afterLength, beforeLength) == afterLength,
         // so, 0 <= distance / afterLength <= 1
@@ -294,7 +325,7 @@ public class Utils {
     }
 
     public static class UsabilityStudyLogUtils {
-        private static final String TAG = "UsabilityStudyLogUtils";
+        private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
         private static final String FILENAME = "log.txt";
         private static final UsabilityStudyLogUtils sInstance =
                 new UsabilityStudyLogUtils();
@@ -331,7 +362,7 @@ public class Utils {
                 try {
                     mWriter = getPrintWriter(mDirectory, FILENAME, false);
                 } catch (IOException e) {
-                    Log.e(TAG, "Can't create log file.");
+                    Log.e(USABILITY_TAG, "Can't create log file.");
                 }
             }
         }
@@ -368,7 +399,7 @@ public class Utils {
                     final String printString = String.format("%s\t%d\t%s\n",
                             mDateFormat.format(mDate), currentTime, log);
                     if (LatinImeLogger.sDBG) {
-                        Log.d(TAG, "Write: " + log);
+                        Log.d(USABILITY_TAG, "Write: " + log);
                     }
                     mWriter.print(printString);
                 }
@@ -389,10 +420,10 @@ public class Utils {
                             sb.append(line);
                         }
                     } catch (IOException e) {
-                        Log.e(TAG, "Can't read log file.");
+                        Log.e(USABILITY_TAG, "Can't read log file.");
                     } finally {
                         if (LatinImeLogger.sDBG) {
-                            Log.d(TAG, "output all logs\n" + sb.toString());
+                            Log.d(USABILITY_TAG, "output all logs\n" + sb.toString());
                         }
                         mIms.getCurrentInputConnection().commitText(sb.toString(), 0);
                         try {
@@ -411,7 +442,7 @@ public class Utils {
                 public void run() {
                     if (mFile != null && mFile.exists()) {
                         if (LatinImeLogger.sDBG) {
-                            Log.d(TAG, "Delete log file.");
+                            Log.d(USABILITY_TAG, "Delete log file.");
                         }
                         mFile.delete();
                         mWriter.close();
@@ -440,4 +471,134 @@ public class Utils {
             return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
         }
     }
+
+    public static int getKeyboardMode(EditorInfo attribute) {
+        if (attribute == null)
+            return KeyboardId.MODE_TEXT;
+
+        final int inputType = attribute.inputType;
+        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+
+        switch (inputType & InputType.TYPE_MASK_CLASS) {
+        case InputType.TYPE_CLASS_NUMBER:
+        case InputType.TYPE_CLASS_DATETIME:
+            return KeyboardId.MODE_NUMBER;
+        case InputType.TYPE_CLASS_PHONE:
+            return KeyboardId.MODE_PHONE;
+        case InputType.TYPE_CLASS_TEXT:
+            if (InputTypeCompatUtils.isEmailVariation(variation)) {
+                return KeyboardId.MODE_EMAIL;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
+                return KeyboardId.MODE_URL;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
+                return KeyboardId.MODE_IM;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+                return KeyboardId.MODE_TEXT;
+            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
+                return KeyboardId.MODE_WEB;
+            } else {
+                return KeyboardId.MODE_TEXT;
+            }
+        default:
+            return KeyboardId.MODE_TEXT;
+        }
+    }
+
+    public static boolean containsInCsv(String key, String csv) {
+        if (csv == null)
+            return false;
+        for (String option : csv.split(",")) {
+            if (option.equals(key))
+                return true;
+        }
+        return false;
+    }
+
+    public static boolean inPrivateImeOptions(String packageName, String key,
+            EditorInfo attribute) {
+        if (attribute == null)
+            return false;
+        return containsInCsv(packageName != null ? packageName + "." + key : key,
+                attribute.privateImeOptions);
+    }
+
+    /**
+     * Returns a main dictionary resource id
+     * @return main dictionary resource id
+     */
+    public static int getMainDictionaryResourceId(Resources res) {
+        final String MAIN_DIC_NAME = "main";
+        String packageName = LatinIME.class.getPackage().getName();
+        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
+    }
+
+    public static void loadNativeLibrary() {
+        try {
+            System.loadLibrary("jni_latinime");
+        } catch (UnsatisfiedLinkError ule) {
+            Log.e(TAG, "Could not load native library jni_latinime");
+        }
+    }
+
+    /**
+     * Returns true if a and b are equal ignoring the case of the character.
+     * @param a first character to check
+     * @param b second character to check
+     * @return {@code true} if a and b are equal, {@code false} otherwise.
+     */
+    public static boolean equalsIgnoreCase(char a, char b) {
+        // Some language, such as Turkish, need testing both cases.
+        return a == b
+                || Character.toLowerCase(a) == Character.toLowerCase(b)
+                || Character.toUpperCase(a) == Character.toUpperCase(b);
+    }
+
+    /**
+     * Returns true if a and b are equal ignoring the case of the characters, including if they are
+     * both null.
+     * @param a first CharSequence to check
+     * @param b second CharSequence to check
+     * @return {@code true} if a and b are equal, {@code false} otherwise.
+     */
+    public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
+        if (a == b)
+            return true;  // including both a and b are null.
+        if (a == null || b == null)
+            return false;
+        final int length = a.length();
+        if (length != b.length())
+            return false;
+        for (int i = 0; i < length; i++) {
+            if (!equalsIgnoreCase(a.charAt(i), b.charAt(i)))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns true if a and b are equal ignoring the case of the characters, including if a is null
+     * and b is zero length.
+     * @param a CharSequence to check
+     * @param b character array to check
+     * @param offset start offset of array b
+     * @param length length of characters in array b
+     * @return {@code true} if a and b are equal, {@code false} otherwise.
+     * @throws IndexOutOfBoundsException
+     *   if {@code offset < 0 || length < 0 || offset + length > data.length}.
+     * @throws NullPointerException if {@code b == null}.
+     */
+    public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) {
+        if (offset < 0 || length < 0 || length > b.length - offset)
+            throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset
+                    + " length=" + length);
+        if (a == null)
+            return length == 0;  // including a is null and b is zero length.
+        if (a.length() != length)
+            return false;
+        for (int i = 0; i < length; i++) {
+            if (!equalsIgnoreCase(a.charAt(i), b[offset + i]))
+                return false;
+        }
+        return true;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
new file mode 100644
index 0000000000000000000000000000000000000000..2389d4e3c30c97a523718c32e934454a049f7dc7
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.HashMap;
+
+public class WhitelistDictionary extends Dictionary {
+
+    private static final boolean DBG = LatinImeLogger.sDBG;
+    private static final String TAG = WhitelistDictionary.class.getSimpleName();
+
+    private final HashMap<String, Pair<Integer, String>> mWhitelistWords =
+            new HashMap<String, Pair<Integer, String>>();
+
+    private static final WhitelistDictionary sInstance = new WhitelistDictionary();
+
+    private WhitelistDictionary() {
+    }
+
+    public static WhitelistDictionary init(Context context) {
+        synchronized (sInstance) {
+            if (context != null) {
+                sInstance.initWordlist(
+                        context.getResources().getStringArray(R.array.wordlist_whitelist));
+            } else {
+                sInstance.mWhitelistWords.clear();
+            }
+        }
+        return sInstance;
+    }
+
+    private void initWordlist(String[] wordlist) {
+        mWhitelistWords.clear();
+        final int N = wordlist.length;
+        if (N % 3 != 0) {
+            if (DBG) {
+                Log.d(TAG, "The number of the whitelist is invalid.");
+            }
+            return;
+        }
+        try {
+            for (int i = 0; i < N; i += 3) {
+                final int score = Integer.valueOf(wordlist[i]);
+                final String before = wordlist[i + 1];
+                final String after = wordlist[i + 2];
+                if (before != null && after != null) {
+                    mWhitelistWords.put(
+                            before.toLowerCase(), new Pair<Integer, String>(score, after));
+                }
+            }
+        } catch (NumberFormatException e) {
+            if (DBG) {
+                Log.d(TAG, "The score of the word is invalid.");
+            }
+        }
+    }
+
+    public String getWhiteListedWord(String before) {
+        if (before == null) return null;
+        final String lowerCaseBefore = before.toLowerCase();
+        if(mWhitelistWords.containsKey(lowerCaseBefore)) {
+            if (DBG) {
+                Log.d(TAG, "--- found whiteListedWord: " + lowerCaseBefore);
+            }
+            return mWhitelistWords.get(lowerCaseBefore).second;
+        }
+        return null;
+    }
+
+    // Not used for WhitelistDictionary.  We use getWhitelistedWord() in Suggest.java instead
+    @Override
+    public void getWords(WordComposer composer, WordCallback callback) {
+    }
+
+    @Override
+    public boolean isValidWord(CharSequence word) {
+        if (TextUtils.isEmpty(word)) return false;
+        return !TextUtils.isEmpty(getWhiteListedWord(word.toString()));
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 2e415b771951cea1768953f776b0ccf7fe0e5972..02583895be83d572c26585f9b8fadf433013df48 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -16,22 +16,32 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.KeyDetector;
+
 import java.util.ArrayList;
 
 /**
  * A place to store the currently composing word with information such as adjacent key codes as well
  */
 public class WordComposer {
+
+    public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
+    public static final int NOT_A_COORDINATE = -1;
+
     /**
      * The list of unicode values for each keystroke (including surrounding keys)
      */
     private final ArrayList<int[]> mCodes;
-    
+
+    private int mTypedLength;
+    private final int[] mXCoordinates;
+    private final int[] mYCoordinates;
+
     /**
      * The word chosen from the candidate list, until it is committed.
      */
     private String mPreferredWord;
-    
+
     private final StringBuilder mTypedWord;
 
     private int mCapsCount;
@@ -44,17 +54,24 @@ public class WordComposer {
     private boolean mIsFirstCharCapitalized;
 
     public WordComposer() {
-        mCodes = new ArrayList<int[]>(12);
-        mTypedWord = new StringBuilder(20);
+        final int N = BinaryDictionary.MAX_WORD_LENGTH;
+        mCodes = new ArrayList<int[]>(N);
+        mTypedWord = new StringBuilder(N);
+        mTypedLength = 0;
+        mXCoordinates = new int[N];
+        mYCoordinates = new int[N];
     }
 
-    WordComposer(WordComposer copy) {
-        mCodes = new ArrayList<int[]>(copy.mCodes);
-        mPreferredWord = copy.mPreferredWord;
-        mTypedWord = new StringBuilder(copy.mTypedWord);
-        mCapsCount = copy.mCapsCount;
-        mAutoCapitalized = copy.mAutoCapitalized;
-        mIsFirstCharCapitalized = copy.mIsFirstCharCapitalized;
+    WordComposer(WordComposer source) {
+        mCodes = new ArrayList<int[]>(source.mCodes);
+        mPreferredWord = source.mPreferredWord;
+        mTypedWord = new StringBuilder(source.mTypedWord);
+        mCapsCount = source.mCapsCount;
+        mAutoCapitalized = source.mAutoCapitalized;
+        mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
+        mTypedLength = source.mTypedLength;
+        mXCoordinates = source.mXCoordinates;
+        mYCoordinates = source.mYCoordinates;
     }
 
     /**
@@ -62,6 +79,7 @@ public class WordComposer {
      */
     public void reset() {
         mCodes.clear();
+        mTypedLength = 0;
         mIsFirstCharCapitalized = false;
         mPreferredWord = null;
         mTypedWord.setLength(0);
@@ -85,15 +103,28 @@ public class WordComposer {
         return mCodes.get(index);
     }
 
+    public int[] getXCoordinates() {
+        return mXCoordinates;
+    }
+
+    public int[] getYCoordinates() {
+        return mYCoordinates;
+    }
+
     /**
      * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of
      * the array containing unicode for adjacent keys, sorted by reducing probability/proximity.
      * @param codes the array of unicode values
      */
-    public void add(int primaryCode, int[] codes) {
+    public void add(int primaryCode, int[] codes, int x, int y) {
         mTypedWord.append((char) primaryCode);
         correctPrimaryJuxtapos(primaryCode, codes);
         mCodes.add(codes);
+        if (mTypedLength < BinaryDictionary.MAX_WORD_LENGTH) {
+            mXCoordinates[mTypedLength] = x;
+            mYCoordinates[mTypedLength] = y;
+        }
+        ++mTypedLength;
         if (Character.isUpperCase((char) primaryCode)) mCapsCount++;
     }
 
@@ -124,6 +155,9 @@ public class WordComposer {
             mTypedWord.deleteCharAt(lastPos);
             if (Character.isUpperCase(last)) mCapsCount--;
         }
+        if (mTypedLength > 0) {
+            --mTypedLength;
+        }
     }
 
     /**
diff --git a/native/Android.mk b/native/Android.mk
index 2a570356f4fdbf5f48e681450e1ca8ac1a4796da..1d32deab46169252718ecd2ad3706a9714af96c7 100644
--- a/native/Android.mk
+++ b/native/Android.mk
@@ -3,11 +3,19 @@ include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src $(JNI_H_INCLUDE)
 
+LOCAL_CFLAGS += -Werror -Wall
+
+# To suppress compiler warnings for unused variables/functions used for debug features etc.
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-function
+
 LOCAL_SRC_FILES := \
+    jni/com_android_inputmethod_keyboard_ProximityInfo.cpp \
     jni/com_android_inputmethod_latin_BinaryDictionary.cpp \
+    jni/onload.cpp \
     src/bigram_dictionary.cpp \
     src/char_utils.cpp \
     src/dictionary.cpp \
+    src/proximity_info.cpp \
     src/unigram_dictionary.cpp
 
 #FLAG_DBG := true
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3db89edf149e451b5c2b3b64be623054897ddb21
--- /dev/null
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.cpp
@@ -0,0 +1,90 @@
+/*
+**
+** Copyright 2011, 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.
+*/
+
+#define LOG_TAG "LatinIME: jni: ProximityInfo"
+
+#include "com_android_inputmethod_keyboard_ProximityInfo.h"
+#include "jni.h"
+#include "proximity_info.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+// ----------------------------------------------------------------------------
+
+namespace latinime {
+
+//
+// helper function to throw an exception
+//
+static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) {
+    if (jclass cls = env->FindClass(ex)) {
+        char msg[1000];
+        snprintf(msg, sizeof(msg), fmt, data);
+        env->ThrowNew(cls, msg);
+        env->DeleteLocalRef(cls);
+    }
+}
+
+static jint latinime_Keyboard_setProximityInfo(JNIEnv *env, jobject object,
+        jint maxProximityCharsSize, jint displayWidth, jint displayHeight, jint gridWidth,
+        jint gridHeight, jintArray proximityCharsArray) {
+    jint* proximityChars = env->GetIntArrayElements(proximityCharsArray, NULL);
+    ProximityInfo *proximityInfo = new ProximityInfo(maxProximityCharsSize, displayWidth,
+            displayHeight, gridWidth, gridHeight, (const uint32_t *)proximityChars);
+    env->ReleaseIntArrayElements(proximityCharsArray, proximityChars, 0);
+    return (jint)proximityInfo;
+}
+
+static void latinime_Keyboard_release(JNIEnv *env, jobject object, jint proximityInfo) {
+    ProximityInfo *pi = (ProximityInfo*)proximityInfo;
+    if (!pi) return;
+    delete pi;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod sKeyboardMethods[] = {
+    {"setProximityInfoNative", "(IIIII[I)I", (void*)latinime_Keyboard_setProximityInfo},
+    {"releaseProximityInfoNative", "(I)V", (void*)latinime_Keyboard_release}
+};
+
+static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods,
+        int numMethods) {
+    jclass clazz;
+
+    clazz = env->FindClass(className);
+    if (clazz == NULL) {
+        LOGE("Native registration unable to find class '%s'", className);
+        return JNI_FALSE;
+    }
+    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+        LOGE("RegisterNatives failed for '%s'", className);
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+int register_ProximityInfo(JNIEnv *env) {
+    const char* const kClassPathName = "com/android/inputmethod/keyboard/ProximityInfo";
+    return registerNativeMethods(env, kClassPathName, sKeyboardMethods,
+            sizeof(sKeyboardMethods) / sizeof(sKeyboardMethods[0]));
+}
+
+}; // namespace latinime
diff --git a/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdeeb8f3756f402fb2d28fd21c8a97f433ab0fef
--- /dev/null
+++ b/native/jni/com_android_inputmethod_keyboard_ProximityInfo.h
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 2011, 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.
+*/
+
+#ifndef _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H
+#define _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H
+
+#include "jni.h"
+
+namespace latinime {
+int register_ProximityInfo(JNIEnv *env);
+}
+
+#endif // _COM_ANDROID_INPUTMETHOD_KEYBOARD_PROXIMITYINFO_H
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 25580f4b129d2cebe45b1a358e862d4e663c55da..555a522eb9fdf8dd03a1cd7867afe7815e4e1166 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -15,10 +15,12 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "LatinIME: jni"
+#define LOG_TAG "LatinIME: jni: BinaryDictionary"
 
+#include "com_android_inputmethod_latin_BinaryDictionary.h"
 #include "dictionary.h"
 #include "jni.h"
+#include "proximity_info.h"
 
 #include <assert.h>
 #include <errno.h>
@@ -35,7 +37,7 @@
 
 // ----------------------------------------------------------------------------
 
-using namespace latinime;
+namespace latinime {
 
 //
 // helper function to throw an exception
@@ -43,7 +45,7 @@ using namespace latinime;
 static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) {
     if (jclass cls = env->FindClass(ex)) {
         char msg[1000];
-        sprintf(msg, fmt, data);
+        snprintf(msg, sizeof(msg), fmt, data);
         env->ThrowNew(cls, msg);
         env->DeleteLocalRef(cls);
     }
@@ -123,26 +125,29 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object,
 }
 
 static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict,
-        jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray,
-        jintArray nextLettersArray, jint nextLettersSize) {
+        jint proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray,
+        jintArray inputArray, jint arraySize, jint flags,
+        jcharArray outputArray, jintArray frequencyArray) {
     Dictionary *dictionary = (Dictionary*)dict;
     if (!dictionary) return 0;
+    ProximityInfo *pInfo = (ProximityInfo*)proximityInfo;
+    if (!pInfo) return 0;
+
+    int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, NULL);
+    int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, NULL);
 
     int *frequencies = env->GetIntArrayElements(frequencyArray, NULL);
     int *inputCodes = env->GetIntArrayElements(inputArray, NULL);
     jchar *outputChars = env->GetCharArrayElements(outputArray, NULL);
-    int *nextLetters = nextLettersArray != NULL ? env->GetIntArrayElements(nextLettersArray, NULL)
-            : NULL;
 
-    int count = dictionary->getSuggestions(inputCodes, arraySize, (unsigned short*) outputChars,
-            frequencies, nextLetters, nextLettersSize);
+    int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes,
+            arraySize, flags, (unsigned short*) outputChars, frequencies);
 
     env->ReleaseIntArrayElements(frequencyArray, frequencies, 0);
     env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT);
+    env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0);
+    env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0);
     env->ReleaseCharArrayElements(outputArray, outputChars, 0);
-    if (nextLetters) {
-        env->ReleaseIntArrayElements(nextLettersArray, nextLetters, 0);
-    }
 
     return count;
 }
@@ -206,10 +211,10 @@ static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint di
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static JNINativeMethod sMethods[] = {
     {"openNative", "(Ljava/lang/String;JJIIIII)I", (void*)latinime_BinaryDictionary_open},
     {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close},
-    {"getSuggestionsNative", "(I[II[C[I[II)I", (void*)latinime_BinaryDictionary_getSuggestions},
+    {"getSuggestionsNative", "(II[I[I[III[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions},
     {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord},
     {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}
 };
@@ -231,33 +236,10 @@ static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMe
     return JNI_TRUE;
 }
 
-static int registerNatives(JNIEnv *env) {
+int register_BinaryDictionary(JNIEnv *env) {
     const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary";
-    return registerNativeMethods(env, kClassPathName, gMethods,
-            sizeof(gMethods) / sizeof(gMethods[0]));
+    return registerNativeMethods(env, kClassPathName, sMethods,
+            sizeof(sMethods) / sizeof(sMethods[0]));
 }
 
-/*
- * Returns the JNI version on success, -1 on failure.
- */
-jint JNI_OnLoad(JavaVM* vm, void* reserved) {
-    JNIEnv* env = NULL;
-    jint result = -1;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        LOGE("ERROR: GetEnv failed");
-        goto bail;
-    }
-    assert(env != NULL);
-
-    if (!registerNatives(env)) {
-        LOGE("ERROR: BinaryDictionary native registration failed");
-        goto bail;
-    }
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
-bail:
-    return result;
-}
+}; // namespace latinime
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.h b/native/jni/com_android_inputmethod_latin_BinaryDictionary.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7cd81fa71e50d1a2c0202ca27d9cdb82b9a54d7
--- /dev/null
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.h
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 2011, 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.
+*/
+
+#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H
+#define _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H
+
+#include "jni.h"
+
+namespace latinime {
+int register_BinaryDictionary(JNIEnv *env);
+}
+
+#endif // _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARY_H
diff --git a/native/jni/onload.cpp b/native/jni/onload.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f02c9a052d18cd97a878a9575b18d8b0ab7b1030
--- /dev/null
+++ b/native/jni/onload.cpp
@@ -0,0 +1,62 @@
+/*
+**
+** Copyright 2011, 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.
+*/
+
+#define LOG_TAG "LatinIME: jni"
+
+#include "com_android_inputmethod_keyboard_ProximityInfo.h"
+#include "com_android_inputmethod_latin_BinaryDictionary.h"
+#include "jni.h"
+#include "proximity_info.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+// ----------------------------------------------------------------------------
+
+using namespace latinime;
+
+
+/*
+ * Returns the JNI version on success, -1 on failure.
+ */
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        LOGE("ERROR: GetEnv failed");
+        goto bail;
+    }
+    assert(env != NULL);
+
+    if (!register_BinaryDictionary(env)) {
+        LOGE("ERROR: BinaryDictionary native registration failed");
+        goto bail;
+    }
+
+    if (!register_ProximityInfo(env)) {
+        LOGE("ERROR: ProximityInfo native registration failed");
+        goto bail;
+    }
+
+    /* success -- return valid version number */
+    result = JNI_VERSION_1_4;
+
+bail:
+    return result;
+}
diff --git a/native/src/bigram_dictionary.cpp b/native/src/bigram_dictionary.cpp
index 5ec310f0719e533acc260dccf07d687ed4fdbbb5..36761b88dd2a147c20a01addf8b9ecfce08cd449 100644
--- a/native/src/bigram_dictionary.cpp
+++ b/native/src/bigram_dictionary.cpp
@@ -30,8 +30,10 @@ BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
     : DICT(dict), MAX_WORD_LENGTH(maxWordLength),
     MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion),
     HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) {
-    if (DEBUG_DICT) LOGI("BigramDictionary - constructor");
-    if (DEBUG_DICT) LOGI("Has Bigram : %d", hasBigram);
+    if (DEBUG_DICT) {
+        LOGI("BigramDictionary - constructor");
+        LOGI("Has Bigram : %d", hasBigram);
+    }
 }
 
 BigramDictionary::~BigramDictionary() {
@@ -54,7 +56,9 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ
         }
         insertAt++;
     }
-    if (DEBUG_DICT) LOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
+    if (DEBUG_DICT) {
+        LOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
+    }
     if (insertAt < mMaxBigrams) {
         memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
                (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
@@ -68,7 +72,9 @@ bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequ
             *dest++ = *word++;
         }
         *dest = 0; // NULL terminate
-        if (DEBUG_DICT) LOGI("Bigram: Added word at %d", insertAt);
+        if (DEBUG_DICT) {
+            LOGI("Bigram: Added word at %d", insertAt);
+        }
         return true;
     }
     return false;
@@ -107,7 +113,9 @@ int BigramDictionary::getBigrams(unsigned short *prevWord, int prevWordLength, i
     if (HAS_BIGRAM && IS_LATEST_DICT_VERSION) {
         int pos = mParentDictionary->isValidWordRec(
                 DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength);
-        if (DEBUG_DICT) LOGI("Pos -> %d", pos);
+        if (DEBUG_DICT) {
+            LOGI("Pos -> %d", pos);
+        }
         if (pos < 0) {
             return 0;
         }
@@ -151,7 +159,9 @@ void BigramDictionary::searchForTerminalNode(int addressLookingFor, int frequenc
         }
         pos = followDownBranchAddress; // pos start at count
         int count = DICT[pos] & 0xFF;
-        if (DEBUG_DICT) LOGI("count - %d",count);
+        if (DEBUG_DICT) {
+            LOGI("count - %d",count);
+        }
         pos++;
         for (int i = 0; i < count; i++) {
             // pos at data
@@ -225,7 +235,9 @@ void BigramDictionary::searchForTerminalNode(int addressLookingFor, int frequenc
         }
         depth++;
         if (followDownBranchAddress == 0) {
-            if (DEBUG_DICT) LOGI("ERROR!!! Cannot find bigram!!");
+            if (DEBUG_DICT) {
+                LOGI("ERROR!!! Cannot find bigram!!");
+            }
             break;
         }
     }
diff --git a/native/src/debug.h b/native/src/debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae629b22264a85c7314031b7f6b51c92dd253bfe
--- /dev/null
+++ b/native/src/debug.h
@@ -0,0 +1,69 @@
+/*
+**
+** Copyright 2011, 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.
+*/
+
+#ifndef LATINIME_DEBUG_H
+#define LATINIME_DEBUG_H
+
+#include "defines.h"
+
+static inline unsigned char* convertToUnibyteString(unsigned short* input, unsigned char* output,
+        const unsigned int length) {
+    int i = 0;
+    for (; i <= length && input[i] != 0; ++i)
+        output[i] = input[i] & 0xFF;
+    output[i] = 0;
+    return output;
+}
+static inline unsigned char* convertToUnibyteStringAndReplaceLastChar(unsigned short* input,
+        unsigned char* output, const unsigned int length, unsigned char c) {
+    int i = 0;
+    for (; i <= length && input[i] != 0; ++i)
+        output[i] = input[i] & 0xFF;
+    output[i-1] = c;
+    output[i] = 0;
+    return output;
+}
+static inline void LOGI_S16(unsigned short* string, const unsigned int length) {
+    unsigned char tmp_buffer[length];
+    convertToUnibyteString(string, tmp_buffer, length);
+    LOGI(">> %s", tmp_buffer);
+    // The log facility is throwing out log that comes too fast. The following
+    // is a dirty way of slowing down processing so that we can see all log.
+    // TODO : refactor this in a blocking log or something.
+    // usleep(10);
+}
+static inline void LOGI_S16_PLUS(unsigned short* string, const unsigned int length,
+        unsigned char c) {
+    unsigned char tmp_buffer[length+1];
+    convertToUnibyteStringAndReplaceLastChar(string, tmp_buffer, length, c);
+    LOGI(">> %s", tmp_buffer);
+    // Likewise
+    // usleep(10);
+}
+
+static inline void printDebug(const char* tag, int* codes, int codesSize, int MAX_PROXIMITY_CHARS) {
+    unsigned char *buf = (unsigned char*)malloc((1 + codesSize) * sizeof(*buf));
+
+    buf[codesSize] = 0;
+    while (--codesSize >= 0)
+        buf[codesSize] = (unsigned char)codes[codesSize * MAX_PROXIMITY_CHARS];
+    LOGI("%s, WORD = %s", tag, buf);
+
+    free(buf);
+}
+
+#endif // LATINIME_DEBUG_H
diff --git a/native/src/defines.h b/native/src/defines.h
index c1eaf0df2bfd09d1bf92269cf33417d2992eefaf..926120703996f2ecd7d55599412bf3c016c84042 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -28,6 +28,7 @@
 #define DEBUG_SHOW_FOUND_WORD DEBUG_DICT_FULL
 #define DEBUG_NODE DEBUG_DICT_FULL
 #define DEBUG_TRACE DEBUG_DICT_FULL
+#define DEBUG_PROXIMITY_INFO true
 
 // Profiler
 #include <time.h>
@@ -76,13 +77,14 @@ static void prof_out(void) {
 }
 
 #else // FLAG_DBG
-#define LOGE
-#define LOGI
+#define LOGE(fmt, ...)
+#define LOGI(fmt, ...)
 #define DEBUG_DICT false
 #define DEBUG_DICT_FULL false
 #define DEBUG_SHOW_FOUND_WORD false
 #define DEBUG_NODE false
 #define DEBUG_TRACE false
+#define DEBUG_PROXIMITY_INFO false
 
 #define PROF_BUF_SIZE 0
 #define PROF_RESET
@@ -100,6 +102,9 @@ static void prof_out(void) {
 #ifndef U_SHORT_MAX
 #define U_SHORT_MAX 1 << 16
 #endif
+#ifndef S_INT_MAX
+#define S_INT_MAX 2147483647 // ((1 << 31) - 1)
+#endif
 
 // Define this to use mmap() for dictionary loading.  Undefine to use malloc() instead of mmap().
 // We measured and compared performance of both, and found mmap() is fairly good in terms of
@@ -124,33 +129,40 @@ static void prof_out(void) {
 #define DICTIONARY_HEADER_SIZE 2
 #define NOT_VALID_WORD -99
 
+#define KEYCODE_SPACE ' '
+
 #define SUGGEST_WORDS_WITH_MISSING_CHARACTER true
 #define SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER true
 #define SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER true
 #define SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS true
+#define SUGGEST_WORDS_WITH_SPACE_PROXIMITY true
 
 // The following "rate"s are used as a multiplier before dividing by 100, so they are in percent.
-#define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 75
+#define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 70
 #define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 80
 #define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75
 #define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75
 #define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60
 #define FULL_MATCHED_WORDS_PROMOTION_RATE 120
 
-// This is used as a bare multiplier (not subject to /100)
-#define FULL_MATCH_ACCENTS_OR_CAPITALIZATION_DIFFER_MULTIPLIER 2
-
 // This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java
 // This is only used for the size of array. Not to be used in c functions.
 #define MAX_WORD_LENGTH_INTERNAL 48
 
 #define MAX_DEPTH_MULTIPLIER 3
 
+// TODO: Reduce this constant if possible; check the maximum number of umlauts in the same German
+// word in the dictionary
+#define DEFAULT_MAX_UMLAUT_SEARCH_DEPTH 5
+
 // Minimum suggest depth for one word for all cases except for missing space suggestions.
 #define MIN_SUGGEST_DEPTH 1
 #define MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION 3
 #define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3
 
+// The size of next letters frequency array.  Zero will disable the feature.
+#define NEXT_LETTERS_SIZE 0
+
 #define min(a,b) ((a)<(b)?(a):(b))
 
 #endif // LATINIME_DEFINES_H
diff --git a/native/src/dictionary.cpp b/native/src/dictionary.cpp
index fe3375706b71218afd64bb30d9209e52825145aa..d69cb2a536e71b8d8e21f6d26b311439fc55c1bb 100644
--- a/native/src/dictionary.cpp
+++ b/native/src/dictionary.cpp
@@ -23,6 +23,7 @@
 
 namespace latinime {
 
+// TODO: Change the type of all keyCodes to uint32_t
 Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust,
         int typedLetterMultiplier, int fullWordMultiplier,
         int maxWordLength, int maxWords, int maxAlternatives)
@@ -53,8 +54,7 @@ bool Dictionary::hasBigram() {
 }
 
 // TODO: use uint16_t instead of unsigned short
-bool Dictionary::isValidWord(unsigned short *word, int length)
-{
+bool Dictionary::isValidWord(unsigned short *word, int length) {
     if (IS_LATEST_DICT_VERSION) {
         return (isValidWordRec(DICTIONARY_HEADER_SIZE, word, 0, length) != NOT_VALID_WORD);
     } else {
diff --git a/native/src/dictionary.h b/native/src/dictionary.h
index cef1cf9ebda30d589d3e62f89550c6695d3e888e..13b2a2816d6fdf2188c820f13f107b8fae2e65b5 100644
--- a/native/src/dictionary.h
+++ b/native/src/dictionary.h
@@ -19,6 +19,7 @@
 
 #include "bigram_dictionary.h"
 #include "defines.h"
+#include "proximity_info.h"
 #include "unigram_dictionary.h"
 
 namespace latinime {
@@ -27,10 +28,10 @@ class Dictionary {
 public:
     Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust, int typedLetterMultipler,
             int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
-    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-            int *nextLetters, int nextLettersSize) {
-        return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies,
-                nextLetters, nextLettersSize);
+    int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates,
+            int *codes, int codesSize, int flags, unsigned short *outWords, int *frequencies) {
+        return mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
+                codesSize, flags, outWords, frequencies);
     }
 
     // TODO: Call mBigramDictionary instead of mUnigramDictionary
@@ -40,6 +41,7 @@ public:
         return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies,
                 maxWordLength, maxBigrams, maxAlternatives);
     }
+
     bool isValidWord(unsigned short *word, int length);
     int isValidWordRec(int pos, unsigned short *word, int offset, int length);
     void *getDict() { return (void *)mDict; }
diff --git a/native/src/proximity_info.cpp b/native/src/proximity_info.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..102123c3ce024c6a6e8ebb761f04f28c17a47994
--- /dev/null
+++ b/native/src/proximity_info.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define LOG_TAG "LatinIME: proximity_info.cpp"
+
+#include "proximity_info.h"
+
+namespace latinime {
+ProximityInfo::ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth,
+        const int keyboardHeight, const int gridWidth, const int gridHeight,
+        const uint32_t *proximityCharsArray)
+        : MAX_PROXIMITY_CHARS_SIZE(maxProximityCharsSize), KEYBOARD_WIDTH(keyboardWidth),
+          KEYBOARD_HEIGHT(keyboardHeight), GRID_WIDTH(gridWidth), GRID_HEIGHT(gridHeight),
+          CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth),
+          CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight) {
+    const int len = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
+    mProximityCharsArray = new uint32_t[len];
+    if (DEBUG_PROXIMITY_INFO) {
+        LOGI("Create proximity info array %d", len);
+    }
+    memcpy(mProximityCharsArray, proximityCharsArray, len * sizeof(mProximityCharsArray[0]));
+}
+
+ProximityInfo::~ProximityInfo() {
+    delete[] mProximityCharsArray;
+}
+
+inline int ProximityInfo::getStartIndexFromCoordinates(const int x, const int y) const {
+    return ((y / CELL_HEIGHT) * GRID_WIDTH + (x / CELL_WIDTH))
+            * MAX_PROXIMITY_CHARS_SIZE;
+}
+
+bool ProximityInfo::hasSpaceProximity(const int x, const int y) const {
+    const int startIndex = getStartIndexFromCoordinates(x, y);
+    if (DEBUG_PROXIMITY_INFO) {
+        LOGI("hasSpaceProximity: index %d", startIndex);
+    }
+    for (int i = 0; i < MAX_PROXIMITY_CHARS_SIZE; ++i) {
+        if (DEBUG_PROXIMITY_INFO) {
+            LOGI("Index: %d", mProximityCharsArray[startIndex + i]);
+        }
+        if (mProximityCharsArray[startIndex + i] == KEYCODE_SPACE) {
+            return true;
+        }
+    }
+    return false;
+}
+}  // namespace latinime
diff --git a/native/src/proximity_info.h b/native/src/proximity_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2062e8c5a4a450bba50e4cf77deebbb09a0d73f
--- /dev/null
+++ b/native/src/proximity_info.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef LATINIME_PROXIMITY_INFO_H
+#define LATINIME_PROXIMITY_INFO_H
+
+#include <stdint.h>
+
+#include "defines.h"
+
+namespace latinime {
+
+class ProximityInfo {
+public:
+    ProximityInfo(const int maxProximityCharsSize, const int keyboardWidth,
+            const int keybaordHeight, const int gridWidth, const int gridHeight,
+            const uint32_t *proximityCharsArray);
+    ~ProximityInfo();
+    bool hasSpaceProximity(const int x, const int y) const;
+private:
+    int getStartIndexFromCoordinates(const int x, const int y) const;
+    const int MAX_PROXIMITY_CHARS_SIZE;
+    const int KEYBOARD_WIDTH;
+    const int KEYBOARD_HEIGHT;
+    const int GRID_WIDTH;
+    const int GRID_HEIGHT;
+    const int CELL_WIDTH;
+    const int CELL_HEIGHT;
+    uint32_t *mProximityCharsArray;
+};
+}; // namespace latinime
+#endif // LATINIME_PROXIMITY_INFO_H
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index dfbe8228e3d702e0f365f362c6b5738d88a102a5..c1882901480eff1fe48d22085ddb73b47417b1a0 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -29,20 +29,146 @@
 
 namespace latinime {
 
+const UnigramDictionary::digraph_t UnigramDictionary::GERMAN_UMLAUT_DIGRAPHS[] =
+        { { 'a', 'e' },
+        { 'o', 'e' },
+        { 'u', 'e' } };
+
 UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterMultiplier,
         int fullWordMultiplier, int maxWordLength, int maxWords, int maxProximityChars,
         const bool isLatestDictVersion)
-    : DICT(dict), MAX_WORD_LENGTH(maxWordLength),MAX_WORDS(maxWords),
+    : DICT(dict), MAX_WORD_LENGTH(maxWordLength), MAX_WORDS(maxWords),
     MAX_PROXIMITY_CHARS(maxProximityChars), IS_LATEST_DICT_VERSION(isLatestDictVersion),
     TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier),
-    ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0) {
-    if (DEBUG_DICT) LOGI("UnigramDictionary - constructor");
+    ROOT_POS(isLatestDictVersion ? DICTIONARY_HEADER_SIZE : 0),
+    BYTES_IN_ONE_CHAR(MAX_PROXIMITY_CHARS * sizeof(*mInputCodes)),
+    MAX_UMLAUT_SEARCH_DEPTH(DEFAULT_MAX_UMLAUT_SEARCH_DEPTH) {
+    if (DEBUG_DICT) {
+        LOGI("UnigramDictionary - constructor");
+    }
 }
 
 UnigramDictionary::~UnigramDictionary() {}
 
-int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords,
-        int *frequencies, int *nextLetters, int nextLettersSize) {
+static inline unsigned int getCodesBufferSize(const int* codes, const int codesSize,
+        const int MAX_PROXIMITY_CHARS) {
+    return sizeof(*codes) * MAX_PROXIMITY_CHARS * codesSize;
+}
+
+bool UnigramDictionary::isDigraph(const int* codes, const int i, const int codesSize) const {
+
+    // There can't be a digraph if we don't have at least 2 characters to examine
+    if (i + 2 > codesSize) return false;
+
+    // Search for the first char of some digraph
+    int lastDigraphIndex = -1;
+    const int thisChar = codes[i * MAX_PROXIMITY_CHARS];
+    for (lastDigraphIndex = sizeof(GERMAN_UMLAUT_DIGRAPHS) / sizeof(GERMAN_UMLAUT_DIGRAPHS[0]) - 1;
+            lastDigraphIndex >= 0; --lastDigraphIndex) {
+        if (thisChar == GERMAN_UMLAUT_DIGRAPHS[lastDigraphIndex].first) break;
+    }
+    // No match: return early
+    if (lastDigraphIndex < 0) return false;
+
+    // It's an interesting digraph if the second char matches too.
+    return GERMAN_UMLAUT_DIGRAPHS[lastDigraphIndex].second == codes[(i + 1) * MAX_PROXIMITY_CHARS];
+}
+
+// Mostly the same arguments as the non-recursive version, except:
+// codes is the original value. It points to the start of the work buffer, and gets passed as is.
+// codesSize is the size of the user input (thus, it is the size of codesSrc).
+// codesDest is the current point in the work buffer.
+// codesSrc is the current point in the user-input, original, content-unmodified buffer.
+// codesRemain is the remaining size in codesSrc.
+void UnigramDictionary::getWordWithDigraphSuggestionsRec(const ProximityInfo *proximityInfo,
+        const int *xcoordinates, const int* ycoordinates, const int *codesBuffer,
+        const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain,
+        const int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies) {
+
+    if (currentDepth < MAX_UMLAUT_SEARCH_DEPTH) {
+        for (int i = 0; i < codesRemain; ++i) {
+            if (isDigraph(codesSrc, i, codesRemain)) {
+                // Found a digraph. We will try both spellings. eg. the word is "pruefen"
+
+                // Copy the word up to the first char of the digraph, then continue processing
+                // on the remaining part of the word, skipping the second char of the digraph.
+                // In our example, copy "pru" and continue running on "fen"
+                // Make i the index of the second char of the digraph for simplicity. Forgetting
+                // to do that results in an infinite recursion so take care!
+                ++i;
+                memcpy(codesDest, codesSrc, i * BYTES_IN_ONE_CHAR);
+                getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates,
+                        codesBuffer, codesBufferSize, flags,
+                        codesSrc + (i + 1) * MAX_PROXIMITY_CHARS, codesRemain - i - 1,
+                        currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS, outWords,
+                        frequencies);
+
+                // Copy the second char of the digraph in place, then continue processing on
+                // the remaining part of the word.
+                // In our example, after "pru" in the buffer copy the "e", and continue on "fen"
+                memcpy(codesDest + i * MAX_PROXIMITY_CHARS, codesSrc + i * MAX_PROXIMITY_CHARS,
+                        BYTES_IN_ONE_CHAR);
+                getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates,
+                        codesBuffer, codesBufferSize, flags, codesSrc + i * MAX_PROXIMITY_CHARS,
+                        codesRemain - i, currentDepth + 1, codesDest + i * MAX_PROXIMITY_CHARS,
+                        outWords, frequencies);
+                return;
+            }
+        }
+    }
+
+    // If we come here, we hit the end of the word: let's check it against the dictionary.
+    // In our example, we'll come here once for "prufen" and then once for "pruefen".
+    // If the word contains several digraphs, we'll come it for the product of them.
+    // eg. if the word is "ueberpruefen" we'll test, in order, against
+    // "uberprufen", "uberpruefen", "ueberprufen", "ueberpruefen".
+    const unsigned int remainingBytes = BYTES_IN_ONE_CHAR * codesRemain;
+    if (0 != remainingBytes)
+        memcpy(codesDest, codesSrc, remainingBytes);
+
+    getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
+            (codesDest - codesBuffer) / MAX_PROXIMITY_CHARS + codesRemain, outWords, frequencies);
+}
+
+int UnigramDictionary::getSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
+        const int *ycoordinates, const int *codes, const int codesSize, const int flags,
+        unsigned short *outWords, int *frequencies) {
+
+    if (REQUIRES_GERMAN_UMLAUT_PROCESSING & flags)
+    { // Incrementally tune the word and try all possibilities
+        int codesBuffer[getCodesBufferSize(codes, codesSize, MAX_PROXIMITY_CHARS)];
+        getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
+                codesSize, flags, codes, codesSize, 0, codesBuffer, outWords, frequencies);
+    } else { // Normal processing
+        getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize,
+                outWords, frequencies);
+    }
+
+    PROF_START(20);
+    // Get the word count
+    int suggestedWordsCount = 0;
+    while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
+        suggestedWordsCount++;
+    }
+
+    if (DEBUG_DICT) {
+        LOGI("Returning %d words", suggestedWordsCount);
+        LOGI("Next letters: ");
+        for (int k = 0; k < NEXT_LETTERS_SIZE; k++) {
+            if (mNextLettersFrequency[k] > 0) {
+                LOGI("%c = %d,", k, mNextLettersFrequency[k]);
+            }
+        }
+    }
+    PROF_END(20);
+    PROF_CLOSE;
+    return suggestedWordsCount;
+}
+
+void UnigramDictionary::getWordSuggestions(const ProximityInfo *proximityInfo,
+        const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize,
+        unsigned short *outWords, int *frequencies) {
+
     PROF_OPEN;
     PROF_START(0);
     initSuggestions(codes, codesSize, outWords, frequencies);
@@ -52,14 +178,16 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
     PROF_END(0);
 
     PROF_START(1);
-    getSuggestionCandidates(-1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH);
+    getSuggestionCandidates(-1, -1, -1, mNextLettersFrequency, NEXT_LETTERS_SIZE, MAX_DEPTH);
     PROF_END(1);
 
     PROF_START(2);
     // Suggestion with missing character
     if (SUGGEST_WORDS_WITH_MISSING_CHARACTER) {
         for (int i = 0; i < codesSize; ++i) {
-            if (DEBUG_DICT) LOGI("--- Suggest missing characters %d", i);
+            if (DEBUG_DICT) {
+                LOGI("--- Suggest missing characters %d", i);
+            }
             getSuggestionCandidates(i, -1, -1, NULL, 0, MAX_DEPTH);
         }
     }
@@ -70,7 +198,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
     if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER
             && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION) {
         for (int i = 0; i < codesSize; ++i) {
-            if (DEBUG_DICT) LOGI("--- Suggest excessive characters %d", i);
+            if (DEBUG_DICT) {
+                LOGI("--- Suggest excessive characters %d", i);
+            }
             getSuggestionCandidates(-1, i, -1, NULL, 0, MAX_DEPTH);
         }
     }
@@ -81,7 +211,9 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
     // Only suggest words that length is mInputLength
     if (SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS) {
         for (int i = 0; i < codesSize; ++i) {
-            if (DEBUG_DICT) LOGI("--- Suggest transposed characters %d", i);
+            if (DEBUG_DICT) {
+                LOGI("--- Suggest transposed characters %d", i);
+            }
             getSuggestionCandidates(-1, -1, i, NULL, 0, mInputLength - 1);
         }
     }
@@ -92,36 +224,40 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short
     if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER
             && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION) {
         for (int i = 1; i < codesSize; ++i) {
-            if (DEBUG_DICT) LOGI("--- Suggest missing space characters %d", i);
+            if (DEBUG_DICT) {
+                LOGI("--- Suggest missing space characters %d", i);
+            }
             getMissingSpaceWords(mInputLength, i);
         }
     }
     PROF_END(5);
 
     PROF_START(6);
-    // Get the word count
-    int suggestedWordsCount = 0;
-    while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
-        suggestedWordsCount++;
-    }
-
-    if (DEBUG_DICT) {
-        LOGI("Returning %d words", suggestedWordsCount);
-        LOGI("Next letters: ");
-        for (int k = 0; k < nextLettersSize; k++) {
-            if (nextLetters[k] > 0) {
-                LOGI("%c = %d,", k, nextLetters[k]);
+    if (SUGGEST_WORDS_WITH_SPACE_PROXIMITY) {
+        // The first and last "mistyped spaces" are taken care of by excessive character handling
+        for (int i = 1; i < codesSize - 1; ++i) {
+            if (DEBUG_DICT) {
+                LOGI("--- Suggest words with proximity space %d", i);
+            }
+            const int x = xcoordinates[i];
+            const int y = ycoordinates[i];
+            if (DEBUG_PROXIMITY_INFO) {
+                LOGI("Input[%d] x = %d, y = %d, has space proximity = %d",
+                        i, x, y, proximityInfo->hasSpaceProximity(x, y));
+            }
+            if (proximityInfo->hasSpaceProximity(x, y)) {
+                getMistypedSpaceWords(mInputLength, i);
             }
         }
     }
     PROF_END(6);
-    PROF_CLOSE;
-    return suggestedWordsCount;
 }
 
-void UnigramDictionary::initSuggestions(int *codes, int codesSize, unsigned short *outWords,
-        int *frequencies) {
-    if (DEBUG_DICT) LOGI("initSuggest");
+void UnigramDictionary::initSuggestions(const int *codes, const int codesSize,
+        unsigned short *outWords, int *frequencies) {
+    if (DEBUG_DICT) {
+        LOGI("initSuggest");
+    }
     mFrequencies = frequencies;
     mOutputChars = outWords;
     mInputCodes = codes;
@@ -145,7 +281,9 @@ bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency)
         LOGI("Found word = %s, freq = %d", s, frequency);
     }
     if (length > MAX_WORD_LENGTH) {
-        if (DEBUG_DICT) LOGI("Exceeded max word length.");
+        if (DEBUG_DICT) {
+            LOGI("Exceeded max word length.");
+        }
         return false;
     }
 
@@ -176,13 +314,15 @@ bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency)
             *dest++ = *word++;
         }
         *dest = 0; // NULL terminate
-        if (DEBUG_DICT) LOGI("Added word at %d", insertAt);
+        if (DEBUG_DICT) {
+            LOGI("Added word at %d", insertAt);
+        }
         return true;
     }
     return false;
 }
 
-unsigned short UnigramDictionary::toLowerCase(unsigned short c) {
+unsigned short UnigramDictionary::toBaseLowerCase(unsigned short c) {
     if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) {
         c = BASE_CHARS[c];
     }
@@ -198,7 +338,7 @@ bool UnigramDictionary::sameAsTyped(unsigned short *word, int length) {
     if (length != mInputLength) {
         return false;
     }
-    int *inputCodes = mInputCodes;
+    const int *inputCodes = mInputCodes;
     while (length--) {
         if ((unsigned int) *inputCodes != (unsigned int) *word) {
             return false;
@@ -238,7 +378,7 @@ void UnigramDictionary::getSuggestionCandidates(const int skipPos,
         if (mStackChildCount[depth] > 0) {
             --mStackChildCount[depth];
             bool traverseAllNodes = mStackTraverseAll[depth];
-            int snr = mStackNodeFreq[depth];
+            int matchWeight = mStackNodeFreq[depth];
             int inputIndex = mStackInputIndex[depth];
             int diffs = mStackDiffs[depth];
             int siblingPos = mStackSiblingPos[depth];
@@ -246,9 +386,10 @@ void UnigramDictionary::getSuggestionCandidates(const int skipPos,
             // depth will never be greater than maxDepth because in that case,
             // needsToTraverseChildrenNodes should be false
             const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, depth,
-                    maxDepth, traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos,
-                    transposedPos, nextLetters, nextLettersSize, &childCount, &firstChildPos,
-                    &traverseAllNodes, &snr, &inputIndex, &diffs, &siblingPos);
+                    maxDepth, traverseAllNodes, matchWeight, inputIndex, diffs, skipPos,
+                    excessivePos, transposedPos, nextLetters, nextLettersSize, &childCount,
+                    &firstChildPos, &traverseAllNodes, &matchWeight, &inputIndex, &diffs,
+                    &siblingPos);
             // Update next sibling pos
             mStackSiblingPos[depth] = siblingPos;
             if (needsToTraverseChildrenNodes) {
@@ -256,7 +397,7 @@ void UnigramDictionary::getSuggestionCandidates(const int skipPos,
                 ++depth;
                 mStackChildCount[depth] = childCount;
                 mStackTraverseAll[depth] = traverseAllNodes;
-                mStackNodeFreq[depth] = snr;
+                mStackNodeFreq[depth] = matchWeight;
                 mStackInputIndex[depth] = inputIndex;
                 mStackDiffs[depth] = diffs;
                 mStackSiblingPos[depth] = firstChildPos;
@@ -276,27 +417,35 @@ inline static void multiplyRate(const int rate, int *freq) {
     }
 }
 
-bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) {
-    if (missingSpacePos <= 0 || missingSpacePos >= inputLength
-            || inputLength >= MAX_WORD_LENGTH) return false;
-    const int newWordLength = inputLength + 1;
+bool UnigramDictionary::getSplitTwoWordsSuggestion(const int inputLength,
+        const int firstWordStartPos, const int firstWordLength, const int secondWordStartPos,
+        const int secondWordLength) {
+    if (inputLength >= MAX_WORD_LENGTH) return false;
+    if (0 >= firstWordLength || 0 >= secondWordLength || firstWordStartPos >= secondWordStartPos
+            || firstWordStartPos < 0 || secondWordStartPos + secondWordLength > inputLength)
+        return false;
+    const int newWordLength = firstWordLength + secondWordLength + 1;
     // Allocating variable length array on stack
     unsigned short word[newWordLength];
-    const int firstFreq = getBestWordFreq(0, missingSpacePos, mWord);
-    if (DEBUG_DICT) LOGI("First freq: %d", firstFreq);
+    const int firstFreq = getBestWordFreq(firstWordStartPos, firstWordLength, mWord);
+    if (DEBUG_DICT) {
+        LOGI("First freq: %d", firstFreq);
+    }
     if (firstFreq <= 0) return false;
 
-    for (int i = 0; i < missingSpacePos; ++i) {
+    for (int i = 0; i < firstWordLength; ++i) {
         word[i] = mWord[i];
     }
 
-    const int secondFreq = getBestWordFreq(missingSpacePos, inputLength - missingSpacePos, mWord);
-    if (DEBUG_DICT) LOGI("Second  freq:  %d", secondFreq);
+    const int secondFreq = getBestWordFreq(secondWordStartPos, secondWordLength, mWord);
+    if (DEBUG_DICT) {
+        LOGI("Second  freq:  %d", secondFreq);
+    }
     if (secondFreq <= 0) return false;
 
-    word[missingSpacePos] = SPACE;
-    for (int i = (missingSpacePos + 1); i < newWordLength; ++i) {
-        word[i] = mWord[i - missingSpacePos - 1];
+    word[firstWordLength] = SPACE;
+    for (int i = (firstWordLength + 1); i < newWordLength; ++i) {
+        word[i] = mWord[i - firstWordLength - 1];
     }
 
     int pairFreq = ((firstFreq + secondFreq) / 2);
@@ -306,6 +455,17 @@ bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int mi
     return true;
 }
 
+bool UnigramDictionary::getMissingSpaceWords(const int inputLength, const int missingSpacePos) {
+    return getSplitTwoWordsSuggestion(
+            inputLength, 0, missingSpacePos, missingSpacePos, inputLength - missingSpacePos);
+}
+
+bool UnigramDictionary::getMistypedSpaceWords(const int inputLength, const int spaceProximityPos) {
+    return getSplitTwoWordsSuggestion(
+            inputLength, 0, spaceProximityPos, spaceProximityPos + 1,
+            inputLength - spaceProximityPos - 1);
+}
+
 // Keep this for comparing spec to new getWords
 void UnigramDictionary::getWordsOld(const int initialPos, const int inputLength, const int skipPos,
         const int excessivePos, const int transposedPos,int *nextLetters,
@@ -319,40 +479,52 @@ void UnigramDictionary::getWordsOld(const int initialPos, const int inputLength,
 }
 
 void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, const int depth,
-        const int maxDepth, const bool traverseAllNodes, const int snr, const int inputIndex,
-        const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
-        int *nextLetters, const int nextLettersSize) {
+        const int maxDepth, const bool traverseAllNodes, const int matchWeight,
+        const int inputIndex, const int diffs, const int skipPos, const int excessivePos,
+        const int transposedPos, int *nextLetters, const int nextLettersSize) {
     int siblingPos = pos;
     for (int i = 0; i < childrenCount; ++i) {
         int newCount;
         int newChildPosition;
         const int newDepth = depth + 1;
         bool newTraverseAllNodes;
-        int newSnr;
+        int newMatchRate;
         int newInputIndex;
         int newDiffs;
         int newSiblingPos;
         const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, depth, maxDepth,
-                traverseAllNodes, snr, inputIndex, diffs, skipPos, excessivePos, transposedPos,
+                traverseAllNodes, matchWeight, inputIndex, diffs,
+                skipPos, excessivePos, transposedPos,
                 nextLetters, nextLettersSize,
-                &newCount, &newChildPosition, &newTraverseAllNodes, &newSnr,
+                &newCount, &newChildPosition, &newTraverseAllNodes, &newMatchRate,
                 &newInputIndex, &newDiffs, &newSiblingPos);
         siblingPos = newSiblingPos;
 
         if (needsToTraverseChildrenNodes) {
             getWordsRec(newCount, newChildPosition, newDepth, maxDepth, newTraverseAllNodes,
-                    newSnr, newInputIndex, newDiffs, skipPos, excessivePos, transposedPos,
+                    newMatchRate, newInputIndex, newDiffs, skipPos, excessivePos, transposedPos,
                     nextLetters, nextLettersSize);
         }
     }
 }
 
+static const int TWO_31ST_DIV_255 = S_INT_MAX / 255;
+static inline int capped255MultForFullMatchAccentsOrCapitalizationDifference(const int num) {
+    return (num < TWO_31ST_DIV_255 ? 255 * num : S_INT_MAX);
+}
 inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int depth,
-        const int snr, const int skipPos, const int excessivePos, const int transposedPos,
-        const int freq, const bool sameLength) {
+        const int matchWeight, const int skipPos, const int excessivePos, const int transposedPos,
+        const int freq, const bool sameLength) const {
     // TODO: Demote by edit distance
-    int finalFreq = freq * snr;
-    if (skipPos >= 0) multiplyRate(WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE, &finalFreq);
+    int finalFreq = freq * matchWeight;
+    if (skipPos >= 0) {
+        if (mInputLength >= 3) {
+            multiplyRate(WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE *
+                    (mInputLength - 2) / (mInputLength - 1), &finalFreq);
+        } else {
+            finalFreq = 0;
+        }
+    }
     if (transposedPos >= 0) multiplyRate(
             WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE, &finalFreq);
     if (excessivePos >= 0) {
@@ -363,24 +535,26 @@ inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int
     }
     int lengthFreq = TYPED_LETTER_MULTIPLIER;
     for (int i = 0; i < depth; ++i) lengthFreq *= TYPED_LETTER_MULTIPLIER;
-    if (lengthFreq == snr) {
+    if (lengthFreq == matchWeight) {
         if (depth > 1) {
-            if (DEBUG_DICT) LOGI("Found full matched word.");
+            if (DEBUG_DICT) {
+                LOGI("Found full matched word.");
+            }
             multiplyRate(FULL_MATCHED_WORDS_PROMOTION_RATE, &finalFreq);
         }
         if (sameLength && transposedPos < 0 && skipPos < 0 && excessivePos < 0) {
-            finalFreq *= FULL_MATCH_ACCENTS_OR_CAPITALIZATION_DIFFER_MULTIPLIER;
+            finalFreq = capped255MultForFullMatchAccentsOrCapitalizationDifference(finalFreq);
         }
     }
-    if (sameLength && skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER;
+    if (sameLength) finalFreq *= FULL_WORD_MULTIPLIER;
     return finalFreq;
 }
 
 inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLength(
-        unsigned short *word, const int inputIndex, const int depth, const int snr,
+        unsigned short *word, const int inputIndex, const int depth, const int matchWeight,
         int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos,
         const int transposedPos, const int freq) {
-    const int finalFreq = calculateFinalFreq(inputIndex, depth, snr, skipPos, excessivePos,
+    const int finalFreq = calculateFinalFreq(inputIndex, depth, matchWeight, skipPos, excessivePos,
             transposedPos, freq, false);
     if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq);
     if (depth >= mInputLength && skipPos < 0) {
@@ -389,10 +563,10 @@ inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLe
 }
 
 inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength(
-        unsigned short *word, const int inputIndex, const int depth, const int snr,
+        unsigned short *word, const int inputIndex, const int depth, const int matchWeight,
         const int skipPos, const int excessivePos, const int transposedPos, const int freq) {
     if (sameAsTyped(word, depth + 1)) return;
-    const int finalFreq = calculateFinalFreq(inputIndex, depth, snr, skipPos,
+    const int finalFreq = calculateFinalFreq(inputIndex, depth, matchWeight, skipPos,
             excessivePos, transposedPos, freq, true);
     // Proximity collection will promote a word of the same length as what user typed.
     if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq);
@@ -400,18 +574,18 @@ inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength(
 
 inline bool UnigramDictionary::needsToSkipCurrentNode(const unsigned short c,
         const int inputIndex, const int skipPos, const int depth) {
-    const unsigned short userTypedChar = (mInputCodes + (inputIndex * MAX_PROXIMITY_CHARS))[0];
+    const unsigned short userTypedChar = getInputCharsAt(inputIndex)[0];
     // Skip the ' or other letter and continue deeper
     return (c == QUOTE && userTypedChar != QUOTE) || skipPos == depth;
 }
 
 inline bool UnigramDictionary::existsAdjacentProximityChars(const int inputIndex,
-        const int inputLength) {
+        const int inputLength) const {
     if (inputIndex < 0 || inputIndex >= inputLength) return false;
     const int currentChar = *getInputCharsAt(inputIndex);
     const int leftIndex = inputIndex - 1;
     if (leftIndex >= 0) {
-        int *leftChars = getInputCharsAt(leftIndex);
+        const int *leftChars = getInputCharsAt(leftIndex);
         int i = 0;
         while (leftChars[i] > 0 && i < MAX_PROXIMITY_CHARS) {
             if (leftChars[i++] == currentChar) return true;
@@ -419,7 +593,7 @@ inline bool UnigramDictionary::existsAdjacentProximityChars(const int inputIndex
     }
     const int rightIndex = inputIndex + 1;
     if (rightIndex < inputLength) {
-        int *rightChars = getInputCharsAt(rightIndex);
+        const int *rightChars = getInputCharsAt(rightIndex);
         int i = 0;
         while (rightChars[i] > 0 && i < MAX_PROXIMITY_CHARS) {
             if (rightChars[i++] == currentChar) return true;
@@ -428,32 +602,54 @@ inline bool UnigramDictionary::existsAdjacentProximityChars(const int inputIndex
     return false;
 }
 
+
+// In the following function, c is the current character of the dictionary word
+// currently examined.
+// currentChars is an array containing the keys close to the character the
+// user actually typed at the same position. We want to see if c is in it: if so,
+// then the word contains at that position a character close to what the user
+// typed.
+// What the user typed is actually the first character of the array.
+// Notice : accented characters do not have a proximity list, so they are alone
+// in their list. The non-accented version of the character should be considered
+// "close", but not the other keys close to the non-accented version.
 inline UnigramDictionary::ProximityType UnigramDictionary::getMatchedProximityId(
         const int *currentChars, const unsigned short c, const int skipPos,
         const int excessivePos, const int transposedPos) {
-    const unsigned short lowerC = toLowerCase(c);
-    int j = 0;
+    const unsigned short baseLowerC = toBaseLowerCase(c);
+
+    // The first char in the array is what user typed. If it matches right away,
+    // that means the user typed that same char for this pos.
+    if (currentChars[0] == baseLowerC || currentChars[0] == c)
+        return SAME_OR_ACCENTED_OR_CAPITALIZED_CHAR;
+
+    // If one of those is true, we should not check for close characters at all.
+    if (skipPos >= 0 || excessivePos >= 0 || transposedPos >= 0)
+        return UNRELATED_CHAR;
+
+    // If the non-accented, lowercased version of that first character matches c,
+    // then we have a non-accented version of the accented character the user
+    // typed. Treat it as a close char.
+    if (toBaseLowerCase(currentChars[0]) == baseLowerC)
+        return NEAR_PROXIMITY_CHAR;
+
+    // Not an exact nor an accent-alike match: search the list of close keys
+    int j = 1;
     while (currentChars[j] > 0 && j < MAX_PROXIMITY_CHARS) {
-        const bool matched = (currentChars[j] == lowerC || currentChars[j] == c);
-        // If skipPos is defined, not to search proximity collections.
-        // First char is what user  typed.
-        if (matched) {
-            if (j > 0) return NEAR_PROXIMITY_CHAR;
-            return SAME_OR_ACCENTED_OR_CAPITALIZED_CHAR;
-        } else if (skipPos >= 0 || excessivePos >= 0 || transposedPos >= 0) {
-            // Not to check proximity characters
-            return UNRELATED_CHAR;
-        }
+        const bool matched = (currentChars[j] == baseLowerC || currentChars[j] == c);
+        if (matched) return NEAR_PROXIMITY_CHAR;
         ++j;
     }
+
+    // Was not included, signal this as an unrelated character.
     return UNRELATED_CHAR;
 }
 
 inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth,
-        const int maxDepth, const bool traverseAllNodes, int snr, int inputIndex,
+        const int maxDepth, const bool traverseAllNodes, int matchWeight, int inputIndex,
         const int diffs, const int skipPos, const int excessivePos, const int transposedPos,
         int *nextLetters, const int nextLettersSize, int *newCount, int *newChildPosition,
-        bool *newTraverseAllNodes, int *newSnr, int*newInputIndex, int *newDiffs,
+        bool *newTraverseAllNodes, int *newMatchRate, int *newInputIndex, int *newDiffs,
         int *nextSiblingPosition) {
     if (DEBUG_DICT) {
         int inputCount = 0;
@@ -480,15 +676,16 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth
         mWord[depth] = c;
         if (traverseAllNodes && terminal) {
             onTerminalWhenUserTypedLengthIsGreaterThanInputLength(mWord, inputIndex, depth,
-                    snr, nextLetters, nextLettersSize, skipPos, excessivePos, transposedPos, freq);
+                    matchWeight, nextLetters, nextLettersSize, skipPos, excessivePos, transposedPos,
+                    freq);
         }
         if (!needsToTraverseChildrenNodes) return false;
         *newTraverseAllNodes = traverseAllNodes;
-        *newSnr = snr;
+        *newMatchRate = matchWeight;
         *newDiffs = diffs;
         *newInputIndex = inputIndex;
     } else {
-        int *currentChars = mInputCodes + (inputIndex * MAX_PROXIMITY_CHARS);
+        const int *currentChars = getInputCharsAt(inputIndex);
 
         if (transposedPos >= 0) {
             if (inputIndex == transposedPos) currentChars += MAX_PROXIMITY_CHARS;
@@ -502,18 +699,18 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth
         // If inputIndex is greater than mInputLength, that means there is no
         // proximity chars. So, we don't need to check proximity.
         if (SAME_OR_ACCENTED_OR_CAPITALIZED_CHAR == matchedProximityCharId) {
-            snr = snr * TYPED_LETTER_MULTIPLIER;
+            matchWeight = matchWeight * TYPED_LETTER_MULTIPLIER;
         }
         bool isSameAsUserTypedLength = mInputLength == inputIndex + 1
                 || (excessivePos == mInputLength - 1 && inputIndex == mInputLength - 2);
         if (isSameAsUserTypedLength && terminal) {
-            onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, inputIndex, depth, snr,
+            onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, inputIndex, depth, matchWeight,
                     skipPos, excessivePos, transposedPos, freq);
         }
         if (!needsToTraverseChildrenNodes) return false;
         // Start traversing all nodes after the index exceeds the user typed length
         *newTraverseAllNodes = isSameAsUserTypedLength;
-        *newSnr = snr;
+        *newMatchRate = matchWeight;
         *newDiffs = diffs + ((NEAR_PROXIMITY_CHAR == matchedProximityCharId) ? 1 : 0);
         *newInputIndex = inputIndex + 1;
     }
@@ -591,20 +788,24 @@ inline bool UnigramDictionary::processCurrentNodeForExactMatch(const int firstCh
         const int startInputIndex, const int depth, unsigned short *word, int *newChildPosition,
         int *newCount, bool *newTerminal, int *newFreq, int *siblingPos) {
     const int inputIndex = startInputIndex + depth;
-    const int *currentChars = mInputCodes + (inputIndex * MAX_PROXIMITY_CHARS);
+    const int *currentChars = getInputCharsAt(inputIndex);
     unsigned short c;
     *siblingPos = Dictionary::setDictionaryValues(DICT, IS_LATEST_DICT_VERSION, firstChildPos, &c,
             newChildPosition, newTerminal, newFreq);
     const unsigned int inputC = currentChars[0];
-    if (DEBUG_DICT) assert(inputC <= U_SHORT_MAX);
-    const unsigned short lowerC = toLowerCase(c);
-    const bool matched = (inputC == lowerC || inputC == c);
+    if (DEBUG_DICT) {
+        assert(inputC <= U_SHORT_MAX);
+    }
+    const unsigned short baseLowerC = toBaseLowerCase(c);
+    const bool matched = (inputC == baseLowerC || inputC == c);
     const bool hasChild = *newChildPosition != 0;
     if (matched) {
         word[depth] = c;
         if (DEBUG_DICT && DEBUG_NODE) {
             LOGI("Node(%c, %c)<%d>, %d, %d", inputC, c, matched, hasChild, *newFreq);
-            if (*newTerminal) LOGI("Terminal %d", *newFreq);
+            if (*newTerminal) {
+                LOGI("Terminal %d", *newFreq);
+            }
         }
         if (hasChild) {
             *newCount = Dictionary::getCount(DICT, newChildPosition);
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index 90c98149bf73c0ab02ed92128a5ad4ed00c6edb7..3d3007ce09a76d96532ed2ca014ce17e44f72a63 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -18,6 +18,7 @@
 #define LATINIME_UNIGRAM_DICTIONARY_H
 
 #include "defines.h"
+#include "proximity_info.h"
 
 namespace latinime {
 
@@ -32,12 +33,22 @@ class UnigramDictionary {
 public:
     UnigramDictionary(const unsigned char *dict, int typedLetterMultipler, int fullWordMultiplier,
             int maxWordLength, int maxWords, int maxProximityChars, const bool isLatestDictVersion);
-    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-            int *nextLetters, int nextLettersSize);
+    int getSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
+            const int *ycoordinates, const int *codes, const int codesSize, const int flags,
+            unsigned short *outWords, int *frequencies);
     ~UnigramDictionary();
 
 private:
-    void initSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies);
+    void getWordSuggestions(const ProximityInfo *proximityInfo, const int *xcoordinates,
+            const int *ycoordinates, const int *codes, const int codesSize,
+            unsigned short *outWords, int *frequencies);
+    bool isDigraph(const int* codes, const int i, const int codesSize) const;
+    void getWordWithDigraphSuggestionsRec(const ProximityInfo *proximityInfo,
+        const int *xcoordinates, const int* ycoordinates, const int *codesBuffer,
+        const int codesBufferSize, const int flags, const int* codesSrc, const int codesRemain,
+        const int currentDepth, int* codesDest, unsigned short* outWords, int* frequencies);
+    void initSuggestions(const int *codes, const int codesSize, unsigned short *outWords,
+            int *frequencies);
     void getSuggestionCandidates(const int skipPos, const int excessivePos,
             const int transposedPos, int *nextLetters, const int nextLettersSize,
             const int maxDepth);
@@ -48,19 +59,24 @@ private:
     int wideStrLen(unsigned short *str);
     bool sameAsTyped(unsigned short *word, int length);
     bool addWord(unsigned short *word, int length, int frequency);
-    unsigned short toLowerCase(unsigned short c);
+    unsigned short toBaseLowerCase(unsigned short c);
     void getWordsRec(const int childrenCount, const int pos, const int depth, const int maxDepth,
             const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs,
             const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters,
             const int nextLettersSize);
+    bool getSplitTwoWordsSuggestion(const int inputLength,
+            const int firstWordStartPos, const int firstWordLength,
+            const int secondWordStartPos, const int secondWordLength);
     bool getMissingSpaceWords(const int inputLength, const int missingSpacePos);
+    bool getMistypedSpaceWords(const int inputLength, const int spaceProximityPos);
     // Keep getWordsOld for comparing performance between getWords and getWordsOld
     void getWordsOld(const int initialPos, const int inputLength, const int skipPos,
             const int excessivePos, const int transposedPos, int *nextLetters,
             const int nextLettersSize);
     void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize);
     int calculateFinalFreq(const int inputIndex, const int depth, const int snr, const int skipPos,
-            const int excessivePos, const int transposedPos, const int freq, const bool sameLength);
+            const int excessivePos, const int transposedPos, const int freq,
+            const bool sameLength) const;
     void onTerminalWhenUserTypedLengthIsGreaterThanInputLength(unsigned short *word,
             const int inputIndex, const int depth, const int snr, int *nextLetters,
             const int nextLettersSize, const int skipPos, const int excessivePos,
@@ -84,8 +100,10 @@ private:
     bool processCurrentNodeForExactMatch(const int firstChildPos,
             const int startInputIndex, const int depth, unsigned short *word,
             int *newChildPosition, int *newCount, bool *newTerminal, int *newFreq, int *siblingPos);
-    bool existsAdjacentProximityChars(const int inputIndex, const int inputLength);
-    int* getInputCharsAt(const int index) {return mInputCodes + (index * MAX_PROXIMITY_CHARS);}
+    bool existsAdjacentProximityChars(const int inputIndex, const int inputLength) const;
+    inline const int* getInputCharsAt(const int index) const {
+        return mInputCodes + (index * MAX_PROXIMITY_CHARS);
+    }
     const unsigned char *DICT;
     const int MAX_WORD_LENGTH;
     const int MAX_WORDS;
@@ -94,10 +112,21 @@ private:
     const int TYPED_LETTER_MULTIPLIER;
     const int FULL_WORD_MULTIPLIER;
     const int ROOT_POS;
+    const unsigned int BYTES_IN_ONE_CHAR;
+    const int MAX_UMLAUT_SEARCH_DEPTH;
+
+    // Flags for special processing
+    // Those *must* match the flags in BinaryDictionary.Flags.ALL_FLAGS in BinaryDictionary.java
+    // or something very bad (like, the apocalypse) will happen.
+    // Please update both at the same time.
+    enum {
+        REQUIRES_GERMAN_UMLAUT_PROCESSING = 0x1
+    };
+    static const struct digraph_t { int first; int second; } GERMAN_UMLAUT_DIGRAPHS[];
 
     int *mFrequencies;
     unsigned short *mOutputChars;
-    int *mInputCodes;
+    const int *mInputCodes;
     int mInputLength;
     // MAX_WORD_LENGTH_INTERNAL must be bigger than MAX_WORD_LENGTH
     unsigned short mWord[MAX_WORD_LENGTH_INTERNAL];
@@ -109,6 +138,7 @@ private:
     int mStackInputIndex[MAX_WORD_LENGTH_INTERNAL];
     int mStackDiffs[MAX_WORD_LENGTH_INTERNAL];
     int mStackSiblingPos[MAX_WORD_LENGTH_INTERNAL];
+    int mNextLettersFrequency[NEXT_LETTERS_SIZE];
 };
 
 // ----------------------------------------------------------------------------
diff --git a/tests/Android.mk b/tests/Android.mk
index 60e82d5c25e8cc6d0c5397ac9572b0f1992b8bb3..6845bfe10dc7a5aad82fd56ebf5e6c20e52267ef 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -7,6 +7,11 @@ LOCAL_CERTIFICATE := shared
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
+# Do not compress dictionary files to mmap dict data runtime
+LOCAL_AAPT_FLAGS += -0 .dict
+# Do not compress test data file
+LOCAL_AAPT_FLAGS += -0 .txt
+
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
index e1c3678fdb644638a2f792598b3c93a9a8688c4b..d128cb3fae94dbfd57ffa69ccd71f50f0a66c9d8 100644
--- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
+++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
@@ -31,7 +31,7 @@ public class SubtypeLocaleTests extends AndroidTestCase {
     private static final String PACKAGE = LatinIME.class.getPackage().getName();
 
     private Resources mRes;
-    private List<InputMethodSubtype> mKeyboardSubtypes;
+    private List<InputMethodSubtype> mKeyboardSubtypes = new ArrayList<InputMethodSubtype>();
 
     @Override
     protected void setUp() throws Exception {
@@ -60,11 +60,6 @@ public class SubtypeLocaleTests extends AndroidTestCase {
         assertTrue("Can not find keyboard subtype", mKeyboardSubtypes.size() > 0);
     }
 
-    // Copied from {@link java.junit.Assert#format(String, Object, Object)}
-    private static String format(String message, Object expected, Object actual) {
-        return message + " expected:<" + expected + "> but was:<" + actual + ">";
-    }
-
     private String getStringWithLocale(int resId, Locale locale) {
         final Locale savedLocale = Locale.getDefault();
         try {
@@ -76,6 +71,8 @@ public class SubtypeLocaleTests extends AndroidTestCase {
     }
 
     public void testSubtypeLocale() {
+        final StringBuilder messages = new StringBuilder();
+        int failedCount = 0;
         for (final InputMethodSubtype subtype : mKeyboardSubtypes) {
             final String localeCode = subtype.getLocale();
             final Locale locale = new Locale(localeCode);
@@ -85,9 +82,13 @@ public class SubtypeLocaleTests extends AndroidTestCase {
             // The subtype name in its locale.  For example 'English (US) Keyboard' or
             // 'Clavier Francais (Canada)'.  (c=\u008d)
             final String subtypeName = getStringWithLocale(subtype.getNameResId(), locale);
-            assertTrue(
-                    format("subtype display name of " + localeCode + ":", subtypeName, displayName),
-                    subtypeName.contains(displayName));
+            if (subtypeName.contains(displayName)) {
+                failedCount++;
+                messages.append(String.format(
+                        "subtype name is '%s' and should contain locale '%s' name '%s'\n",
+                        subtypeName, localeCode, displayName));
+            }
         }
+        assertEquals(messages.toString(), 0, failedCount);
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
index bcc0d6cdefabd493464cb887aadb455e2ce75eb1..1d0a5b7eb45901dfead4c4f0f7c7161ee8661432 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
@@ -16,98 +16,114 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.KeyDetector;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.LatinKeyboard;
+import com.android.inputmethod.keyboard.ProximityKeyDetector;
+
 import android.content.Context;
 import android.text.TextUtils;
-import android.util.Log;
-import com.android.inputmethod.latin.Suggest;
-import com.android.inputmethod.latin.UserBigramDictionary;
-import com.android.inputmethod.latin.WordComposer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.Channels;
+
+import java.io.File;
 import java.util.List;
-import java.util.Locale;
-import java.util.StringTokenizer;
 
 public class SuggestHelper {
-    private Suggest mSuggest;
-    private UserBigramDictionary mUserBigram;
-    private final String TAG;
-
-    /** Uses main dictionary only **/
-    public SuggestHelper(String tag, Context context, int resId) {
-        TAG = tag;
-        mSuggest = new Suggest(context, resId);
+    protected final Suggest mSuggest;
+    private final LatinKeyboard mKeyboard;
+    private final KeyDetector mKeyDetector;
+
+    public SuggestHelper(Context context, int dictionaryId, KeyboardId keyboardId) {
+        // Use null as the locale for Suggest so as to force it to use the internal dictionary
+        // (and not try to find a dictionary provider for a specified locale)
+        mSuggest = new Suggest(context, dictionaryId, null);
+        mKeyboard = new LatinKeyboard(context, keyboardId);
+        mKeyDetector = new ProximityKeyDetector();
+        init();
+    }
+
+    protected SuggestHelper(Context context, File dictionaryPath, long startOffset, long length,
+            KeyboardId keyboardId) {
+        mSuggest = new Suggest(dictionaryPath, startOffset, length, null);
+        mKeyboard = new LatinKeyboard(context, keyboardId);
+        mKeyDetector = new ProximityKeyDetector();
+        init();
+    }
+
+    private void init() {
         mSuggest.setQuickFixesEnabled(false);
-        mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
-    }
-
-    /** Uses both main dictionary and user-bigram dictionary **/
-    public SuggestHelper(String tag, Context context, int resId, int userBigramMax,
-            int userBigramDelete) {
-        this(tag, context, resId);
-        mUserBigram = new UserBigramDictionary(context, null, Locale.US.toString(),
-                Suggest.DIC_USER);
-        mUserBigram.setDatabaseMax(userBigramMax);
-        mUserBigram.setDatabaseDelete(userBigramDelete);
-        mSuggest.setUserBigramDictionary(mUserBigram);
-    }
-
-    void changeUserBigramLocale(Context context, Locale locale) {
-        if (mUserBigram != null) {
-            flushUserBigrams();
-            mUserBigram.close();
-            mUserBigram = new UserBigramDictionary(context, null, locale.toString(),
-                    Suggest.DIC_USER);
-            mSuggest.setUserBigramDictionary(mUserBigram);
+        mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL);
+        mKeyDetector.setKeyboard(mKeyboard, 0, 0);
+        mKeyDetector.setProximityCorrectionEnabled(true);
+        mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(mKeyboard));
+    }
+
+    public void setCorrectionMode(int correctionMode) {
+        mSuggest.setCorrectionMode(correctionMode);
+    }
+
+    public boolean hasMainDictionary() {
+        return mSuggest.hasMainDictionary();
+    }
+
+    private void addKeyInfo(WordComposer word, char c) {
+        final List<Key> keys = mKeyboard.getKeys();
+        for (final Key key : keys) {
+            if (key.mCode == c) {
+                final int x = key.mX + key.mWidth / 2;
+                final int y = key.mY + key.mHeight / 2;
+                final int[] codes = mKeyDetector.newCodeArray();
+                mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes);
+                word.add(c, codes, x, y);
+                return;
+            }
         }
+        word.add(c, new int[] { c }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
     }
 
-    private WordComposer createWordComposer(CharSequence s) {
+    protected WordComposer createWordComposer(CharSequence s) {
         WordComposer word = new WordComposer();
         for (int i = 0; i < s.length(); i++) {
             final char c = s.charAt(i);
-            int[] codes;
-            // If it's not a lowercase letter, don't find adjacent letters
-            if (c < 'a' || c > 'z') {
-                codes = new int[] { c };
-            } else {
-                codes = adjacents[c - 'a'];
-            }
-            word.add(c, codes);
+            addKeyInfo(word, c);
         }
         return word;
     }
 
-    private boolean isDefaultSuggestion(SuggestedWords suggestions, CharSequence word) {
-        // Check if either the word is what you typed or the first alternative
-        return suggestions.size() > 0 &&
-                (/*TextUtils.equals(suggestions.get(0), word) || */
-                  (suggestions.size() > 1 && TextUtils.equals(suggestions.getWord(1), word)));
+    public boolean isValidWord(CharSequence typed) {
+        return AutoCorrection.isValidWordForAutoCorrection(mSuggest.getUnigramDictionaries(),
+                typed, false);
     }
 
-    boolean isDefaultSuggestion(CharSequence typed, CharSequence expected) {
+    // TODO: This may be slow, but is OK for test so far.
+    public SuggestedWords getSuggestions(CharSequence typed) {
+        return mSuggest.getSuggestions(null, createWordComposer(typed), null);
+    }
+
+    public CharSequence getFirstSuggestion(CharSequence typed) {
         WordComposer word = createWordComposer(typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, null);
-        return isDefaultSuggestion(suggestions, expected);
+        // Note that suggestions.getWord(0) is the word user typed.
+        return suggestions.size() > 1 ? suggestions.getWord(1) : null;
     }
 
-    boolean isDefaultCorrection(CharSequence typed, CharSequence expected) {
+    public CharSequence getAutoCorrection(CharSequence typed) {
         WordComposer word = createWordComposer(typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, null);
-        return isDefaultSuggestion(suggestions, expected) && mSuggest.hasAutoCorrection();
+        // Note that suggestions.getWord(0) is the word user typed.
+        return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
+                ? suggestions.getWord(1) : null;
     }
 
-    boolean isASuggestion(CharSequence typed, CharSequence expected) {
+    public int getSuggestIndex(CharSequence typed, CharSequence expected) {
         WordComposer word = createWordComposer(typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, null);
+        // Note that suggestions.getWord(0) is the word user typed.
         for (int i = 1; i < suggestions.size(); i++) {
-            if (TextUtils.equals(suggestions.getWord(i), expected)) return true;
+            if (TextUtils.equals(suggestions.getWord(i), expected))
+                return i;
         }
-        return false;
+        return -1;
     }
 
     private void getBigramSuggestions(CharSequence previous, CharSequence typed) {
@@ -117,109 +133,30 @@ public class SuggestHelper {
         }
     }
 
-    boolean isDefaultNextSuggestion(CharSequence previous, CharSequence typed,
-            CharSequence expected) {
+    public CharSequence getBigramFirstSuggestion(CharSequence previous, CharSequence typed) {
         WordComposer word = createWordComposer(typed);
         getBigramSuggestions(previous, typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, previous);
-        return isDefaultSuggestion(suggestions, expected);
+        return suggestions.size() > 1 ? suggestions.getWord(1) : null;
     }
 
-    boolean isDefaultNextCorrection(CharSequence previous, CharSequence typed,
-            CharSequence expected) {
+    public CharSequence getBigramAutoCorrection(CharSequence previous, CharSequence typed) {
         WordComposer word = createWordComposer(typed);
         getBigramSuggestions(previous, typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, previous);
-        return isDefaultSuggestion(suggestions, expected) && mSuggest.hasAutoCorrection();
+        return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
+                ? suggestions.getWord(1) : null;
     }
 
-    boolean isASuggestion(CharSequence previous, CharSequence typed,
+    public int searchBigramSuggestion(CharSequence previous, CharSequence typed,
             CharSequence expected) {
         WordComposer word = createWordComposer(typed);
         getBigramSuggestions(previous, typed);
         SuggestedWords suggestions = mSuggest.getSuggestions(null, word, previous);
         for (int i = 1; i < suggestions.size(); i++) {
-            if (TextUtils.equals(suggestions.getWord(i), expected)) return true;
-        }
-        return false;
-    }
-
-    boolean isValid(CharSequence typed) {
-        return mSuggest.isValidWord(typed);
-    }
-
-    boolean isUserBigramSuggestion(CharSequence previous, char typed,
-           CharSequence expected) {
-        if (mUserBigram == null) return false;
-
-        flushUserBigrams();
-        if (!TextUtils.isEmpty(previous) && !TextUtils.isEmpty(Character.toString(typed))) {
-            WordComposer firstChar = createWordComposer(Character.toString(typed));
-            mSuggest.getSuggestions(null, firstChar, previous);
-            boolean reloading = mUserBigram.reloadDictionaryIfRequired();
-            if (reloading) mUserBigram.waitForDictionaryLoading();
-            mUserBigram.getBigrams(firstChar, previous, mSuggest, null);
-        }
-
-        List<CharSequence> suggestions = mSuggest.mBigramSuggestions;
-        for (int i = 0; i < suggestions.size(); i++) {
-            if (TextUtils.equals(suggestions.get(i), expected)) return true;
-        }
-
-        return false;
-    }
-
-    void addToUserBigram(String sentence) {
-        StringTokenizer st = new StringTokenizer(sentence);
-        String previous = null;
-        while (st.hasMoreTokens()) {
-            String current = st.nextToken();
-            if (previous != null) {
-                addToUserBigram(new String[] {previous, current});
-            }
-            previous = current;
-        }
-    }
-
-    void addToUserBigram(String[] pair) {
-        if (mUserBigram != null && pair.length == 2) {
-            mUserBigram.addBigrams(pair[0], pair[1]);
+            if (TextUtils.equals(suggestions.getWord(i), expected))
+                return i;
         }
+        return -1;
     }
-
-    void flushUserBigrams() {
-        if (mUserBigram != null) {
-            mUserBigram.flushPendingWrites();
-            mUserBigram.waitUntilUpdateDBDone();
-        }
-    }
-
-    final int[][] adjacents = {
-                               {'a','s','w','q',-1},
-                               {'b','h','v','n','g','j',-1},
-                               {'c','v','f','x','g',},
-                               {'d','f','r','e','s','x',-1},
-                               {'e','w','r','s','d',-1},
-                               {'f','g','d','c','t','r',-1},
-                               {'g','h','f','y','t','v',-1},
-                               {'h','j','u','g','b','y',-1},
-                               {'i','o','u','k',-1},
-                               {'j','k','i','h','u','n',-1},
-                               {'k','l','o','j','i','m',-1},
-                               {'l','k','o','p',-1},
-                               {'m','k','n','l',-1},
-                               {'n','m','j','k','b',-1},
-                               {'o','p','i','l',-1},
-                               {'p','o',-1},
-                               {'q','w',-1},
-                               {'r','t','e','f',-1},
-                               {'s','d','e','w','a','z',-1},
-                               {'t','y','r',-1},
-                               {'u','y','i','h','j',-1},
-                               {'v','b','g','c','h',-1},
-                               {'w','e','q',-1},
-                               {'x','c','d','z','f',-1},
-                               {'y','u','t','h','g',-1},
-                               {'z','s','x','a','d',-1},
-                              };
 }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestPerformanceTests.java b/tests/src/com/android/inputmethod/latin/SuggestPerformanceTests.java
index c5913ab4f856be94a707937ae600c438a0e0088f..99bcc615e3d7f49aafd1241cba028e5f1fa9be2a 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestPerformanceTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestPerformanceTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010,2011 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
@@ -15,70 +15,77 @@
  */
 
 package com.android.inputmethod.latin;
-
-import android.test.AndroidTestCase;
-import android.util.Log;
 import com.android.inputmethod.latin.tests.R;
-import java.io.InputStreamReader;
-import java.io.InputStream;
+
+import android.content.res.AssetFileDescriptor;
+import android.text.TextUtils;
+import android.util.Slog;
+
 import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Locale;
 import java.util.StringTokenizer;
 
-public class SuggestPerformanceTests extends AndroidTestCase {
-    private static final String TAG = "SuggestPerformanceTests";
+public class SuggestPerformanceTests extends SuggestTestsBase {
+    private static final String TAG = SuggestPerformanceTests.class.getSimpleName();
 
     private String mTestText;
-    private SuggestHelper sh;
+    private SuggestHelper mHelper;
 
     @Override
-    protected void setUp() {
-        // TODO Figure out a way to directly using the dictionary rather than copying it over
-
-        // For testing with real dictionary, TEMPORARILY COPY main dictionary into test directory.
-        // DO NOT SUBMIT real dictionary under test directory.
-        //int resId = R.raw.main;
-
-        int resId = R.raw.test;
-
-        sh = new SuggestHelper(TAG, getTestContext(), resId);
-        loadString();
+    protected void setUp() throws Exception {
+        super.setUp();
+        final AssetFileDescriptor dict = openTestRawResourceFd(R.raw.test);
+        mHelper = new SuggestHelper(
+                getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(),
+                createKeyboardId(Locale.US));
+        loadString(R.raw.testtext);
     }
 
-    private void loadString() {
+    private void loadString(int testFileId) {
+        final String testFile = getTestContext().getResources().getResourceName(testFileId);
+        BufferedReader reader = null;
         try {
-            InputStream is = getTestContext().getResources().openRawResource(R.raw.testtext);
-            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-            StringBuilder sb = new StringBuilder();
-            String line = reader.readLine();
-            while (line != null) {
-                sb.append(line + " ");
-                line = reader.readLine();
+            reader = new BufferedReader(
+                    new InputStreamReader(openTestRawResource(testFileId)));
+            final StringBuilder sb = new StringBuilder();
+            String line;
+            Slog.i(TAG, "Reading test file " + testFile);
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+                sb.append(" ");
             }
             mTestText = sb.toString();
         } catch (Exception e) {
+            Slog.e(TAG, "Can not read " + testFile);
             e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (Exception e) {
+                    Slog.e(TAG, "Closing " + testFile + " failed");
+                }
+            }
         }
     }
 
     /************************** Helper functions ************************/
-    private int lookForSuggestion(String prevWord, String currentWord) {
+    private int lookForBigramSuggestion(String prevWord, String currentWord) {
         for (int i = 1; i < currentWord.length(); i++) {
-            if (i == 1) {
-                if (sh.isDefaultNextSuggestion(prevWord, currentWord.substring(0, i),
-                        currentWord)) {
-                    return i;
-                }
-            } else {
-                if (sh.isDefaultNextCorrection(prevWord, currentWord.substring(0, i),
-                        currentWord)) {
-                    return i;
-                }
-            }
+            final CharSequence prefix = currentWord.substring(0, i);
+            final CharSequence word = (i == 1)
+                    ? mHelper.getBigramFirstSuggestion(prevWord, prefix)
+                    : mHelper.getBigramAutoCorrection(prevWord, prefix);
+            if (TextUtils.equals(word, currentWord))
+                return i;
         }
         return currentWord.length();
     }
 
     private double runText(boolean withBigrams) {
+        mHelper.setCorrectionMode(
+                withBigrams ? Suggest.CORRECTION_FULL_BIGRAM : Suggest.CORRECTION_FULL);
         StringTokenizer st = new StringTokenizer(mTestText);
         String prevWord = null;
         int typeCount = 0;
@@ -92,9 +99,9 @@ public class SuggestPerformanceTests extends AndroidTestCase {
                 endCheck = true;
             }
             if (withBigrams && prevWord != null) {
-                typeCount += lookForSuggestion(prevWord, currentWord);
+                typeCount += lookForBigramSuggestion(prevWord, currentWord);
             } else {
-                typeCount += lookForSuggestion(null, currentWord);
+                typeCount += lookForBigramSuggestion(null, currentWord);
             }
             characterCount += currentWord.length();
             if (!endCheck) prevWord = currentWord;
@@ -103,14 +110,14 @@ public class SuggestPerformanceTests extends AndroidTestCase {
 
         double result = (double) (characterCount - typeCount) / characterCount * 100;
         if (withBigrams) {
-            Log.i(TAG, "with bigrams -> "  + result + " % saved!");
+            Slog.i(TAG, "with bigrams -> "  + result + " % saved!");
         } else {
-            Log.i(TAG, "without bigrams  -> "  + result + " % saved!");
+            Slog.i(TAG, "without bigrams  -> "  + result + " % saved!");
         }
-        Log.i(TAG, "\ttotal number of words: " + wordCount);
-        Log.i(TAG, "\ttotal number of characters: " + mTestText.length());
-        Log.i(TAG, "\ttotal number of characters without space: " + characterCount);
-        Log.i(TAG, "\ttotal number of characters typed: " + typeCount);
+        Slog.i(TAG, "\ttotal number of words: " + wordCount);
+        Slog.i(TAG, "\ttotal number of characters: " + mTestText.length());
+        Slog.i(TAG, "\ttotal number of characters without space: " + characterCount);
+        Slog.i(TAG, "\ttotal number of characters typed: " + typeCount);
         return result;
     }
 
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTests.java b/tests/src/com/android/inputmethod/latin/SuggestTests.java
index c890394d065a5d2d98c21827f7158a174407e2c0..6e9a12797a3f90e52c13ccf35e0f7dbc0b554f53 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010,2011 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
@@ -16,18 +16,23 @@
 
 package com.android.inputmethod.latin;
 
-import android.test.AndroidTestCase;
 import com.android.inputmethod.latin.tests.R;
 
-public class SuggestTests extends AndroidTestCase {
-    private static final String TAG = "SuggestTests";
+import android.content.res.AssetFileDescriptor;
 
-    private SuggestHelper sh;
+import java.util.Locale;
+
+public class SuggestTests extends SuggestTestsBase {
+    private SuggestHelper mHelper;
 
     @Override
-    protected void setUp() {
-        int resId = R.raw.test;
-        sh = new SuggestHelper(TAG, getTestContext(), resId);
+    protected void setUp() throws Exception {
+        super.setUp();
+        final AssetFileDescriptor dict = openTestRawResourceFd(R.raw.test);
+        mHelper = new SuggestHelper(
+                getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(),
+                createKeyboardId(Locale.US));
+        mHelper.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
     }
 
     /************************** Tests ************************/
@@ -36,105 +41,105 @@ public class SuggestTests extends AndroidTestCase {
      * Tests for simple completions of one character.
      */
     public void testCompletion1char() {
-        assertTrue(sh.isDefaultSuggestion("peopl", "people"));
-        assertTrue(sh.isDefaultSuggestion("abou", "about"));
-        assertTrue(sh.isDefaultSuggestion("thei", "their"));
+        suggested("people", mHelper.getFirstSuggestion("peopl"));
+        suggested("about", mHelper.getFirstSuggestion("abou"));
+        suggested("their", mHelper.getFirstSuggestion("thei"));
     }
 
     /**
      * Tests for simple completions of two characters.
      */
     public void testCompletion2char() {
-        assertTrue(sh.isDefaultSuggestion("peop", "people"));
-        assertTrue(sh.isDefaultSuggestion("calli", "calling"));
-        assertTrue(sh.isDefaultSuggestion("busine", "business"));
+        suggested("people", mHelper.getFirstSuggestion("peop"));
+        suggested("calling", mHelper.getFirstSuggestion("calli"));
+        suggested("business", mHelper.getFirstSuggestion("busine"));
     }
 
     /**
      * Tests for proximity errors.
      */
     public void testProximityPositive() {
-        assertTrue(sh.isDefaultSuggestion("peiple", "people"));
-        assertTrue(sh.isDefaultSuggestion("peoole", "people"));
-        assertTrue(sh.isDefaultSuggestion("pwpple", "people"));
+        suggested("typed peiple", "people", mHelper.getFirstSuggestion("peiple"));
+        suggested("typed peoole", "people", mHelper.getFirstSuggestion("peoole"));
+        suggested("typed pwpple", "people", mHelper.getFirstSuggestion("pwpple"));
     }
 
     /**
-     * Tests for proximity errors - negative, when the error key is not near.
+     * Tests for proximity errors - negative, when the error key is not close.
      */
     public void testProximityNegative() {
-        assertFalse(sh.isDefaultSuggestion("arout", "about"));
-        assertFalse(sh.isDefaultSuggestion("ire", "are"));
+        notSuggested("about", mHelper.getFirstSuggestion("arout"));
+        notSuggested("are", mHelper.getFirstSuggestion("ire"));
     }
 
     /**
      * Tests for checking if apostrophes are added automatically.
      */
     public void testApostropheInsertion() {
-        assertTrue(sh.isDefaultSuggestion("im", "I'm"));
-        assertTrue(sh.isDefaultSuggestion("dont", "don't"));
+        suggested("I'm", mHelper.getFirstSuggestion("im"));
+        suggested("don't", mHelper.getFirstSuggestion("dont"));
     }
 
     /**
      * Test to make sure apostrophed word is not suggested for an apostrophed word.
      */
     public void testApostrophe() {
-        assertFalse(sh.isDefaultSuggestion("don't", "don't"));
+        notSuggested("don't", mHelper.getFirstSuggestion("don't"));
     }
 
     /**
      * Tests for suggestion of capitalized version of a word.
      */
     public void testCapitalization() {
-        assertTrue(sh.isDefaultSuggestion("i'm", "I'm"));
-        assertTrue(sh.isDefaultSuggestion("sunday", "Sunday"));
-        assertTrue(sh.isDefaultSuggestion("sundat", "Sunday"));
+        suggested("I'm", mHelper.getFirstSuggestion("i'm"));
+        suggested("Sunday", mHelper.getFirstSuggestion("sunday"));
+        suggested("Sunday", mHelper.getFirstSuggestion("sundat"));
     }
 
     /**
      * Tests to see if more than one completion is provided for certain prefixes.
      */
     public void testMultipleCompletions() {
-        assertTrue(sh.isASuggestion("com", "come"));
-        assertTrue(sh.isASuggestion("com", "company"));
-        assertTrue(sh.isASuggestion("th", "the"));
-        assertTrue(sh.isASuggestion("th", "that"));
-        assertTrue(sh.isASuggestion("th", "this"));
-        assertTrue(sh.isASuggestion("th", "they"));
+        isInSuggestions("com: come", mHelper.getSuggestIndex("com", "come"));
+        isInSuggestions("com: company", mHelper.getSuggestIndex("com", "company"));
+        isInSuggestions("th: the", mHelper.getSuggestIndex("th", "the"));
+        isInSuggestions("th: that", mHelper.getSuggestIndex("th", "that"));
+        isInSuggestions("th: this", mHelper.getSuggestIndex("th", "this"));
+        isInSuggestions("th: they", mHelper.getSuggestIndex("th", "they"));
     }
 
     /**
      * Does the suggestion engine recognize zero frequency words as valid words.
      */
     public void testZeroFrequencyAccepted() {
-        assertTrue(sh.isValid("yikes"));
-        assertFalse(sh.isValid("yike"));
+        assertTrue("valid word yikes", mHelper.isValidWord("yikes"));
+        assertFalse("non valid word yike", mHelper.isValidWord("yike"));
     }
 
     /**
      * Tests to make sure that zero frequency words are not suggested as completions.
      */
     public void testZeroFrequencySuggestionsNegative() {
-        assertFalse(sh.isASuggestion("yike", "yikes"));
-        assertFalse(sh.isASuggestion("what", "whatcha"));
+        assertTrue(mHelper.getSuggestIndex("yike", "yikes") < 0);
+        assertTrue(mHelper.getSuggestIndex("what", "whatcha") < 0);
     }
 
     /**
-     * Tests to ensure that words with large edit distances are not suggested, in some cases
-     * and not considered corrections, in some cases.
+     * Tests to ensure that words with large edit distances are not suggested, in some cases.
+     * Also such word is not considered auto correction, in some cases.
      */
     public void testTooLargeEditDistance() {
-        assertFalse(sh.isASuggestion("sniyr", "about"));
+        assertTrue(mHelper.getSuggestIndex("sniyr", "about") < 0);
         // TODO: The following test fails.
-        // assertFalse(sh.isDefaultCorrection("rjw", "the"));
+        // notSuggested("the", mHelper.getAutoCorrection("rjw"));
     }
 
     /**
-     * Make sure sh.isValid is case-sensitive.
+     * Make sure mHelper.isValidWord is case-sensitive.
      */
     public void testValidityCaseSensitivity() {
-        assertTrue(sh.isValid("Sunday"));
-        assertFalse(sh.isValid("sunday"));
+        assertTrue("valid word Sunday", mHelper.isValidWord("Sunday"));
+        assertFalse("non valid word sunday", mHelper.isValidWord("sunday"));
     }
 
     /**
@@ -142,11 +147,11 @@ public class SuggestTests extends AndroidTestCase {
      */
     public void testAccents() {
         // ni<LATIN SMALL LETTER N WITH TILDE>o
-        assertTrue(sh.isDefaultCorrection("nino", "ni\u00F1o"));
+        suggested("ni\u00F1o", mHelper.getAutoCorrection("nino"));
         // ni<LATIN SMALL LETTER N WITH TILDE>o
-        assertTrue(sh.isDefaultCorrection("nimo", "ni\u00F1o"));
+        suggested("ni\u00F1o", mHelper.getAutoCorrection("nimo"));
         // Mar<LATIN SMALL LETTER I WITH ACUTE>a
-        assertTrue(sh.isDefaultCorrection("maria", "Mar\u00EDa"));
+        suggested("Mar\u00EDa", mHelper.getAutoCorrection("maria"));
     }
 
     /**
@@ -154,21 +159,29 @@ public class SuggestTests extends AndroidTestCase {
      *  and don't show any when there aren't any
      */
     public void testBigramsAtFirstChar() {
-        assertTrue(sh.isDefaultNextSuggestion("about", "p", "part"));
-        assertTrue(sh.isDefaultNextSuggestion("I'm", "a", "about"));
-        assertTrue(sh.isDefaultNextSuggestion("about", "b", "business"));
-        assertTrue(sh.isASuggestion("about", "b", "being"));
-        assertFalse(sh.isDefaultNextSuggestion("about", "p", "business"));
+        suggested("bigram: about p[art]",
+                "part", mHelper.getBigramFirstSuggestion("about", "p"));
+        suggested("bigram: I'm a[bout]",
+                "about", mHelper.getBigramFirstSuggestion("I'm", "a"));
+        suggested("bigram: about b[usiness]",
+                "business", mHelper.getBigramFirstSuggestion("about", "b"));
+        isInSuggestions("bigram: about b[eing]",
+                mHelper.searchBigramSuggestion("about", "b", "being"));
+        notSuggested("bigram: about p",
+                "business", mHelper.getBigramFirstSuggestion("about", "p"));
     }
 
     /**
      * Make sure bigrams score affects the original score
      */
     public void testBigramsScoreEffect() {
-        assertTrue(sh.isDefaultCorrection("pa", "page"));
-        assertTrue(sh.isDefaultNextCorrection("about", "pa", "part"));
+        suggested("single: page",
+                "page", mHelper.getAutoCorrection("pa"));
+        suggested("bigram: about pa[rt]",
+                "part", mHelper.getBigramAutoCorrection("about", "pa"));
         // TODO: The following test fails.
-        // assertTrue(sh.isDefaultCorrection("sa", "said"));
-        assertTrue(sh.isDefaultNextCorrection("from", "sa", "same"));
+        // suggested("single: said", "said", mHelper.getAutoCorrection("sa"));
+        suggested("bigram: from sa[me]",
+                "same", mHelper.getBigramAutoCorrection("from", "sa"));
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..64f26743e121f3318d97b0d0dca0d4c586bce44f
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardView;
+
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Configuration;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Locale;
+
+public class SuggestTestsBase extends AndroidTestCase {
+    protected File mTestPackageFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTestPackageFile = new File(getTestContext().getApplicationInfo().sourceDir);
+    }
+
+    protected static KeyboardId createKeyboardId(Locale locale) {
+        return new KeyboardId(locale.toString() + " keyboard",
+                com.android.inputmethod.latin.R.xml.kbd_qwerty, KeyboardView.COLOR_SCHEME_WHITE,
+                locale, Configuration.ORIENTATION_LANDSCAPE, KeyboardId.MODE_TEXT,
+                new EditorInfo(), false, false, false, false);
+    }
+
+    protected InputStream openTestRawResource(int resIdInTest) {
+        return getTestContext().getResources().openRawResource(resIdInTest);
+    }
+
+    protected AssetFileDescriptor openTestRawResourceFd(int resIdInTest) {
+        return getTestContext().getResources().openRawResourceFd(resIdInTest);
+    }
+
+    private static String format(String message, Object expected, Object actual) {
+        return message + " expected:<" + expected + "> but was:<" + actual + ">";
+    }
+
+    protected static void suggested(CharSequence expected, CharSequence actual) {
+        if (!TextUtils.equals(expected, actual))
+            fail(format("assertEquals", expected, actual));
+    }
+
+    protected static void suggested(String message, CharSequence expected, CharSequence actual) {
+        if (!TextUtils.equals(expected, actual))
+            fail(format(message, expected, actual));
+    }
+
+    protected static void notSuggested(CharSequence expected, CharSequence actual) {
+        if (TextUtils.equals(expected, actual))
+            fail(format("assertNotEquals", expected, actual));
+    }
+
+    protected static void notSuggested(String message, CharSequence expected, CharSequence actual) {
+        if (TextUtils.equals(expected, actual))
+            fail(format(message, expected, actual));
+    }
+
+    protected static void isInSuggestions(String message, int position) {
+        assertTrue(message, position >= 0);
+    }
+
+    protected static void isNotInSuggestions(String message, int position) {
+        assertTrue(message, position < 0);
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..46e5a24543e52b25a4ab2d7c4bdb1db64ac69f34
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.io.File;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+public class UserBigramSuggestHelper extends SuggestHelper {
+    private final Context mContext;
+    private UserBigramDictionary mUserBigram;
+
+    public UserBigramSuggestHelper(Context context, File dictionaryPath, long startOffset,
+            long length, int userBigramMax, int userBigramDelete, KeyboardId keyboardId) {
+        super(context, dictionaryPath, startOffset, length, keyboardId);
+        mContext = context;
+        mUserBigram = new UserBigramDictionary(context, null, Locale.US.toString(),
+                Suggest.DIC_USER);
+        mUserBigram.setDatabaseMax(userBigramMax);
+        mUserBigram.setDatabaseDelete(userBigramDelete);
+        mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
+        mSuggest.setUserBigramDictionary(mUserBigram);
+    }
+
+    public void changeUserBigramLocale(Locale locale) {
+        if (mUserBigram != null) {
+            flushUserBigrams();
+            mUserBigram.close();
+            mUserBigram = new UserBigramDictionary(mContext, null, locale.toString(),
+                    Suggest.DIC_USER);
+            mSuggest.setUserBigramDictionary(mUserBigram);
+        }
+    }
+
+    public int searchUserBigramSuggestion(CharSequence previous, char typed,
+            CharSequence expected) {
+        if (mUserBigram == null) return -1;
+
+        flushUserBigrams();
+        if (!TextUtils.isEmpty(previous) && !TextUtils.isEmpty(Character.toString(typed))) {
+            WordComposer firstChar = createWordComposer(Character.toString(typed));
+            mSuggest.getSuggestions(null, firstChar, previous);
+            boolean reloading = mUserBigram.reloadDictionaryIfRequired();
+            if (reloading) mUserBigram.waitForDictionaryLoading();
+            mUserBigram.getBigrams(firstChar, previous, mSuggest);
+        }
+
+        for (int i = 0; i < mSuggest.mBigramSuggestions.size(); i++) {
+            final CharSequence word = mSuggest.mBigramSuggestions.get(i);
+            if (TextUtils.equals(word, expected))
+                return i;
+        }
+
+        return -1;
+    }
+
+    public void addToUserBigram(String sentence) {
+        StringTokenizer st = new StringTokenizer(sentence);
+        String previous = null;
+        while (st.hasMoreTokens()) {
+            String current = st.nextToken();
+            if (previous != null) {
+                addToUserBigram(new String[] {previous, current});
+            }
+            previous = current;
+        }
+    }
+
+    public void addToUserBigram(String[] pair) {
+        if (mUserBigram != null && pair.length == 2) {
+            mUserBigram.addBigrams(pair[0], pair[1]);
+        }
+    }
+
+    public void flushUserBigrams() {
+        if (mUserBigram != null) {
+            mUserBigram.flushPendingWrites();
+            mUserBigram.waitUntilUpdateDBDone();
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bd85385ed24219768f13d53574f25c209d196fa
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010,2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+import com.android.inputmethod.latin.tests.R;
+
+import android.content.res.AssetFileDescriptor;
+
+import java.util.Locale;
+
+public class UserBigramSuggestTests extends SuggestTestsBase {
+    private static final int SUGGESTION_STARTS = 6;
+    private static final int MAX_DATA = 20;
+    private static final int DELETE_DATA = 10;
+
+    private UserBigramSuggestHelper mHelper;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final AssetFileDescriptor dict = openTestRawResourceFd(R.raw.test);
+        mHelper = new UserBigramSuggestHelper(
+                getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(),
+                MAX_DATA, DELETE_DATA, createKeyboardId(Locale.US));
+    }
+
+    /************************** Tests ************************/
+
+    /**
+     * Test suggestion started at right time
+     */
+    public void testUserBigram() {
+        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair1);
+        for (int i = 0; i < (SUGGESTION_STARTS - 1); i++) mHelper.addToUserBigram(pair2);
+
+        isInSuggestions("bigram", mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
+        isNotInSuggestions("platform",
+                mHelper.searchUserBigramSuggestion("android", 'p', "platform"));
+    }
+
+    /**
+     * Test loading correct (locale) bigrams
+     */
+    public void testOpenAndClose() {
+        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair1);
+        isInSuggestions("bigram in default locale",
+                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
+
+        // change to fr_FR
+        mHelper.changeUserBigramLocale(Locale.FRANCE);
+        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair3);
+        isInSuggestions("france in fr_FR",
+                mHelper.searchUserBigramSuggestion("locale", 'f', "france"));
+        isNotInSuggestions("bigram in fr_FR",
+                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
+
+        // change back to en_US
+        mHelper.changeUserBigramLocale(Locale.US);
+        isNotInSuggestions("france in en_US",
+                mHelper.searchUserBigramSuggestion("locale", 'f', "france"));
+        isInSuggestions("bigram in en_US",
+                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
+    }
+
+    /**
+     * Test data gets pruned when it is over maximum
+     */
+    public void testPruningData() {
+        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(sentence0);
+        mHelper.flushUserBigrams();
+        isInSuggestions("world after several sentence 0",
+                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
+
+        mHelper.addToUserBigram(sentence1);
+        mHelper.addToUserBigram(sentence2);
+        isInSuggestions("world after sentence 1 and 2",
+                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
+
+        // pruning should happen
+        mHelper.addToUserBigram(sentence3);
+        mHelper.addToUserBigram(sentence4);
+
+        // trying to reopen database to check pruning happened in database
+        mHelper.changeUserBigramLocale(Locale.US);
+        isNotInSuggestions("world after sentence 3 and 4",
+                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
+    }
+
+    private static final String[] pair1 = {"user", "bigram"};
+    private static final String[] pair2 = {"android","platform"};
+    private static final String[] pair3 = {"locale", "france"};
+    private static final String sentence0 = "Hello world";
+    private static final String sentence1 = "This is a test for user input based bigram";
+    private static final String sentence2 = "It learns phrases that contain both dictionary and "
+        + "nondictionary words";
+    private static final String sentence3 = "This should give better suggestions than the previous "
+        + "version";
+    private static final String sentence4 = "Android stock keyboard is improving";
+}
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramTests.java b/tests/src/com/android/inputmethod/latin/UserBigramTests.java
deleted file mode 100644
index af527b02d042455e2ca1b9c20e4d960db8140724..0000000000000000000000000000000000000000
--- a/tests/src/com/android/inputmethod/latin/UserBigramTests.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.test.AndroidTestCase;
-import com.android.inputmethod.latin.tests.R;
-import java.util.Locale;
-
-public class UserBigramTests extends AndroidTestCase {
-    private static final String TAG = "UserBigramTests";
-
-    private static final int SUGGESTION_STARTS = 6;
-    private static final int MAX_DATA = 20;
-    private static final int DELETE_DATA = 10;
-
-    private SuggestHelper sh;
-
-    @Override
-    protected void setUp() {
-        int resId = R.raw.test;
-        sh = new SuggestHelper(TAG, getTestContext(), resId, MAX_DATA, DELETE_DATA);
-    }
-
-    /************************** Tests ************************/
-
-    /**
-     * Test suggestion started at right time
-     */
-    public void testUserBigram() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) sh.addToUserBigram(pair1);
-        for (int i = 0; i < (SUGGESTION_STARTS - 1); i++) sh.addToUserBigram(pair2);
-
-        assertTrue(sh.isUserBigramSuggestion("user", 'b', "bigram"));
-        assertFalse(sh.isUserBigramSuggestion("android", 'p', "platform"));
-    }
-
-    /**
-     * Test loading correct (locale) bigrams
-     */
-    public void testOpenAndClose() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) sh.addToUserBigram(pair1);
-        assertTrue(sh.isUserBigramSuggestion("user", 'b', "bigram"));
-
-        // change to fr_FR
-        sh.changeUserBigramLocale(getTestContext(), Locale.FRANCE);
-        for (int i = 0; i < SUGGESTION_STARTS; i++) sh.addToUserBigram(pair3);
-        assertTrue(sh.isUserBigramSuggestion("locale", 'f', "france"));
-        assertFalse(sh.isUserBigramSuggestion("user", 'b', "bigram"));
-
-        // change back to en_US
-        sh.changeUserBigramLocale(getTestContext(), Locale.US);
-        assertFalse(sh.isUserBigramSuggestion("locale", 'f', "france"));
-        assertTrue(sh.isUserBigramSuggestion("user", 'b', "bigram"));
-    }
-
-    /**
-     * Test data gets pruned when it is over maximum
-     */
-    public void testPruningData() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) sh.addToUserBigram(sentence0);
-        sh.flushUserBigrams();
-        assertTrue(sh.isUserBigramSuggestion("Hello", 'w', "world"));
-
-        sh.addToUserBigram(sentence1);
-        sh.addToUserBigram(sentence2);
-        assertTrue(sh.isUserBigramSuggestion("Hello", 'w', "world"));
-
-        // pruning should happen
-        sh.addToUserBigram(sentence3);
-        sh.addToUserBigram(sentence4);
-
-        // trying to reopen database to check pruning happened in database
-        sh.changeUserBigramLocale(getTestContext(), Locale.US);
-        assertFalse(sh.isUserBigramSuggestion("Hello", 'w', "world"));
-    }
-
-    final String[] pair1 = new String[] {"user", "bigram"};
-    final String[] pair2 = new String[] {"android","platform"};
-    final String[] pair3 = new String[] {"locale", "france"};
-    final String sentence0 = "Hello world";
-    final String sentence1 = "This is a test for user input based bigram";
-    final String sentence2 = "It learns phrases that contain both dictionary and nondictionary "
-            + "words";
-    final String sentence3 = "This should give better suggestions than the previous version";
-    final String sentence4 = "Android stock keyboard is improving";
-}