Android N change language programmatically Android N change language programmatically android android

Android N change language programmatically


Ok. Finally i managed to find a solution.

First you should know that in 25 API Resources.updateConfiguration(...) is deprecated. So instead you can do something like this:

1) You need to create your own ContextWrapper that will override all configuration params in baseContext. For example this is mine ContextWrapper that changes Locale correctly. Pay attention on context.createConfigurationContext(configuration) method.

public class ContextWrapper extends android.content.ContextWrapper {    public ContextWrapper(Context base) {        super(base);    }    public static ContextWrapper wrap(Context context, Locale newLocale) {        Resources res = context.getResources();        Configuration configuration = res.getConfiguration();        if (BuildUtils.isAtLeast24Api()) {            configuration.setLocale(newLocale);            LocaleList localeList = new LocaleList(newLocale);            LocaleList.setDefault(localeList);            configuration.setLocales(localeList);            context = context.createConfigurationContext(configuration);        } else if (BuildUtils.isAtLeast17Api()) {            configuration.setLocale(newLocale);            context = context.createConfigurationContext(configuration);        } else {            configuration.locale = newLocale;            res.updateConfiguration(configuration, res.getDisplayMetrics());        }        return new ContextWrapper(context);    }}

2) Here's what you should do in your BaseActivity:

@Overrideprotected void attachBaseContext(Context newBase) {    Locale newLocale;    // .. create or get your new Locale object here.    Context context = ContextWrapper.wrap(newBase, newLocale);    super.attachBaseContext(context);}

Note:

Remember to recreate your activity if you want to change Locale in your App somewhere. You can override any configuration you want using this solution.


Inspired by various codes (i.e: our Stackoverflow team (shout out people)), I had produced a much simpler version. The ContextWrapper extension is unnecessary.

First let's say you have 2 buttons for 2 languages, EN and KH. In the onClick for the buttons save the language code into SharedPreferences, then call the activity recreate() method.

Example:

@Overridepublic void onClick(View v) {    switch(v.getId()) {        case R.id.btn_lang_en:            //save "en" to SharedPref here            break;        case R.id.btn_lang_kh:            //save "kh" to SharedPref here            break;        default:        break;    }    getActivity().recreate();}

Then create a static method that returns ContextWrapper, perhaps in a Utils class (coz that's what I did, lul).

public static ContextWrapper changeLang(Context context, String lang_code){    Locale sysLocale;    Resources rs = context.getResources();    Configuration config = rs.getConfiguration();    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {        sysLocale = config.getLocales().get(0);    } else {        sysLocale = config.locale;    }    if (!lang_code.equals("") && !sysLocale.getLanguage().equals(lang_code)) {        Locale locale = new Locale(lang_code);        Locale.setDefault(locale);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {            config.setLocale(locale);        } else {            config.locale = locale;        }        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {            context = context.createConfigurationContext(config);        } else {            context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());        }    }    return new ContextWrapper(context);}

Finally, load the language code from SharedPreferences in ALL ACTIVITY'S attachBaseContext(Context newBase) method.

@Overrideprotected void attachBaseContext(Context newBase) {    String lang_code = "en"; //load it from SharedPref    Context context = Utils.changeLang(newBase, lang_code);    super.attachBaseContext(context);}

BONUS: To save palm sweat on keyboard, I created a LangSupportBaseActivity class that extends the Activity and use the last chunk of code there. And I have all other activities extends LangSupportBaseActivity.

Example:

public class LangSupportBaseActivity extends Activity{    ...blab blab blab so on and so forth lines of neccessary code    @Override    protected void attachBaseContext(Context newBase) {        String lang_code = "en"; //load it from SharedPref        Context context = Utils.changeLang(newBase, lang_code);        super.attachBaseContext(context);    }}public class HomeActivity extends LangSupportBaseActivity{    ...blab blab blab}


Since Android 7.0+ some parts of my app didn't change their language anymore. Even with the new methods proposed above. Updating of both application and activity context helped me. Here is a Kotlin example of Activity subclass overrides:

private fun setApplicationLanguage(newLanguage: String) {    val activityRes = resources    val activityConf = activityRes.configuration    val newLocale = Locale(newLanguage)    activityConf.setLocale(newLocale)    activityRes.updateConfiguration(activityConf, activityRes.displayMetrics)    val applicationRes = applicationContext.resources    val applicationConf = applicationRes.configuration    applicationConf.setLocale(newLocale)    applicationRes.updateConfiguration(applicationConf,            applicationRes.displayMetrics)}override fun attachBaseContext(newBase: Context?) {    super.attachBaseContext(newBase)    setApplicationLanguage("fa");}

Note: updateConfiguration is deprecated but anyway, createConfigurationContext for each Activity, left some strings unchanged.