Search code examples
androidandroid-locale

How to detect Android configuration change of Locale during per App Language change


I am investigating per app language in my current android application and have add this to my android manifest file

android:configChanges="locale|layoutDirection"

My activities onConfigurationChanged function is called and I can see how to detect text direction changes using the below code:

@RequiresApi(Build.VERSION_CODES.N)
override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)

     if (newConfig.layoutDirection == Configuration.SCREENLAYOUT_LAYOUTDIR_LTR) {
        finishAffinity()
        recreate()
    }
}

How do you detect the locale has changed?

Is by !newConfig.locales.isEmpty?


Solution

  • As mentioned here

    ACTION_LOCALE_CHANGED :

    Broadcast Action: The receiver's effective locale has changed. This happens when the device locale, the receiving app's locale (set via LocaleManager.setApplicationLocales(LocaleList)) or language tags of Regional preferences changed. Can be received by manifest-declared receivers.

    • EXTRA_PACKAGE_NAME is the name of the package for which locale changed.

    • EXTRA_LOCALE_LIST contains locales that are currently set for specified app


    You may use BroadcastReceiver with intent filter Intent.ACTION_LOCALE_CHANGED. Register that receiver and when locale gets change you will get it in method onReceive with intent object then match with intent.action == Intent.ACTION_LOCALE_CHANGED and do further process.

    You may consider the following example to achieve it :

    public class LocaleReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
    
            if (intent.getAction() == Intent.ACTION_LOCALE_CHANGED){
                Log.v("LocaleRecevier", "received ACTION_LOCALE_CHANGED");
    
                Locale newLocale = context.getResources().getConfiguration().locale();
    
                Log.v("LocaleRecevier", newLocale);
    
            }
    
        }
    }
    

    Register your Brodcast receiver in Manifest file

    <receiver
        android:name=".LocaleReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.LOCALE_CHANGED" />
        </intent-filter>
    </receiver>
    

    Update 1

    It is not possible with Android APIs to directly differentiate whether locale is changed from device settings or from within your app or some other app. Standard APIs provided in Android make it possible for a locale change to be detected.

    However, there are a few ways to get a little insight into this:

    Monitor Locale Internal Change

    • The application should have a variable that stores the previously set locale.
    • Update this value whenever the locale in your app is changed programmatically.
    • When the user changes its locale throughout the system (detected by comparison with the stored variable with Locale.getDefault());. If they do match, you have a pretty strong indication that the change originated from the side of your app.

    example :

    private Locale previousLocale;
    
    public void setAppLocale(Locale newLocale) {
      previousLocale = Locale.getDefault();
      Locale.setDefault(newLocale);
      // Update UI and resources based on newLocale
    }
    
    public boolean isLocaleChangeFromApp() {
      return Locale.getDefault().equals(previousLocale);
    }
    
    // ...
    
    // When locale changes (e.g., in an activity's `onCreate`):
    Locale currentLocale = Locale.getDefault();
    if (currentLocale.equals(previousLocale)) {
      // Locale change likely from app
    } else {
      // Locale change likely from device settings
      previousLocale = currentLocale;
    }
    

    This, of course, is not foolproof, since other applications may edit the locale, but it is a crude indication and helps set the context.