diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index b58efe0829e8c746f06dff2058b7a436a738f9c2..cb431959774fa5e0cc829cb986f6226c5285d12e 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -285,6 +285,8 @@
     <string name="subtype_mode_nl_keyboard">Dutch Keyboard</string>
     <!-- Description for Polish keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_pl_keyboard">Polish Keyboard</string>
+    <!-- Description for Portuguese keyboard subtype [CHAR LIMIT=35] -->
+    <string name="subtype_mode_pt_keyboard">Portuguese Keyboard</string>
     <!-- Description for Russian keyboard subtype [CHAR LIMIT=35] -->
     <string name="subtype_mode_ru_keyboard">Russian Keyboard</string>
     <!-- Description for Serbian keyboard subtype [CHAR LIMIT=35] -->
diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml
index e6569667d87c21d74de3f11ff078fe76bc29c207..6b5c223916f2e3681692e7b12f169b433433592d 100644
--- a/java/res/xml-de/kbd_qwerty.xml
+++ b/java/res/xml-de/kbd_qwerty.xml
@@ -28,7 +28,7 @@
     latin:verticalGap="@dimen/key_bottom_gap"
     latin:popupKeyboardTemplate="@xml/kbd_popup_template"
     latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
-    latin:keyboardLocale="de_DE"
+    latin:keyboardLocale="de"
 >
     <include
         latin:keyboardLayout="@xml/kbd_qwertz_rows" />
diff --git a/java/res/xml-es/kbd_qwerty.xml b/java/res/xml-es/kbd_qwerty.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e7c1e09bd4e361d2043a7946ed3dc408b685792
--- /dev/null
+++ b/java/res/xml-es/kbd_qwerty.xml
@@ -0,0 +1,35 @@
+<?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"
+    latin:keyboardLocale="es,es_US"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml-fr/kbd_qwerty.xml
index 2f8e67bb187550631f1f7a029bdf6b1e7d1d518c..e4b73bf21f149966b8b9737c32e8fdb2f7270074 100644
--- a/java/res/xml-fr/kbd_qwerty.xml
+++ b/java/res/xml-fr/kbd_qwerty.xml
@@ -28,7 +28,7 @@
     latin:verticalGap="@dimen/key_bottom_gap"
     latin:popupKeyboardTemplate="@xml/kbd_popup_template"
     latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
-    latin:keyboardLocale="fr_FR"
+    latin:keyboardLocale="fr"
 >
     <include
         latin:keyboardLayout="@xml/kbd_azerty_rows" />
diff --git a/java/res/xml-pl/kbd_qwerty.xml b/java/res/xml-pl/kbd_qwerty.xml
index fad28d641ab43e1b6949d8bba6abcd78c7628924..ea52b296fe607018122ac660eca898abb2f2c5a1 100644
--- a/java/res/xml-pl/kbd_qwerty.xml
+++ b/java/res/xml-pl/kbd_qwerty.xml
@@ -28,7 +28,7 @@
     latin:verticalGap="@dimen/key_bottom_gap"
     latin:popupKeyboardTemplate="@xml/kbd_popup_template"
     latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
-    latin:keyboardLocale="pl_PL"
+    latin:keyboardLocale="pl"
 >
     <include
         latin:keyboardLayout="@xml/kbd_qwerty_rows" />
diff --git a/java/res/xml-pt/kbd_qwerty.xml b/java/res/xml-pt/kbd_qwerty.xml
new file mode 100644
index 0000000000000000000000000000000000000000..64c1a0137d47e0735a370ea2d68002999d47080f
--- /dev/null
+++ b/java/res/xml-pt/kbd_qwerty.xml
@@ -0,0 +1,35 @@
+<?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"
+    latin:keyboardLocale="pt"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml
index e5aea581eb512f7751997bf01143f01bbb1bdf18..065cf3afc3ea9f9ce877119fb5b99e4e5ae4d48e 100644
--- a/java/res/xml-ru/kbd_qwerty.xml
+++ b/java/res/xml-ru/kbd_qwerty.xml
@@ -27,7 +27,7 @@
     latin:verticalGap="@dimen/key_bottom_gap"
     latin:popupKeyboardTemplate="@xml/kbd_popup_template"
     latin:maxPopupKeyboardColumn="@integer/config_max_popup_keyboard_column"
