diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index c20546607a05159995c0aa025d5aecc723834965..eced45ea5323c7db5ef08c7e5a9d1faf5a38d23d 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -61,9 +61,9 @@ public class DictionaryFacilitator {
     // dictionary.
     private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140;
 
-    private DictionaryGroup mDictionaryGroup = new DictionaryGroup();
+    private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
     private boolean mIsUserDictEnabled = false;
-    private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+    private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0);
     // To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
     private final Object mLock = new Object();
     private final DistracterFilter mDistracterFilter;
@@ -193,8 +193,9 @@ public class DictionaryFacilitator {
         mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser);
     }
 
+    // TODO: remove this, replace with version returning multiple locales
     public Locale getLocale() {
-        return mDictionaryGroup.mLocale;
+        return mDictionaryGroups[0].mLocale;
     }
 
     private static ExpandableBinaryDictionary getSubDict(final String dictType,
@@ -226,6 +227,21 @@ public class DictionaryFacilitator {
                 usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */);
     }
 
+    private DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups,
+            final Locale locale) {
+        for (int i = 0; i < dictionaryGroups.length; ++i) {
+            if (locale.equals(dictionaryGroups[i].mLocale)) {
+                return dictionaryGroups[i];
+            }
+        }
+        return null;
+    }
+
+    private DictionaryGroup getDictionaryGroupForActiveLanguage() {
+        // TODO: implement this
+        return mDictionaryGroups[0];
+    }
+
     public void resetDictionariesWithDictNamePrefix(final Context context,
             final Locale newLocaleToUse,
             final boolean useContactsDict, final boolean usePersonalizedDicts,
@@ -252,7 +268,7 @@ public class DictionaryFacilitator {
             final ArrayList<String> dictsForLocale = new ArrayList<>();
             existingDictsToCleanup.put(newLocale, dictsForLocale);
             final DictionaryGroup currentDictionaryGroupForLocale =
-                    newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
+                    findDictionaryGroupWithLocale(mDictionaryGroups, newLocale);
             if (null == currentDictionaryGroupForLocale) {
                 continue;
             }
@@ -266,10 +282,11 @@ public class DictionaryFacilitator {
             }
         }
 
-        final HashMap<Locale, DictionaryGroup> newDictionaryGroups = new HashMap<>();
-        for (final Locale newLocale : newLocales) {
+        final DictionaryGroup[] newDictionaryGroups = new DictionaryGroup[newLocales.length];
+        for (int i = 0; i < newLocales.length; ++i) {
+            final Locale newLocale = newLocales[i];
             final DictionaryGroup dictionaryGroupForLocale =
-                    newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
+                    findDictionaryGroupWithLocale(mDictionaryGroups, newLocale);
             final ArrayList<String> dictsToCleanupForLocale = existingDictsToCleanup.get(newLocale);
             final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
 
@@ -297,30 +314,29 @@ public class DictionaryFacilitator {
                 }
                 subDicts.put(subDictType, subDict);
             }
-            newDictionaryGroups.put(newLocale, new DictionaryGroup(newLocale, mainDict, subDicts));
+            newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, subDicts);
         }
 
         // Replace Dictionaries.
-        // TODO: use multiple locales.
-        final DictionaryGroup newDictionaryGroup = newDictionaryGroups.get(newLocaleToUse);
-        final DictionaryGroup oldDictionaryGroup;
+        final DictionaryGroup[] oldDictionaryGroups;
         synchronized (mLock) {
-            oldDictionaryGroup = mDictionaryGroup;
-            mDictionaryGroup = newDictionaryGroup;
+            oldDictionaryGroups = mDictionaryGroups;
+            mDictionaryGroups = newDictionaryGroups;
             mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context);
-            if (null == newDictionaryGroup.getDict(Dictionary.TYPE_MAIN)) {
+            if (hasAtLeastOneUninitializedMainDictionary()) {
                 asyncReloadUninitializedMainDictionaries(context, newLocales, listener);
             }
         }
         if (listener != null) {
-            listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
+            listener.onUpdateMainDictionaryAvailability(hasAtLeastOneInitializedMainDictionary());
         }
 
         // Clean up old dictionaries.
         for (final Locale localeToCleanUp : existingDictsToCleanup.keySet()) {
             final ArrayList<String> dictTypesToCleanUp =
                     existingDictsToCleanup.get(localeToCleanUp);
-            final DictionaryGroup dictionarySetToCleanup = oldDictionaryGroup;
+            final DictionaryGroup dictionarySetToCleanup =
+                    findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp);
             for (final String dictType : dictTypesToCleanUp) {
                 dictionarySetToCleanup.closeDict(dictType);
             }
