diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index f37f6cc4b716815539bb63660a7c83a9629beccf..a1ffe5a93abc311dacaf58b32c0b7bc0a7e2fbdd 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -82,6 +82,7 @@
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
                 <action android:name="android.intent.action.USER_INITIALIZE" />
+                <action android:name="android.intent.action.LOCALE_CHANGED" />
             </intent-filter>
         </receiver>
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 0804cebc4d4a55cca27cf17674d8d91af9b5784b..3f436731319717c94ecab8eca4b56adad61cd04a 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -119,7 +119,15 @@ public final class KeyboardLayoutSet {
                 new SparseArray<>();
     }
 
-    public static void clearKeyboardCache() {
+    public static void onSystemLocaleChanged() {
+        clearKeyboardCache();
+    }
+
+    public static void onKeyboardThemeChanged() {
+        clearKeyboardCache();
+    }
+
+    private static void clearKeyboardCache() {
         sKeyboardCache.clear();
         sKeysCache.clear();
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 30bd1dfda996dc0b0e9037ad64ee41c7eb9ca848..389d58a309d65b932e3a99335d1c586bdf0256cc 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -103,7 +103,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
         if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) {
             mKeyboardTheme = keyboardTheme;
             mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
-            KeyboardLayoutSet.clearKeyboardCache();
+            KeyboardLayoutSet.onKeyboardThemeChanged();
             return true;
         }
         return false;
diff --git a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
index e4ee42660081ac1ebab730d096a4cd0be08cf7d9..123ab208c7e7a4333b1610d42096ec4f95745ab0 100644
--- a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
@@ -17,21 +17,16 @@
 package com.android.inputmethod.latin;
 
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
 import android.os.Process;
-import android.preference.PreferenceManager;
 import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.IntentCompatUtils;
-import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
-import com.android.inputmethod.latin.setup.SetupActivity;
 import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
 
 /**
@@ -58,6 +53,9 @@ import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
  * When a multiuser account has been created, {@link Intent#ACTION_USER_INITIALIZE} is received
  * by this receiver and it checks the whether the setup wizard's icon should be appeared or not on
  * the launcher depending on which partition this IME is installed.
+ *
+ * When the system locale has been changed, {@link Intent#ACTION_LOCALE_CHANGED} is received by
+ * this receiver and the {@link KeyboardLayoutSet}'s cache is cleared.
  */
 public final class SystemBroadcastReceiver extends BroadcastReceiver {
     private static final String TAG = SystemBroadcastReceiver.class.getSimpleName();
@@ -67,21 +65,22 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
         final String intentAction = intent.getAction();
         if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
             Log.i(TAG, "Package has been replaced: " + context.getPackageName());
-        } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
-            Log.i(TAG, "Boot has been completed");
-        } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
-            Log.i(TAG, "User initialize");
-        }
-
-        LauncherIconVisibilityManager.onReceiveGlobalIntent(intentAction, context);
-
-        if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
             // Need to restore additional subtypes because system always clears additional
             // subtypes when the package is replaced.
             RichInputMethodManager.init(context);
             final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
             final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes(context);
             richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
+            LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+        } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
+            Log.i(TAG, "Boot has been completed");
+            LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+        } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
+            Log.i(TAG, "User initialize");
+            LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+        } else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
+            Log.i(TAG, "System locale changed");
+            KeyboardLayoutSet.onSystemLocaleChanged();
         }
 
         // The process that hosts this broadcast receiver is invoked and remains alive even after
diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
index 9585736e71d13d403fd93606ea65189865a7befe..3f0b10225c21ae05b6c0d958ae85f844d0915e62 100644
--- a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
+++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
@@ -24,7 +24,6 @@ import android.content.pm.PackageManager;
 import android.preference.PreferenceManager;
 import android.util.Log;
 
-import com.android.inputmethod.compat.IntentCompatUtils;
 import com.android.inputmethod.latin.settings.Settings;
 
 /**
@@ -55,14 +54,6 @@ import com.android.inputmethod.latin.settings.Settings;
 public final class LauncherIconVisibilityManager {
     private static final String TAG = LauncherIconVisibilityManager.class.getSimpleName();
 
-    public static void onReceiveGlobalIntent(final String action, final Context context) {
-        if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(action) ||
-                Intent.ACTION_BOOT_COMPLETED.equals(action) ||
-                IntentCompatUtils.is_ACTION_USER_INITIALIZE(action)) {
-            updateSetupWizardIconVisibility(context);
-        }
-    }
-
     public static void updateSetupWizardIconVisibility(final Context context) {
         final ComponentName setupWizardActivity = new ComponentName(context, SetupActivity.class);
         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
index 545b42254f5d557c7312abc81ef859adfaad837c..9e795dbc290e9c842ff4b641c604a89b32305ed9 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
@@ -118,8 +118,16 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio
         super.testActionCustom();
     }
 
+    // Working variable to simulate system locale changing.
+    private Locale mSystemLocale = Locale.getDefault();
+
     private void doTestActionLabelInLocale(final InputMethodSubtype subtype,
             final Locale labelLocale, final Locale systemLocale) {
+        // Simulate system locale changing, see {@link SystemBroadcastReceiver}.
+        if (!systemLocale.equals(mSystemLocale)) {
+            KeyboardLayoutSet.onSystemLocaleChanged();
+            mSystemLocale = systemLocale;
+        }
         final String tag = "label=" + labelLocale + " system=" + systemLocale
                 + " " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
         final RunInLocale<Void> job = new RunInLocale<Void>() {
@@ -164,9 +172,8 @@ public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActio
                 SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
         // An action label of no language keyboard should be displayed in the system locale.
         doTestActionLabelInLocale(noLanguage, Locale.US, Locale.US);
-        // TODO: Uncomment the following test once a bug is fixed.
-        // doTestActionLabelInLocale(noLanguage, Locale.FRENCH, Locale.FRENCH);
-        // doTestActionLabelInLocale(noLanguage, Locale.ITALIAN, Locale.ITALIAN);
-        // doTestActionLabelInLocale(noLanguage, Locale.JAPANESE, Locale.JAPANESE);
+        doTestActionLabelInLocale(noLanguage, Locale.FRENCH, Locale.FRENCH);
+        doTestActionLabelInLocale(noLanguage, Locale.ITALIAN, Locale.ITALIAN);
+        doTestActionLabelInLocale(noLanguage, Locale.JAPANESE, Locale.JAPANESE);
     }
 }