How to change Android O / Oreo / api 26 app language
Asked Answered
C

9

27

I want to change the language of the app and this works fine until API 26.

For api > 25 I put Locale.setDefault(Locale.Category.DISPLAY, mynewlanglocale); before setContentView(R.layout.activity_main); but nothing changes.

The docs don't explain too much about this.

Come answered 7/11, 2017 at 18:45 Comment(6)
You mean you want to use Kotlin?Trioecious
Using Java and Android Studio 2.3.3Come
You change the API level in your build.gradle project fileTrioecious
my Min Sdk Version is API19 and Target Sdk Version is API23Come
youre not making ANY sense here bro. you want to code for oreo right??? then change your target to 26.Trioecious
@DroiDev he's talking about the language of text on the phone, and the approach he's taking no longer working in 26.Merrifield
F
36

I had the same problem: since Android 8.0+ some parts of my app did't change their language anymore. Updating of both application and activity context helps me. Here is an example of MainActivity function:

private void setApplicationLanguage(String newLanguage) {
    Resources activityRes = getResources();
    Configuration activityConf = activityRes.getConfiguration();
    Locale newLocale = new Locale(newLanguage);
    activityConf.setLocale(newLocale);
    activityRes.updateConfiguration(activityConf, activityRes.getDisplayMetrics());

    Resources applicationRes = getApplicationContext().getResources();
    Configuration applicationConf = applicationRes.getConfiguration();
    applicationConf.setLocale(newLocale);
    applicationRes.updateConfiguration(applicationConf, 
    applicationRes.getDisplayMetrics());
}
Firer answered 26/7, 2018 at 9:42 Comment(5)
Super simple, worked for me too. I tested on 7.1 and 8.0.Playbill
Thanks! Woks on 10 and 7.0Cobham
tnx. this works for me. but is this the better solution?Alumina
If this does not work for you and you are using appcompat 1.1.0 check this #55266334Sodomite
this worked for me, but ONLY IF I invoke this method inside onCreate and onResumeMaurice
T
20

Yes in android Oreo localization is not working fine with updateconfiguration. But it is deprecated in android N itself. Instead of updateconfiguration use createconfiguration in each attachcontext. it is working fine for me. Try this...

In you activity add this..

@Override
protected void attachBaseContext(Context newBase) {
    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
        super.attachBaseContext(MyContextWrapper.wrap(newBase, "ta"));
    }
    else {
        super.attachBaseContext(newBase);
    }
}

In MyContextWrapper.java

 public static ContextWrapper wrap(Context context, String language) {
    Resources res = context.getResources();
    Configuration configuration = res.getConfiguration();
    Locale newLocale = new Locale(language);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        configuration.setLocale(newLocale);
        LocaleList localeList = new LocaleList(newLocale);
        LocaleList.setDefault(localeList);
        configuration.setLocales(localeList);
        context = context.createConfigurationContext(configuration);

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLocale(newLocale);
        context = context.createConfigurationContext(configuration);

    } else {
        configuration.locale = newLocale;
        res.updateConfiguration(configuration, res.getDisplayMetrics());
    }

    return new ContextWrapper(context);
}
Thorax answered 8/1, 2018 at 6:14 Comment(5)
Thanks for the answer. Why are you checking like this: if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {} What about lower version? How we change them?Carthy
I have added code for lower version too in else part. And in lower version updateconfiguration method is enough for the language change.Thorax
1. I need to add this on all my activities or just the MainActivity of my App? and 2. Inside of attachBaseContext, how can I retrieve the language from SharedPreferences? I tried but, the App crashes when I open it.Gale
Can this be done on Application class? if yes, it would help to override attachBaseContext in all activities!! @RajalakshmiArumugamElectrodialysis
Not working for me on Oreo device s8. Can anyone help me?Borman
S
10

updateConfiguration is deprecated and you should use createConfigurationContext. I solved it this way:

    @Override
    protected void attachBaseContext(Context newBase) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Configuration config = newBase.getResources().getConfiguration();
            //Update your config with the Locale i. e. saved in SharedPreferences
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newBase);
            String language = prefs.getString(SP_KEY_LANGUAGE, "en_US");
            Locale.setDefault(locale);
            config.setLocale(new Locale(language));
            newBase = newBase.createConfigurationContext(config);
        }
        super.attachBaseContext(newBase);
    }
Saki answered 5/12, 2017 at 16:30 Comment(0)
K
4

Updated For All android versions till Oreo

Create a class like this

public class LocaleUtils {

@Retention(RetentionPolicy.SOURCE)
@StringDef({ENGLISH, FRENCH, SPANISH})
public @interface LocaleDef {
    String[] SUPPORTED_LOCALES = {ENGLISH, FRENCH, SPANISH};
}

public static final String ENGLISH = "en";
public static final String FRENCH = "fr";
public static final String SPANISH = "es";


public static void initialize(Context context) {
    setLocale(context, ENGLISH);
}

public static void initialize(Context context, @LocaleDef String defaultLanguage) {
    setLocale(context, defaultLanguage);
}


public static boolean setLocale(Context context, @LocaleDef String language) {
    return updateResources(context, language);
}

private static boolean updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    context.createConfigurationContext(configuration);
    configuration.locale = locale;
    resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    return true;
}

}

Now when you select the language from your app, Save the language code in Shared Preference like below