@@ -330,12 +346,18 @@ public class DictionaryFacilitator {
     private void asyncReloadUninitializedMainDictionaries(final Context context,
             final Locale[] locales, final DictionaryInitializationListener listener) {
         final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
-        mLatchForWaitingLoadingMainDictionary = latchForWaitingLoadingMainDictionary;
+        mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary;
         ExecutorUtils.getExecutor("InitializeBinaryDictionary").execute(new Runnable() {
             @Override
             public void run() {
                 for (final Locale locale : locales) {
-                    final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+                    final DictionaryGroup dictionaryGroup =
+                            findDictionaryGroupWithLocale(mDictionaryGroups, locale);
+                    if (null == dictionaryGroup) {
+                        // This should never happen, but better safe than crashy
+                        Log.w(TAG, "Expected a dictionary group for " + locale + " but none found");
+                        continue;
+                    }
                     final Dictionary mainDict =
                             DictionaryFactory.createMainDictionaryFromManager(context, locale);
                     synchronized (mLock) {
@@ -348,7 +370,8 @@ public class DictionaryFacilitator {
                     }
                 }
                 if (listener != null) {
-                    listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
+                    listener.onUpdateMainDictionaryAvailability(
+                            hasAtLeastOneInitializedMainDictionary());
                 }
                 latchForWaitingLoadingMainDictionary.countDown();
             }
@@ -381,17 +404,20 @@ public class DictionaryFacilitator {
                 subDicts.put(dictType, dict);
             }
         }
-        mDictionaryGroup = new DictionaryGroup(locale, mainDictionary, subDicts);
+        mDictionaryGroups = new DictionaryGroup[] {
+                new DictionaryGroup(locale, mainDictionary, subDicts) };
     }
 
     public void closeDictionaries() {
-        final DictionaryGroup dictionaryGroup;
+        final DictionaryGroup[] dictionaryGroups;
         synchronized (mLock) {
-            dictionaryGroup = mDictionaryGroup;
-            mDictionaryGroup = new DictionaryGroup();
+            dictionaryGroups = mDictionaryGroups;
+            mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
         }
-        for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
-            dictionaryGroup.closeDict(dictType);
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+                dictionaryGroup.closeDict(dictType);
+            }
         }
         mDistracterFilter.close();
         if (mPersonalizationHelper != null) {
@@ -401,40 +427,71 @@ public class DictionaryFacilitator {
 
     @UsedForTesting
     public ExpandableBinaryDictionary getSubDictForTesting(final String dictName) {
-        return mDictionaryGroup.getSubDict(dictName);
+        return mDictionaryGroups[0].getSubDict(dictName);
     }
 
-    // The main dictionary could have been loaded asynchronously.  Don't cache the return value
-    // of this method.
-    public boolean hasInitializedMainDictionary() {
-        final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN);
-        return mainDict != null && mainDict.isInitialized();
+    // The main dictionaries are loaded asynchronously.  Don't cache the return value
+    // of these methods.
+    public boolean hasAtLeastOneInitializedMainDictionary() {
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN);
+            if (mainDict != null && mainDict.isInitialized()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean hasAtLeastOneUninitializedMainDictionary() {
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN);
+            if (mainDict == null || !mainDict.isInitialized()) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public boolean hasPersonalizationDictionary() {
-        return mDictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION);
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public void flushPersonalizationDictionary() {
-        final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
-                mDictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
+        final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion =
+                new HashSet<>();
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
+                    dictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
+            personalizationDictsUsedForSuggestion.add(personalizationDictUsedForSuggestion);
+        }
         mPersonalizationHelper.flushPersonalizationDictionariesToUpdate(
-                personalizationDictUsedForSuggestion);
+                personalizationDictsUsedForSuggestion);
         mDistracterFilter.close();
     }
 
-    public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit)
+    public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
             throws InterruptedException {
-        mLatchForWaitingLoadingMainDictionary.await(timeout, unit);
+        mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
     }
 
     @UsedForTesting
     public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit)
             throws InterruptedException {
-        waitForLoadingMainDictionary(timeout, unit);
-        final Map<String, ExpandableBinaryDictionary> dictMap = mDictionaryGroup.mSubDictMap;
-        for (final ExpandableBinaryDictionary dict : dictMap.values()) {
-            dict.waitAllTasksForTests();
+        waitForLoadingMainDictionaries(timeout, unit);
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            for (final ExpandableBinaryDictionary dict : dictionaryGroup.mSubDictMap.values()) {
+                dict.waitAllTasksForTests();
+            }
         }
     }
 
@@ -453,7 +510,7 @@ public class DictionaryFacilitator {
     public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
             final PrevWordsInfo prevWordsInfo, final int timeStampInSeconds,
             final boolean blockPotentiallyOffensive) {
-        final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+        final DictionaryGroup dictionaryGroup = getDictionaryGroupForActiveLanguage();
         final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
         PrevWordsInfo prevWordsInfoForCurrentWord = prevWordsInfo;
         for (int i = 0; i < words.length; i++) {
@@ -520,7 +577,8 @@ public class DictionaryFacilitator {
     }
 
     private void removeWord(final String dictName, final String word) {
-        final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
+        final ExpandableBinaryDictionary dictionary =
+                getDictionaryGroupForActiveLanguage().getSubDict(dictName);
         if (dictionary != null) {
             dictionary.removeUnigramEntryDynamically(word);
         }
@@ -536,20 +594,22 @@ public class DictionaryFacilitator {
     public SuggestionResults getSuggestionResults(final WordComposer composer,
             final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
             final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
-        final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
         final SuggestionResults suggestionResults =
                 new SuggestionResults(SuggestedWords.MAX_SUGGESTIONS);
         final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
-        for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
-            final Dictionary dictionary = dictionaryGroup.getDict(dictType);
-            if (null == dictionary) continue;
-            final ArrayList<SuggestedWordInfo> dictionarySuggestions =
-                    dictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
-                            settingsValuesForSuggestion, sessionId, languageWeight);
-            if (null == dictionarySuggestions) continue;
-            suggestionResults.addAll(dictionarySuggestions);
-            if (null != suggestionResults.mRawSuggestions) {
-                suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+                final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+                if (null == dictionary) continue;
+                final ArrayList<SuggestedWordInfo> dictionarySuggestions =
+                        dictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
+                                settingsValuesForSuggestion, sessionId, languageWeight);
+                if (null == dictionarySuggestions) continue;
+                suggestionResults.addAll(dictionarySuggestions);
+                if (null != suggestionResults.mRawSuggestions) {
+                    suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
+                }
             }
         }
         return suggestionResults;
@@ -559,20 +619,22 @@ public class DictionaryFacilitator {
         if (TextUtils.isEmpty(word)) {
             return false;
         }
-        final DictionaryGroup dictionaryGroup = mDictionaryGroup;
-        if (dictionaryGroup.mLocale == null) {
-            return false;
-        }
-        final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
-        for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
-            final Dictionary dictionary = dictionaryGroup.getDict(dictType);
-            // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
-            // would be immutable once it's finished initializing, but concretely a null test is
-            // probably good enough for the time being.
-            if (null == dictionary) continue;
-            if (dictionary.isValidWord(word)
-                    || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
-                return true;
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            if (dictionaryGroup.mLocale == null) {
+                continue;
+            }
+            final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
+            for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+                final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+                // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
+                // would be immutable once it's finished initializing, but concretely a null test is
+                // probably good enough for the time being.
+                if (null == dictionary) continue;
+                if (dictionary.isValidWord(word)
+                        || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
+                    return true;
+                }
             }
         }
         return false;
@@ -584,18 +646,20 @@ public class DictionaryFacilitator {
             return Dictionary.NOT_A_PROBABILITY;
         }
         int maxFreq = Dictionary.NOT_A_PROBABILITY;
-        final DictionaryGroup dictionaryGroup = mDictionaryGroup;
-        for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
-            final Dictionary dictionary = dictionaryGroup.getDict(dictType);
-            if (dictionary == null) continue;
-            final int tempFreq;
-            if (isGettingMaxFrequencyOfExactMatches) {
-                tempFreq = dictionary.getMaxFrequencyOfExactMatches(word);
-            } else {
-                tempFreq = dictionary.getFrequency(word);
-            }
-            if (tempFreq >= maxFreq) {
-                maxFreq = tempFreq;
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+                final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+                if (dictionary == null) continue;
+                final int tempFreq;
+                if (isGettingMaxFrequencyOfExactMatches) {
+                    tempFreq = dictionary.getMaxFrequencyOfExactMatches(word);
+                } else {
+                    tempFreq = dictionary.getFrequency(word);
+                }
+                if (tempFreq >= maxFreq) {
+                    maxFreq = tempFreq;
+                }
             }
         }
         return maxFreq;
@@ -610,9 +674,12 @@ public class DictionaryFacilitator {
     }
 
     private void clearSubDictionary(final String dictName) {
-        final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
-        if (dictionary != null) {
-            dictionary.clear();
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictName);
+            if (dictionary != null) {
+                dictionary.clear();
+            }
         }
     }
 
@@ -641,8 +708,10 @@ public class DictionaryFacilitator {
 
     public void addPhraseToContextualDictionary(final String[] phrase, final int probability,
             final int bigramProbabilityForWords, final int bigramProbabilityForPhrases) {
+        // TODO: we're inserting the phrase into the dictionary for the active language. Rethink
+        // this a bit from a theoretical point of view.
         final ExpandableBinaryDictionary contextualDict =
-                mDictionaryGroup.getSubDict(Dictionary.TYPE_CONTEXTUAL);
+                getDictionaryGroupForActiveLanguage().getSubDict(Dictionary.TYPE_CONTEXTUAL);
         if (contextualDict == null) {
             return;
         }
@@ -675,22 +744,27 @@ public class DictionaryFacilitator {
     }
 
     public void dumpDictionaryForDebug(final String dictName) {
-        final ExpandableBinaryDictionary dictToDump = mDictionaryGroup.getSubDict(dictName);
-        if (dictToDump == null) {
-            Log.e(TAG, "Cannot dump " + dictName + ". "
-                    + "The dictionary is not being used for suggestion or cannot be dumped.");
-            return;
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            final ExpandableBinaryDictionary dictToDump = dictionaryGroup.getSubDict(dictName);
+            if (dictToDump == null) {
+                Log.e(TAG, "Cannot dump " + dictName + ". "
+                        + "The dictionary is not being used for suggestion or cannot be dumped.");
+                return;
+            }
+            dictToDump.dumpAllWordsForDebug();
         }
-        dictToDump.dumpAllWordsForDebug();
     }
 
     public ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts() {
         final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>();
-        final DictionaryGroup dictionaryGroup = mDictionaryGroup;
-        for (final String dictType : SUB_DICT_TYPES) {
-            final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType);
-            if (dictionary == null) continue;
-            statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
+        final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+        for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+            for (final String dictType : SUB_DICT_TYPES) {
+                final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType);
+                if (dictionary == null) continue;
+                statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
+            }
         }
         return statsOfEnabledSubDicts;
     }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
index fa0265d8694a2e47d9a713a8b48638b6460f2f80..ff4a6bde1ed79c945a731fd490fa67e888724bd6 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
@@ -84,7 +84,7 @@ public class DictionaryFacilitatorLruCache {
     private void waitForLoadingMainDictionary(final DictionaryFacilitator dictionaryFacilitator) {
         for (int i = 0; i < MAX_RETRY_COUNT_FOR_WAITING_FOR_LOADING_DICT; i++) {
             try {
-                dictionaryFacilitator.waitForLoadingMainDictionary(
+                dictionaryFacilitator.waitForLoadingMainDictionaries(
                         WAIT_FOR_LOADING_MAIN_DICT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
                 return;
             } catch (final InterruptedException e) {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index a1dd67f273400493176a9932f87cc7e95b5bfff1..671ba671484062feec24062d99f03b1fddef66f3 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -156,23 +156,25 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     }
 
     private void asyncExecuteTaskWithWriteLock(final Runnable task) {
-        asyncExecuteTaskWithLock(mLock.writeLock(), task);
+        asyncExecuteTaskWithLock(mLock.writeLock(), mDictName /* executorName */, task);
     }
 
-    private void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) {
-        asyncPreCheckAndExecuteTaskWithLock(lock, null /* preCheckTask */, task);
+    private void asyncExecuteTaskWithLock(final Lock lock, final String executorName,
+            final Runnable task) {
+        asyncPreCheckAndExecuteTaskWithLock(lock, null /* preCheckTask */, executorName, task);
     }
 
     private void asyncPreCheckAndExecuteTaskWithWriteLock(
             final Callable<Boolean> preCheckTask, final Runnable task) {
-        asyncPreCheckAndExecuteTaskWithLock(mLock.writeLock(), preCheckTask, task);
+        asyncPreCheckAndExecuteTaskWithLock(mLock.writeLock(), preCheckTask,
+                mDictName /* executorName */, task);
 
     }
 
     // Execute task with lock when the result of preCheckTask is true or preCheckTask is null.
     private void asyncPreCheckAndExecuteTaskWithLock(final Lock lock,
-            final Callable<Boolean> preCheckTask, final Runnable task) {
-        ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
+            final Callable<Boolean> preCheckTask, final String executorName, final Runnable task) {
+        ExecutorUtils.getExecutor(executorName).execute(new Runnable() {
             @Override
             public void run() {
                 if (preCheckTask != null) {
@@ -676,10 +678,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
 
     public void dumpAllWordsForDebug() {
         reloadDictionaryIfRequired();
-        asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {
+        asyncExecuteTaskWithLock(mLock.readLock(), "dumpAllWordsForDebug", new Runnable() {
             @Override
             public void run() {
-                Log.d(TAG, "Dump dictionary: " + mDictName);
+                Log.d(TAG, "Dump dictionary: " + mDictName + " for " + mLocale);
                 try {
                     final DictionaryHeader header = mBinaryDictionary.getHeader();
                     Log.d(TAG, "Format version: " + mBinaryDictionary.getFormatVersion());
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index aac6276bc35cd6b2c57f5b5b69cf005a1e4353d1..66396d08c97f15f3cace3faf478875ad2984d261 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -998,7 +998,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         mHandler.cancelUpdateSuggestionStrip();
 
         mainKeyboardView.setMainDictionaryAvailability(
-                mDictionaryFacilitator.hasInitializedMainDictionary());
+                mDictionaryFacilitator.hasAtLeastOneInitializedMainDictionary());
         mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
                 currentSettingsValues.mKeyPreviewPopupDismissDelay);
         mainKeyboardView.setSlidingKeyInputPreviewEnabled(
diff --git a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
index 43cebdfa470564f3ab4c943594fd776ae9911906..396d062f821f5a52f815cadbef9d7196ab311b18 100644
--- a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
@@ -88,17 +88,17 @@ public class PersonalizationHelperForDictionaryFacilitator {
 
     /**
      * Flush personalization dictionaries to dictionary files. Close dictionaries after writing
-     * files except the dictionary that is used for generating suggestions.
+     * files except the dictionaries that is used for generating suggestions.
      *
-     * @param personalizationDictUsedForSuggestion the personalization dictionary used for
+     * @param personalizationDictsUsedForSuggestion the personalization dictionaries used for
      * generating suggestions that won't be closed.
      */
     public void flushPersonalizationDictionariesToUpdate(
-            final ExpandableBinaryDictionary personalizationDictUsedForSuggestion) {
+            final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion) {
         for (final ExpandableBinaryDictionary personalizationDict :
                 mPersonalizationDictsToUpdate.values()) {
             personalizationDict.asyncFlushBinaryDictionary();
-            if (personalizationDict != personalizationDictUsedForSuggestion) {
+            if (!personalizationDictsUsedForSuggestion.contains(personalizationDict)) {
                 // Close if the dictionary is not being used for suggestion.
                 personalizationDict.close();
             }
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9e4aa40a22cd77722a06e23e5396933757c26f4f..9bf017578bb92f74f3bac5b9f2df9edfbf1c23f1 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -157,7 +157,7 @@ public final class Suggest {
         if (!isCorrectionEnabled || !allowsToBeAutoCorrected || resultsArePredictions
                 || suggestionResults.isEmpty() || wordComposer.hasDigits()
                 || wordComposer.isMostlyCaps() || wordComposer.isResumed()
-                || !mDictionaryFacilitator.hasInitializedMainDictionary()
+                || !mDictionaryFacilitator.hasAtLeastOneInitializedMainDictionary()
                 || suggestionResults.first().isKindOf(SuggestedWordInfo.KIND_SHORTCUT)) {
             // If we don't have a main dictionary, we never want to auto-correct. The reason for
             // this is, the user may have a contact whose name happens to match a valid word in
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 49b34d391b02c7ec09ec8dbfcf58570ca0facb87..3523916115a8af431272a03f68c9c7fb3e631ba3 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -185,7 +185,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
         try {
             final DictionaryFacilitator dictionaryFacilitator =
                     mDictionaryFacilitatorCache.get(locale);
-            return dictionaryFacilitator.hasInitializedMainDictionary();
+            return dictionaryFacilitator.hasAtLeastOneInitializedMainDictionary();
         } finally {
             mSemaphore.release();
         }