-    latin:keyboardLocale="ru_RU"
+    latin:keyboardLocale="ru"
 >
     <include
         latin:keyboardLayout="@xml/kbd_ru_rows" />
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index df43701d3b7affbf25970cb8143359dac288572f..aba6974a893e8915fa2f5e841c35272602685842 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -150,6 +150,11 @@
             android:imeSubtypeLocale="pl"
             android:imeSubtypeMode="keyboard"
     />
+    <subtype android:icon="@drawable/ic_subtype_keyboard"
+            android:label="@string/subtype_mode_pt_keyboard"
+            android:imeSubtypeLocale="pt"
+            android:imeSubtypeMode="keyboard"
+    />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_mode_ru_keyboard"
             android:imeSubtypeLocale="ru"
diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
index a1b49b4756e38bfae1bf4e4f1293f51a5a8329dd..b8655d112348760fd4b35d4a5bcc915330f21e4a 100644
--- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java
@@ -43,6 +43,8 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map.Entry;
+import java.util.TreeMap;
 
 public class InputLanguageSelection extends PreferenceActivity {
 
@@ -51,21 +53,17 @@ public class InputLanguageSelection extends PreferenceActivity {
     private HashMap<CheckBoxPreference, Locale> mLocaleMap =
             new HashMap<CheckBoxPreference, Locale>();
 
-    private static class Loc implements Comparable<Object> {
+    private static class LocaleEntry implements Comparable<Object> {
         private static Collator sCollator = Collator.getInstance();
 
         private String mLabel;
         public final Locale mLocale;
 
-        public Loc(String label, Locale locale) {
+        public LocaleEntry(String label, Locale locale) {
             this.mLabel = label;
             this.mLocale = locale;
         }
 
-        public void setLabel(String label) {
-            this.mLabel = label;
-        }
-
         @Override
         public String toString() {
             return this.mLabel;
@@ -73,7 +71,7 @@ public class InputLanguageSelection extends PreferenceActivity {
 
         @Override
         public int compareTo(Object o) {
-            return sCollator.compare(this.mLabel, ((Loc) o).mLabel);
+            return sCollator.compare(this.mLabel, ((LocaleEntry) o).mLabel);
         }
     }
 
@@ -85,21 +83,58 @@ public class InputLanguageSelection extends PreferenceActivity {
         mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
         mSelectedLanguages = mPrefs.getString(Settings.PREF_SELECTED_LANGUAGES, "");
         String[] languageList = mSelectedLanguages.split(",");
-        ArrayList<Loc> availableLanguages = getUniqueLocales();
+        ArrayList<LocaleEntry> availableLanguages = getUniqueLocales();
         PreferenceGroup parent = getPreferenceScreen();
+        final HashMap<Long, LocaleEntry> dictionaryIdLocaleMap = new HashMap<Long, LocaleEntry>();
+        final TreeMap<LocaleEntry, Boolean> localeHasDictionaryMap =
+                new TreeMap<LocaleEntry, Boolean>();
         for (int i = 0; i < availableLanguages.size(); i++) {
-            Locale locale = availableLanguages.get(i).mLocale;
-            final Pair<Boolean, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale);
-            final boolean hasDictionary = hasDictionaryOrLayout.first;
+            LocaleEntry loc = availableLanguages.get(i);
+            Locale locale = loc.mLocale;
+            final Pair<Long, Boolean> hasDictionaryOrLayout = hasDictionaryOrLayout(locale);
+            final Long dictionaryId = hasDictionaryOrLayout.first;
             final boolean hasLayout = hasDictionaryOrLayout.second;
+            final boolean hasDictionary = dictionaryId != null;
             // Add this locale to the supported list if:
-            // 1) this locale has a layout/ 2) this locale has a dictionary and the length
-            // of the locale is equal to or larger than 5.
-            if (!hasLayout && !(hasDictionary && locale.toString().length() >= 5)) {
+            // 1) this locale has a layout/ 2) this locale has a dictionary
+            // If some locales have no layout but have a same dictionary, the shortest locale
+            // will be added to the supported list.
+            if (!hasLayout && !hasDictionary) {
                 continue;
             }
+            if (hasLayout) {
+                localeHasDictionaryMap.put(loc, hasDictionary);
+            }
+            if (!hasDictionary) {
+                continue;
+            }
+            if (dictionaryIdLocaleMap.containsKey(dictionaryId)) {
+                final String newLocale = locale.toString();
+                final String oldLocale =
+                        dictionaryIdLocaleMap.get(dictionaryId).mLocale.toString();
+                // Check if this locale is more appropriate to be the candidate of the input locale.
+                if (oldLocale.length() <= newLocale.length() && !hasLayout) {
+                    // Don't add this new locale to the map<dictionary id, locale> if:
+                    // 1) the new locale's name is longer than the existing one, and
+                    // 2) the new locale doesn't have its layout
+                    continue;
+                }
+            }
+            dictionaryIdLocaleMap.put(dictionaryId, loc);
+        }
+
+        for (LocaleEntry localeEntry : dictionaryIdLocaleMap.values()) {
+            if (!localeHasDictionaryMap.containsKey(localeEntry)) {
+                localeHasDictionaryMap.put(localeEntry, true);
+            }
+        }
+
+        for (Entry<LocaleEntry, Boolean> entry : localeHasDictionaryMap.entrySet()) {
+            final LocaleEntry localeEntry = entry.getKey();
+            final Locale locale = localeEntry.mLocale;
+            final Boolean hasDictionary = entry.getValue();
             CheckBoxPreference pref = new CheckBoxPreference(this);
-            pref.setTitle(SubtypeSwitcher.getFullDisplayName(locale, true));
+            pref.setTitle(localeEntry.mLabel);
             boolean checked = isLocaleIn(locale, languageList);
             pref.setChecked(checked);
             if (hasDictionary) {
@@ -118,11 +153,11 @@ public class InputLanguageSelection extends PreferenceActivity {
         return false;
     }
 
-    private Pair<Boolean, Boolean> hasDictionaryOrLayout(Locale locale) {
-        if (locale == null) return new Pair<Boolean, Boolean>(false, false);
+    private Pair<Long, Boolean> hasDictionaryOrLayout(Locale locale) {
+        if (locale == null) return new Pair<Long, Boolean>(null, false);
         final Resources res = getResources();
         final Locale saveLocale = Utils.setSystemLocale(res, locale);
-        final boolean hasDictionary = DictionaryFactory.isDictionaryAvailable(this, locale);
+        final Long dictionaryId = DictionaryFactory.getDictionaryId(this, locale);
         boolean hasLayout = false;
 
         try {
@@ -141,7 +176,7 @@ public class InputLanguageSelection extends PreferenceActivity {
         } catch (IOException e) {
         }
         Utils.setSystemLocale(res, saveLocale);
-        return new Pair<Boolean, Boolean>(hasDictionary, hasLayout);
+        return new Pair<Long, Boolean>(dictionaryId, hasLayout);
     }
 
     private String get5Code(Locale locale) {
@@ -174,13 +209,13 @@ public class InputLanguageSelection extends PreferenceActivity {
         SharedPreferencesCompat.apply(editor);
     }
 
-    public ArrayList<Loc> getUniqueLocales() {
+    public ArrayList<LocaleEntry> getUniqueLocales() {
         String[] locales = getAssets().getLocales();
         Arrays.sort(locales);
-        ArrayList<Loc> uniqueLocales = new ArrayList<Loc>();
+        ArrayList<LocaleEntry> uniqueLocales = new ArrayList<LocaleEntry>();
 
         final int origSize = locales.length;
-        Loc[] preprocess = new Loc[origSize];
+        LocaleEntry[] preprocess = new LocaleEntry[origSize];
         int finalSize = 0;
         for (int i = 0 ; i < origSize; i++ ) {
             String s = locales[i];
@@ -202,26 +237,13 @@ public class InputLanguageSelection extends PreferenceActivity {
 
             if (finalSize == 0) {
                 preprocess[finalSize++] =
-                        new Loc(SubtypeSwitcher.getFullDisplayName(l, true), l);
+                        new LocaleEntry(SubtypeSwitcher.getFullDisplayName(l, false), l);
             } else {
-                // check previous entry:
-                //  same lang and a country -> upgrade to full name and
-                //    insert ours with full name
-                //  diff lang -> insert ours with lang-only name
-                if (preprocess[finalSize-1].mLocale.getLanguage().equals(
-                        language)) {
-                    preprocess[finalSize-1].setLabel(SubtypeSwitcher.getFullDisplayName(
-                            preprocess[finalSize-1].mLocale, false));
-                    preprocess[finalSize++] =
-                            new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l);
+                if (s.equals("zz_ZZ")) {
+                    // ignore this locale
                 } else {
-                    String displayName;
-                    if (s.equals("zz_ZZ")) {
-                        // ignore this locale
-                    } else {
-                        displayName = SubtypeSwitcher.getFullDisplayName(l, true);
-                        preprocess[finalSize++] = new Loc(displayName, l);
-                    }
+                    final String displayName = SubtypeSwitcher.getFullDisplayName(l, false);
+                    preprocess[finalSize++] = new LocaleEntry(displayName, l);
                 }
             }
         }
diff --git a/java/src/com/android/inputmethod/latin/Recorrection.java b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
similarity index 73%
rename from java/src/com/android/inputmethod/latin/Recorrection.java
rename to java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
index 3fa6292ba50c620895dff428d81b6d4a2105583d..adf4204f85e64eb7b7b9e6b5b3eb7d030741dd4d 100644
--- a/java/src/com/android/inputmethod/latin/Recorrection.java
+++ b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
@@ -14,11 +14,21 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.deprecated.recorrection;
 
 import com.android.inputmethod.compat.InputConnectionCompatUtils;
 import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.latin.AutoCorrection;
+import com.android.inputmethod.latin.CandidateView;
+import com.android.inputmethod.latin.EditingUtils;
+import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Settings;
+import com.android.inputmethod.latin.Suggest;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.TextEntryState;
+import com.android.inputmethod.latin.WordComposer;
 
 import android.content.SharedPreferences;
 import android.content.res.Resources;
@@ -37,7 +47,8 @@ public class Recorrection {
 
     private LatinIME mService;
     private boolean mRecorrectionEnabled = false;
-    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
+    private final ArrayList<RecorrectionSuggestionEntries> mRecorrectionSuggestionsList =
+            new ArrayList<RecorrectionSuggestionEntries>();
 
     public static Recorrection getInstance() {
         return sInstance;
@@ -98,42 +109,42 @@ public class Recorrection {
     }
 
     public void updateRecorrectionSelection(KeyboardSwitcher keyboardSwitcher,
-            CandidateView candidateView, int candidatesStart, int candidatesEnd, int newSelStart,
-            int newSelEnd, int oldSelStart, int lastSelectionStart,
+            CandidateView candidateView, int candidatesStart, int candidatesEnd,
+            int newSelStart, int newSelEnd, int oldSelStart, int lastSelectionStart,
             int lastSelectionEnd, boolean hasUncommittedTypedChars) {
-        if (mRecorrectionEnabled && mService.isShowingSuggestionsStrip()) {
-            // Don't look for corrections if the keyboard is not visible
-            if (keyboardSwitcher.isInputViewShown()) {
-                // Check if we should go in or out of correction mode.
-                if (mService.isSuggestionsRequested()
-                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
-                                || TextEntryState.isRecorrecting())
-                                && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) {
-                    if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) {
-                        mService.mHandler.cancelUpdateBigramPredictions();
-                        mService.mHandler.postUpdateOldSuggestions();
-                    } else {
-                        abortRecorrection(false);
-                        // If showing the "touch again to save" hint, do not replace it. Else,
-                        // show the bigrams if we are at the end of the text, punctuation otherwise.
-                        if (candidateView != null
-                                && !candidateView.isShowingAddToDictionaryHint()) {
-                            InputConnection ic = mService.getCurrentInputConnection();
-                            if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) {
-                                if (!mService.isShowingPunctuationList()) {
-                                    mService.setPunctuationSuggestions();
-                                }
-                            } else {
-                                mService.mHandler.postUpdateBigramPredictions();
-                            }
+        if (!mRecorrectionEnabled) return;
+        if (!mService.isShowingSuggestionsStrip()) return;
+        if (!keyboardSwitcher.isInputViewShown()) return;
+        if (!mService.isSuggestionsRequested()) return;
+        // Don't look for corrections if the keyboard is not visible
+        // Check if we should go in or out of correction mode.
+        if ((candidatesStart == candidatesEnd || newSelStart != oldSelStart || TextEntryState
+                .isRecorrecting())
+                && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) {
+            if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) {
+                mService.mHandler.cancelUpdateBigramPredictions();
+                mService.mHandler.postUpdateOldSuggestions();
+            } else {
+                abortRecorrection(false);
+                // If showing the "touch again to save" hint, do not replace it. Else,
+                // show the bigrams if we are at the end of the text, punctuation
+                // otherwise.
+                if (candidateView != null && !candidateView.isShowingAddToDictionaryHint()) {
+                    InputConnection ic = mService.getCurrentInputConnection();
+                    if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) {
+                        if (!mService.isShowingPunctuationList()) {
+                            mService.setPunctuationSuggestions();
                         }
+                    } else {
+                        mService.mHandler.postUpdateBigramPredictions();
                     }
                 }
             }
         }
     }
 
-    public void saveWordInHistory(WordComposer word, CharSequence result) {
+    public void saveRecorrectionSuggestion(WordComposer word, CharSequence result) {
+        if (!mRecorrectionEnabled) return;
         if (word.size() <= 1) {
             return;
         }
@@ -144,12 +155,13 @@ public class Recorrection {
 
         // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
         final String resultCopy = result.toString();
-        WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(word));
-        mWordHistory.add(entry);
+        RecorrectionSuggestionEntries entry = new RecorrectionSuggestionEntries(
+                resultCopy, new WordComposer(word));
+        mRecorrectionSuggestionsList.add(entry);
     }
 
     public void clearWordsInHistory() {
-        mWordHistory.clear();
+        mRecorrectionSuggestionsList.clear();
     }
 
     /**
@@ -162,9 +174,9 @@ public class Recorrection {
             KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) {
         // If we didn't find a match, search for result in typed word history
         WordComposer foundWord = null;
-        WordAlternatives alternatives = null;
+        RecorrectionSuggestionEntries alternatives = null;
         // Search old suggestions to suggest re-corrected suggestions.
-        for (WordAlternatives entry : mWordHistory) {
+        for (RecorrectionSuggestionEntries entry : mRecorrectionSuggestionsList) {
             if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
                 foundWord = entry.mWordComposer;
                 alternatives = entry;
@@ -186,7 +198,7 @@ public class Recorrection {
         // Found a match, show suggestions
         if (foundWord != null || alternatives != null) {
             if (alternatives == null) {
-                alternatives = new WordAlternatives(touching.mWord, foundWord);
+                alternatives = new RecorrectionSuggestionEntries(touching.mWord, foundWord);
             }
             showRecorrections(suggest, keyboardSwitcher, alternatives);
             if (foundWord != null) {
@@ -201,10 +213,10 @@ public class Recorrection {
 
 
     private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher,
-            WordAlternatives alternatives) {
-        SuggestedWords.Builder builder = alternatives.getAlternatives(suggest, keyboardSwitcher);
+            RecorrectionSuggestionEntries entries) {
+        SuggestedWords.Builder builder = entries.getAlternatives(suggest, keyboardSwitcher);
         builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
-        mService.showSuggestions(builder.build(), alternatives.getOriginalWord());
+        mService.showSuggestions(builder.build(), entries.getOriginalWord());
     }
 
     public void setRecorrectionSuggestions(VoiceProxy voiceProxy, CandidateView candidateView,
diff --git a/java/src/com/android/inputmethod/latin/WordAlternatives.java b/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java
similarity index 83%
rename from java/src/com/android/inputmethod/latin/WordAlternatives.java
rename to java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java
index 0e9914400e6e4dfc8072f1389efdfe36309ad77c..914e2cbc1c752ab14152854f68d15213ddb5dcad 100644
--- a/java/src/com/android/inputmethod/latin/WordAlternatives.java
+++ b/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java
@@ -14,17 +14,20 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.deprecated.recorrection;
 
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.latin.Suggest;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.WordComposer;
 
 import android.text.TextUtils;
 
-public class WordAlternatives {
+public class RecorrectionSuggestionEntries {
     public final CharSequence mChosenWord;
     public final WordComposer mWordComposer;
 
-    public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
+    public RecorrectionSuggestionEntries(CharSequence chosenWord, WordComposer wordComposer) {
         mChosenWord = chosenWord;
         mWordComposer = wordComposer;
     }
@@ -56,4 +59,4 @@ public class WordAlternatives {
             Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) {
         return suggest.getSuggestedWordBuilder(keyboardSwitcher.getInputView(), word, null);
     }
-}
\ No newline at end of file
+}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 605676d703bfbf94d14d3d00ce85946392accbb2..bba331868c5b6f02de7a88b771f6981c4812a99f 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -142,6 +142,25 @@ public class DictionaryFactory {
         return hasDictionary;
     }
 
+    // TODO: Do not use the size of the dictionary as an unique dictionary ID.
+    public static Long getDictionaryId(Context context, Locale locale) {
+        final Resources res = context.getResources();
+        final Locale saveLocale = Utils.setSystemLocale(res, locale);
+
+        final int resourceId = Utils.getMainDictionaryResourceId(res);
+        final AssetFileDescriptor afd = res.openRawResourceFd(resourceId);
+        final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH)
+                ? afd.getLength()
+                : null;
+        try {
+            if (null != afd) afd.close();
+        } catch (java.io.IOException e) {
+        }
+
+        Utils.setSystemLocale(res, saveLocale);
+        return size;
+    }
+
     // TODO: Find the Right Way to find out whether the resource is a placeholder or not.
     // Suggestion : strip the locale, open the placeholder file and store its offset.
     // Upon opening the file, if it's the same offset, then it's the placeholder.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index abe6bdd0d919ddbfa12b90b9f472e809f9971d7b..2858b2fb9273c27447616cd9f8370253d4cffa7c 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -25,6 +25,7 @@ import com.android.inputmethod.compat.InputTypeCompatUtils;
 import com.android.inputmethod.compat.VibratorCompatWrapper;
 import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
 import com.android.inputmethod.deprecated.VoiceProxy;
+import com.android.inputmethod.deprecated.recorrection.Recorrection;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
@@ -717,7 +718,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
                 // 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.
-                mRecorrection.saveWordInHistory(mWord, mComposing);
+                mRecorrection.saveRecorrectionSuggestion(mWord, mComposing);
             }
             mComposing.setLength(0);
             mHasUncommittedTypedChars = false;
@@ -1254,7 +1255,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             if (!mHasUncommittedTypedChars) {
                 mHasUncommittedTypedChars = true;
                 mComposing.setLength(0);
-                mRecorrection.saveWordInHistory(mWord, mBestWord);
+                mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord);
                 mWord.reset();
                 clearSuggestions();
             }
@@ -1662,7 +1663,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators);
             ic.commitText(suggestion, 1);
         }
-        mRecorrection.saveWordInHistory(mWord, suggestion);
+        mRecorrection.saveRecorrectionSuggestion(mWord, suggestion);
         mHasUncommittedTypedChars = false;
         mCommittedLength = suggestion.length();
     }
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index cf0592920f120bd23c111f10275fafc78dd93dd2..af5e4b179d14c0c1cd436c22b6400fbf6dc6fad1 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -62,7 +62,7 @@ public class WordComposer {
         mYCoordinates = new int[N];
     }
 
-    WordComposer(WordComposer source) {
+    public WordComposer(WordComposer source) {
         init(source);
     }