private static SharedPreferences getDefaultSharedPreference(Context context) {
    if (PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext()) != null)
        return PreferenceManager.getDefaultSharedPreferences(Application.getInstance().getApplicationContext());
    else
        return null;
}

 public static void setSelectedLanguageId(String id){
    final SharedPreferences prefs = getDefaultSharedPreference(Application.getInstance().getApplicationContext());
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString("app_language_id", id);
    editor.apply();
}

public static String getSelectedLanguageId(){
    return getDefaultSharedPreference(Application.getInstance().getApplicationContext())
            .getString("app_language_id", "en");
}

These three functions should be written inside a Utiltiy class(your preference). Then when you select the app language from the app, call the setSelectedLanguageId() function and pass the language id as parameter.

This way you have saved the selected language in your app. Now in your application class write a function like this

public void initAppLanguage(Context context){
    LocaleUtils.initialize(context, PreferenceUtil.getSelectedLanguageId() );
}

Here the PreferenceUtil is my Utiltiy class. You should replace it with your utility class function.

You should also create a variable in your application class

private static Application applicationInstance;

and in your Application class's onCreate method, initialise applicationInstance to be the applications context like this

applicationInstance = this; 

Now write a getter function in your application class

public static synchronized Application getInstance() {
    return applicationInstance;
}

And now when you start your first activity, call this method in your activity's onCreate

Application.getInstance().initAppLanguage(this);

Remember that we are passing the activity's context to the initAppLanguage() function, not the application context. Passing the Application context won't make it work in Oreo(atleast for me).

So when you select the language try to restart your application completely. You can acheive this by

Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());

startActivity(i);

Hope this helps you!

Kisor answered 9/3, 2018 at 12:25 Comment(1)
great, it worked for me. Below line saved me- Remember that we are passing the activity's context to the initAppLanguage() function, not the application context. Passing the Application context won't make it work in Oreo(atleast for me). Thanks a lot.Amphibious
U
3

It is possible, however i would not recommend to set the language programatically

Android is designed so the System UI and your App have the same language, if you change it programmatically you would be fighting the system

Instead what you can do is enable multilanguage support by adding different strings.xml languages, this will change the language automatically

I reccommend reading through this Google Developers article:

Supporting Different Languages and Cultures

If you really need to change it programatically you can do the following

Locale locale = new Locale("en");
Locale.setDefault(locale);

Configuration config = context.getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);
context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());

On SDK >= 21, you need to call 'Resources.updateConfiguration()', otherwise resources will not be updated.

Hope it helps.

Unger answered 7/11, 2017 at 19:9 Comment(0)
C
1

Here is complete solution worked for kitkat, Lollipop, Marshmallow, Nougat and Oreo too. Just follow all below step.

First create a java class like below

import android.content.Context;
import android.content.res.Configuration;
import java.util.Locale;
public class LocaleUtils {
public static void updateConfig(Context mContext, String sLocale) {
    Locale locale = new Locale(sLocale);
    Locale.setDefault(locale);
    Configuration config = mContext.getResources().getConfiguration();
    config.locale = locale;
    mContext.getResources().updateConfiguration(config,
            mContext.getResources().getDisplayMetrics());
  }
}

Now add this snippet on Button click where you want to change locale

String lang="hi";//pass your language here
SharedPreferences preferences =  PreferenceManager.getDefaultSharedPreferences(mContext);
                        SharedPreferences.Editor editor = preferences.edit();
                        editor.clear();
                        editor.putString("lang", lang");
                        editor.putBoolean("langSelected", true);
                        editor.apply();
                        LocaleUtils.updateConfig(mContext,lang);
                        Intent intent = mContext.getIntent();
                        mContext.overridePendingTransition(0, 0);
                        mContext.finish();
                        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        mContext.overridePendingTransition(0, 0);
                        mContext.startActivity(intent);

Finally paste the below code in Splash Activity or in Launching Activity.

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
    String lang = preferences.getString("lang", "");
    boolean langSelected = preferences.getBoolean("langSelected", false);
    SharedPreferences.Editor editor = preferences.edit();
    if (langSelected) {
        editor.clear();
        editor.putString("lang", lang);
        editor.putBoolean("langSelected", true);
        editor.apply();
        LocaleUtils.updateConfig(this,lang);
    } else {
        LocaleUtils.updateConfig(this, Locale.getDefault().getLanguage());
        editor.clear();
        editor.putString("lang", Locale.getDefault().getLanguage());
        editor.putBoolean("langSelected", false);
        editor.apply();
    }
Costive answered 3/1, 2018 at 6:49 Comment(0)
M
0

You need to use getApplicationContext() instead of getContext()

Millian answered 5/12, 2017 at 10:6 Comment(2)
While this may answer the question, it is better to explain the essential parts of the answer and possibly what was the problem with OPs code.Anchoveta
I am sorry , i do not know whyMillian
E
0

After use all solution in all sources finally i found my issue. That makes me angry for 2 days.

Everyone knows that in Android Oreo (API 26) we must use createConfigurationContext, But My problem is using Country name with local.

Replace

en_US with en

ar_AE with ar

fa_IR with fa

And my problem solved.

Hope to help someone

Eugenie answered 29/1, 2019 at 9:56 Comment(0)
J
0

for android API 26+:

LocaleListCompat appLocale = LocaleListCompat.forLanguageTags(lang);
AppCompatDelegate.setApplicationLocales(appLocale);

And you may don't need to update language in all activity if you change language like this.

Jussive answered 10/3, 2024 at 4:50 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.