Force locale for Android flavor with resConfig

Well, after many hours, here's the solution to my problem for those ending up with the same problem.

Turns out that resConfig is not for what I though. The proper and only way I found to force the locale for a specific flavor is like this:

First, make sure all your activities extends a common activity which will be responsible to force the locale. (I had to create 2 since I have some activities extending FragmentActivity and some extending Activity. I also don't really like doing so in the Activities constructor but since I have to call applyOverrideConfiguration before any call is done on getResources, I need to call it before the activity's onStart).

public class LocaleMainActivity extends Activity {

    public LocaleMainActivity() {
        ActivityUtils.forceLocale(this);
    }
}

public class LocaleMainFragmentActivity extends FragmentActivity {

    public LocaleMainFragmentActivity() {
        ActivityUtils.forceLocale(this);
    }
}

//Method from ActivityUtils
public static void forceLocale(ContextThemeWrapper contextThemeWrapper) {
    Configuration configuration = new Configuration();
    Locale defaultLocale = new Locale(BuildConfig.LOCALE);
    configuration.locale = defaultLocale;
    contextThemeWrapper.applyOverrideConfiguration(configuration);      
}

Next, you need to define the locale in your build.gradle flavors

productFlavors {

    myFrenchFlavor {
     buildConfigField "String", "LOCALE", "\"fr\""
    }
    myEnglishFlavor {
      buildConfigField "String", "LOCALE", "\"en\""
    }
}

I tested the solution on API 19+. Works when you change language while in the app too.



Alternate solution (won't work on Android M+ see android bug report) This solution is wide spreaded on stackOverflow but I faced a wall while implementing this on Android M so keep this in mind.

In the onCreate() of your AndroidApplication you can call updateConfiguration with the locale set.

Locale myLocale = new Locale(BuildConfig.LOCALE);
Resources res = getResources();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, res.getDisplayMetrics());

You will also need to reset it if you defined onConfigurationChanged()

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);            
        Configuration config = new Configuration(newConfig);
        config.locale = new Locale(BuildConfig.LOCALE);
        getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
    }

EDIT: Be aware that this applyOverrideConfiguration currently has a side effect which is explained here Chromium webview does not seems to work with Android applyOverrideConfiguration. The Chromium team are currently working on it!

Thanks.


resConfig does not override the specified resConfigs of the defaultConfig, but just combines them instead. Thus you'll end up with all flavors containing en and fr resources.

So, to avoid that, you shouldn't specify any resConfigs in the defaultConfig and just set it in the specific flavor.

Further, the app will always include the default values, which means if you have English strings there, the fr flavor will still show up with English content on a device set to any non-French locale.