Change app language programmatically in Android
Asked Answered
C

36

575

Is it possible to change the language of an app programmatically while still using Android resources?

If not, is it possible to request a resource in an specific language?

I would like to let the user change the language of the app from the app.

Cribriform answered 24/5, 2010 at 20:17 Comment(9)
You can use the following library, which provides the language list, the preference for your settings screen, and overrides the language in your application: github.com/delight-im/Android-LanguagesHanks
@MarcoW. Do you know if Android-Languages works with Android 5.0 Lollipop?Verify
@Verify Yes, it runs on Android 5.0 without any problems.Hanks
I allready answered this question in a other thread, check here: https://mcmap.net/q/65853/-change-app-language-in-android-5-0-doesn-39-t-workInterclavicle
You can use the following library: github.com/zeugma-solutions/locale-helper-androidMontanez
@Montanez that library really is the cleanest solution around for thisHeartstricken
@Cribriform If we have change the app language then if we have some searching option within app, and if we search in that then, how app will show data, should we develop some different database for each language or some android code setting is there so that app could show data according to search ?Buskined
Follow this link. developine.com/…Westerfield
Per app language feature was just added to API 33 (currently on Developer preview). See my answer https://mcmap.net/q/64530/-change-app-language-programmatically-in-androidDissogeny
V
462

It's possible. You can set the locale. However, I would not recommend that. We've tried it at early stages, it's basically fighting the system.

We have the same requirement for changing the language but decided to settle to the fact that UI should be same as phone UI. It was working via setting locale but was too buggy. And you have to set it every time you enter activity (each activity) from my experience. here is a code if you still need this (again, I don't recommend that)

Resources res = context.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.setLocale(new Locale(language_code.toLowerCase())); // API 17+ only.
// Use conf.locale = new Locale(...) if targeting lower versions
res.updateConfiguration(conf, dm);

If you have language specific content - you can change that base on the setting.


update on 26th of march 2020

    public static void setLocale(Activity activity, String languageCode) {
        Locale locale = new Locale(languageCode);
        Locale.setDefault(locale);
        Resources resources = activity.getResources();
        Configuration config = resources.getConfiguration();
        config.setLocale(locale);
        resources.updateConfiguration(config, resources.getDisplayMetrics());
    }
  • NOTES: Language code cannot got '-' & must be 2 small case letter only
Voroshilov answered 24/5, 2010 at 20:36 Comment(32)
it reverts back after some time.Harmonicon
This needs to be called by all actvities in onCreate method? Or if we give the application Context it is enought to be called only once, and not in all the activities?Lousy
i have tried it @Lousy . but getting the language revert back after some activity and that is also not fixed.Its working very fine in the emulator,but bot in the device. So let me try with calling the in all the activities.Meritorious
Can't believe that Android makes this so hard. I do not really see why there should be a STRICT association between the phone's locale and the application's. I always have my phone using English language although I'm not a native English speaker. The reason is that the translated semi-technical words just gets too weird in my own language so English is just so much easier. It also makes it easier for me to follow advice from the Net. But that does not mean that I want EVERY app on my phone to use English (although perfectly ok that is default). I want to be able to choose !!!Slantwise
"And you have to set it every time you enter activity (each activity)" That's why you create a subclass of Activity and build your app's activities off of that subclass. Which, admittedly, can be tricky if you're using a lot of Android's presupplied subclasses of Activity, but it's not as much work as you make it seem.Shaylynn
@nolan6000 It's not like Android is the only system where that's the case. Most locale-aware operating systems function similarly, and applications with internal locale/language selection have to be specifically designed to work that way (though I'm sure some UI toolkits do have libraries for that sort of thing, but those had to be programmed as well).Shaylynn
Oh, looks like API level 17 introduced Context.createConfigurationContext(), which can be used to wrap the default context with locale-specific configuration and then call getResources on that without having to update the configuration on the resources objects themselves.Shaylynn
I use a similar method. but instead of calling the updateConfiguration method, I just finish and restart my app. It worksNathannathanael
Wasn't Google that cool company that wrote cool code? I can't believe neither 5 lines of code are needed to change the app's language.Feast
What is language_code equal to? How do you check the current language_code in the app?Suboxide
You need to put this in onCreate() of every activity. Otherwise it may get overridden by the system - for instance when you turn your device to landscape and your activity gets recreated with new (system provided) configuration.Dorena
I like this solution but I have one problem with it. If I change the locale to a RTL locale like "ar" then although the language resource qualifier (-ar) is working (e.g. arabic strings are used in my app), the layout direction res qualifier (-ldrtl) is not working. Android fetches resources still from RESFOLDER and not from RESFOLDER-ldrtl. :( Any solution for that?Dorena
In case you set a RTL locale like "ar" and want your -ldrtl resource folders to work as well then also call conf.setLayoutDirection(locale);Dorena
@ZsoltSafrany - Rather than adding a call to conf.setLayoutDirection(locale), you can replace conf.locale = new Locale(...)) with conf.setLocale(new Locale(...)). It will internally call setLayoutDirection.Metacarpus
If you use context.getApplicationContext().getResources() you only have to set the language once for the whole applicationSaliva
Note that calling this code after setContentView in onCreate, the configuration is not retained on orientation change.Effective
"you have to set it every time you enter activity (each activity) " very important . ThanksIngenue
don't forget to recreate(); the activity after setting in case of different orientation language like ArabicTineid
Best would be to create an application class (class that extends android.app.Application) and in it's onCreate function, set the language using the above method by saving the preferred language in shared preference or wherever. And obviously in your android Manifest file add android:name="your application class" under the application tag. This way you don't need to set language in every activity. Hope it helps.Showy
Minor problem with this code: @deprecated See {@link android.content.Context#createConfigurationContext(Configuration)}. - updateConfiguration is deprecatedBoiling
@Alex I dont want to restart my app becasue app is doing some task like recording screen . so without restarting app is there any solution for Android 7.0Runnels
Adding this to onCreate was not enough for me, I had to add it to onResume. Not sure why.Soprano
recreate() can be called after this code to see the changes at the same time. Sometimes recreate may not work then use it under handler like this new Handler().post(new Runnable() { @Override public void run() { recreate(); } });Rieger
The updateConfiguration method has been deprecated, any solution instead?Malave
I am using the solution from the selected answer in here: https://mcmap.net/q/65854/-set-locale-programmatically I am linking in here to help others.Uniform
Totally recommend to use new Configuration object as declared in the updated answer but in the last step I used context.createConfigurationContext(configuration) because the context.updateConfiguration() is now deprecated.Yep
When trying this in the emulator it works fine (both debug and release) but not on my device. I was thinking maybe the app bundle part of it strips the language resources but I don't see any "splits" or anything like that. Any ideas?Neurocoele
@Neurocoele by adding this I have solved the issue bundle { language { // Specifies that the app bundle should not support // configuration APKs for language resources. These // resources are instead packaged with each base and // dynamic feature APK. enableSplit = false } }Geter
On what API level did you test this on? My implementation of this works on 26 onwards, but not belowClinch
you are wrong about two letters code, some languages can have three letters codeLejeune
Note that releasing app bundle doesn't includes languages resources that language switcher implemented this way will not work. Refer this answer for more details to support different languages in app bundle.Singlecross
This no longer worksTrove
L
229

This code really works:

fa = Persian, en = English

  • NOTES: Language code cannot got '-' & must be 2 small case letter only

Enter your language code in languageToLoad variable:

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;

public class Main extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String languageToLoad  = "fa"; // your language
    Locale locale = new Locale(languageToLoad); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
      getBaseContext().getResources().getDisplayMetrics());
    this.setContentView(R.layout.main);
  }
}

UPDATE on Jun 2021(Kotlin):

class Main : Activity() {
    // Called when the activity is first created.
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val config = resources.configuration
        val lang = "fa" // your language code
        val locale = Locale(lang)
        Locale.setDefault(locale)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
            config.setLocale(locale)
        else
            config.locale = locale

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            createConfigurationContext(config)
        resources.updateConfiguration(config, resources.displayMetrics)

        this.setContentView(R.layout.main)
    }
}
Limerick answered 7/2, 2012 at 9:10 Comment(14)
I want to change the locale at runtime, in your code, you put your code before setContentView() method. So your code is not useful for me, So How to change the language at run time, In my application, there are two radio button, on for English and other one for Arabic ,Biolysis
just put setContentView(R.layout.main); after click on a radio button this will work.Limerick
But It reset the update field and not the best way also, @LimerickBiolysis
getBaseContext().getResources().getDisplayMetrics()); - what is the purpose of this line?Osteen
@Buffalo, it's just the second argument for the Resources.updateConfiguration method. I've indented the code to make it more clear.Inflammatory
Heh, ok, sorry. I was at work at that time (Android), hence the diminished attention to detail.Osteen
but keyboard language is not changingAnchylose
But this works only in onCreate method. If I change language on button click menu doesn't change. If anyone can tell how to update menu texts?Staunch
This is working well for all activities upon setting in the launching activity. But, the action bar title seems unaffected and still continues to display the default language. Any idea what I might have missed?Waggon
Config.locale is deprecatedBoiling
instead of "config.locale = locale;" use "if (Build.VERSION.SDK_INT >= 17) { config.setLocale(locale); } else { config.locale = locale; }Infix
چطور کاری کنیم با یه دیالوگی چیزی بیاد و کاربر انتخاب کنه نه اینکه از روی زبان دستگاهش تشخیصش بده how can we set it by using dialog or something ? how user change Language without change language from system of divace ?Denn
Is it possible to list all of the locales the app has translation to?Kenzi
This no longer worksTrove
A
39

I was looking for a way to change the system language programmatically. While I fully understand that a normal application should never do that and instead either:

  • the user should be pointed(through an intent) to the system settings to change it manually
  • the application should handle its localization on its own just like described in the answer of Alex

there was a need to really change the language of the system programmtically.

This is undocumented API and thus should not be used for market/end-user applications!

Anyway heres the solution i found:

  Locale locale = new Locale(targetLocaleAsString);

  Class amnClass = Class.forName("android.app.ActivityManagerNative");
  Object amn = null;
  Configuration config = null;

  // amn = ActivityManagerNative.getDefault();
  Method methodGetDefault = amnClass.getMethod("getDefault");
  methodGetDefault.setAccessible(true);
  amn = methodGetDefault.invoke(amnClass);

  // config = amn.getConfiguration();
  Method methodGetConfiguration = amnClass.getMethod("getConfiguration");
  methodGetConfiguration.setAccessible(true);
  config = (Configuration) methodGetConfiguration.invoke(amn);

  // config.userSetLocale = true;
  Class configClass = config.getClass();
  Field f = configClass.getField("userSetLocale");
  f.setBoolean(config, true);

  // set the locale to the new value
  config.locale = locale;

  // amn.updateConfiguration(config);
  Method methodUpdateConfiguration = amnClass.getMethod("updateConfiguration", Configuration.class);
  methodUpdateConfiguration.setAccessible(true);
  methodUpdateConfiguration.invoke(amn, config);
Antibody answered 13/1, 2011 at 18:9 Comment(14)
give exception invocationtarget exceptionAnchylose
On which version of android? As it's undocumented API, they might have changed the names, or completely removed it... You'll have to check the android source i guess.Antibody
android 4.2,but in which package?Anchylose
Well depends where the invocationTargetException gets thrown. Then you should know the class that was changed.Antibody
@Antibody Hello, i use this code in my app, bt then m recently facing issues as i test it on versions 4.2 and 4.3 , i get invocation target exception, even though the permission has been specified. Any workaround ?Pickel
@Rat-a-tat-a-tat Ratatouille ,starting from Android 4.2 the android.permission.CHANGE_CONFIGURATION can only be granted by app signed with perform key.Brumfield
This solution still works on Android OS version 5.0. You can grant the required CHANGE_CONFIGURATION permission via adb. I made a helper app for this: play.google.com/store/apps/…Emmen
You can no longer grant the required CHANGE_CONFIGURATION permission via adb on Android OS version 6.0: Operation not allowed: java.lang.SecurityException: Permission android.permission.CHANGE_CONFIGURATION is not a changeab le permission typeEmmen
I put my app in /system/priv-app to work around the Android 6.0 issue. Details here.Sunnisunnite
API level 24 onwards, there's possibility to set multiple languages with setLocalesEmmen
@Anchylose I had to move my app from /system/app to /system/priv-app to make it workParlous
@icyerasor, If we have change the app language then if we have some searching option within app, and if we search in that then, how app will show data, should we develop some different database for each language or some android code setting is there so that app could show data according to search ?Buskined
getConfiguration method is removedRhinelandpalatinate
@nimamoradi The necessary changes for this are shown here. getConfiguration was moved to an inner class Proxy extending ActivityManagerNative. The changes should be made only from API 26 and above, check Build version. See the code used by Fastlane here to clarify. Finally the deprecated .locale = should be replaced with setLocale.Radke
P
36

If you want to mantain the language changed over all your app you have to do two things.

First, create a base Activity and make all your activities extend from this:

public class BaseActivity extends AppCompatActivity {

    private Locale mCurrentLocale;

    @Override
    protected void onStart() {
        super.onStart();

        mCurrentLocale = getResources().getConfiguration().locale;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Locale locale = getLocale(this);

        if (!locale.equals(mCurrentLocale)) {

            mCurrentLocale = locale;
            recreate();
        }
    }

    public static Locale getLocale(Context context){
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        String lang = sharedPreferences.getString("language", "en");
        switch (lang) {
            case "English":
                lang = "en";
                break;
            case "Spanish":
                lang = "es";
                break;
        }
        return new Locale(lang);
    }
}

Note that I save the new language in a sharedPreference.

Second, create an extension of Application like this:

    public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        setLocale();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        setLocale();
    }

    private void setLocale() {

        final Resources resources = getResources();
        final Configuration configuration = resources.getConfiguration();
        final Locale locale = getLocale(this);
        if (!configuration.locale.equals(locale)) {
            configuration.setLocale(locale);
            resources.updateConfiguration(configuration, null);
        }
    }
}

Note that getLocale() it's the same as above.

That's all! I hope this can help somebody.

Presumption answered 25/2, 2016 at 3:2 Comment(4)
App activity it is a primary activity, like a MainActivity? for example i can resolve this in setLocale() in my method onCreate()?Measures
App is an extension of Application, it's not an Activity. I do not understand what you need, sorry. Maybe you can try to explain me again :)Presumption
for those Android noobs like me, come here to learn what the Application is and how to use. mobomo.com/2011/05/how-to-use-application-object-of-androidCat
configuration.locate is deprecated, setLocale requires API 17+ and updateConfiguration is deprecatedBoiling
F
28

According to this article. You will need to download LocaleHelper.java referenced in that article.

  1. Create MyApplication class that will extends Application
  2. Override attachBaseContext() to update language.
  3. Register this class in manifest.

    public class MyApplication extends Application {
       @Override
       protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
       }
    }
    
    <application
         android:name="com.package.MyApplication"
         .../>
    
  4. Create BaseActivity and override onAttach() to update language. Needed for Android 6+

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
    
  5. Make all activities on your app extends from BaseActivity.

    public class LocaleHelper {
    
    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    
    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }
    
    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }
    
    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }
    
    public static Context setLocale(Context context, String language) {
        persist(context, language);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
    
        return updateResourcesLegacy(context, language);
    }
    
    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }
    
    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
    
        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }
    
    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
    
        return context.createConfigurationContext(configuration);
    }
    
    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Resources resources = context.getResources();
    
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }
    
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    
        return context;
    }
    }
    
Funiculate answered 30/1, 2018 at 22:53 Comment(2)
can't use super.attachBaseContext(LocaleHelper.onAttach(newBase)) cause I already using super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))Mosher
you can wrap one with another. super.attachBaseContext(CalligraphyContextWrapper.wrap(LocaleHelper.onAttach(newBase)))Zampardi
A
16

Just adding an extra piece that tripped me up.

While the other answers work fine with "de" for example

String lang = "de";
Locale locale = new Locale(lang); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());

The above wont work with for example "fr_BE" locale so it would use the values-fr-rBE folder or similar.

Needs the following slight change to work with "fr_BE"

String lang = "fr";

//create a string for country
String country = "BE";
//use constructor with country
Locale locale = new Locale(lang, country);

Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());
Ardith answered 25/9, 2013 at 10:1 Comment(6)
if you want to apply locale change to current opened activity call activity.recreate()Medulla
I know I'm late to the party, but the new Locale(lang, country) was all I needed!Kendo
activity.recreate() how it works or if we cal this then String lang = "fr";String country = "BE"; will never override how it will run timeAftmost
What about using android.content.res.Configuration conf = res.getConfiguration(); instead of creating a new Configuration instance? Is there any benefit for using a fresh one?Overeat
how about layoutDirection='locale'?Immersion
But if you update the locale and later try to access Locale.getDefault().country/context.resources.configuration.locales[0].language you get blank response. Any reason or solution for this.?Cyrene
S
16

Create a class Extends Application and create a static method. Then you can call this method in all activities before setContentView().

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
}

public static void setLocaleFa (Context context){
    Locale locale = new Locale("fa"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

public static void setLocaleEn (Context context){
    Locale locale = new Locale("en_US"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

}

Usage in activities:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyApp.setLocaleFa(MainActivity.this);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
}
Soap answered 17/6, 2015 at 7:58 Comment(0)
J
15

I am changed for German language for my app start itself.

Here is my correct code. Anyone want use this same for me.. (How to change language in android programmatically)

my code:

Configuration config ; // variable declaration in globally

// this part is given inside onCreate Method starting and before setContentView()

public void onCreate(Bundle icic) 
{
    super.onCreate(icic);
    config = new Configuration(getResources().getConfiguration());
    config.locale = Locale.GERMAN ;
    getResources().updateConfiguration(config,getResources().getDisplayMetrics());

    setContentView(R.layout.newdesign);
}
Jut answered 19/2, 2013 at 6:59 Comment(1)
@Jut Its not working for me and keyboard is not changing to the specified language.. How you have declared activity in manifest?Absentee
I
14

I know it's late to answer but i found this article here . Which explains the whole process very well and provides you a well structured code.

Locale Helper class:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;

import java.util.Locale;

/**
 * This class is used to change your application locale and persist this change for the next time
 * that your app is going to be used.
 * <p/>
 * You can also change the locale of your application on the fly by using the setLocale method.
 * <p/>
 * Created by gunhansancar on 07/10/15.
 */
public class LocaleHelper {

    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }

    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }

    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }

    public static Context setLocale(Context context, String language) {
        persist(context, language);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }

        return updateResourcesLegacy(context, language);
    }

    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }

    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();

        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);

        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }

        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return context;
    }
}

You need to override attachBaseContext and call LocaleHelper.onAttach() to initialize the locale settings in your application.

import android.app.Application;
import android.content.Context;

import com.gunhansancar.changelanguageexample.helper.LocaleHelper;

public class MainApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
    }
}

All you have to do is to add

LocaleHelper.onCreate(this, "en");

wherever you want to change the locale.

Ida answered 2/2, 2016 at 9:12 Comment(5)
LocaleHelper is a class from the article. Any links have a risk of being taken down. Please add the code into your answer.Boiling
I dont want to restart my app becasue app is doing some task like recording screen . so without restarting app is there any solution for Android 7.0Runnels
@Runnels I think that the article covers this case: You have two options to update currently visible layout: First, you can just update the text or any other language dependent resources one by one.Weigela
thanks for adding the new createConfigurationContext, that was helpfulIndeterminable
onCreate or onAttach to call ?Aquilar
C
13

Mayuri's answer is correct but that will only work on Api 33 or above. Here is the step by step backward compatible solution :

Step 1: create locales_config.xml under res/xml folder.

//res/xml/locales_config.xml
<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Add your required languages -->
    <locale android:name="hi" />
    <locale android:name="en" />
</locale-config>

Step 2 : Add localeConfig in Manifest under Application

<manifest>
<application
    android:localeConfig="@xml/locales_config">
</application>

Step 3 : Add this service in Manifest

<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
  android:name="autoStoreLocales"
  android:value="true" />
</service>

Step 4 : specify the same languages using the resConfigs property in your app's module-level build.gradle file:

  android {
  defaultConfig {
      ...
      resConfigs "hi","en"
  }
  }

(it requires appCompat version 1.6.0 or higher)

implementation 'androidx.appcompat:appcompat:1.6.0'

Step 5 : Now you can use below code to change app language (tested on android 9,10,12 & 13)

  LocaleListCompat appLocale = LocaleListCompat.forLanguageTags("hi"); //Give user selected language code 
  AppCompatDelegate.setApplicationLocales(appLocale);
Clifford answered 25/1, 2023 at 12:44 Comment(4)
The google docs: developer.android.com/guide/topics/resources/app-languages , and the sample app : github.com/android/user-interface-samples/tree/main/…Hudgins
The problem with this is that setApplicationLocales recreates the activity in a way that we get a black screen for a tiny moment.Sediment
when adding localeconfig to manifest, it says: Attribute localeConfig is only used in API level 33 and higher (current min is 28). So what about backward compatibility, if it is ignored for lower versions? And if you set Autostorelocales to true, then you don't need manual config xml fileScream
After spending 2 days, I finally found the right answer. Thank you for providing it.Buckshee
B
12

Time for a due update.

First off, the deprecated list with the API in which it was deprecated:

  • configuration.locale (API 17)
  • updateConfiguration(configuration, displaymetrics) (API 17)

The thing no question answered recently has gotten right is the usage of the new method.

createConfigurationContext is the new method for updateConfiguration.

Some have used it standalone like this:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
createConfigurationContext(overrideConfiguration);

... but that doesn't work. Why? The method returns a context, which then is used to handle Strings.xml translations and other localized resources (images, layouts, whatever).

The proper usage is like this:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
//the configuration can be used for other stuff as well
Context context  = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();

If you just copy-pasted that into your IDE, you may see a warning that the API requires you targeting API 17 or above. This can be worked around by putting it in a method and adding the annotation @TargetApi(17)

But wait. What about the older API's?

You need to create another method using updateConfiguration without the TargetApi annotation.

Resources res = YourApplication.getInstance().getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale("th");
res.updateConfiguration(conf, dm);

You don't need to return a context here.

Now, managing these can be difficult. In API 17+ you need the context created (or the resources from the context created) to get the appropriate resources based on localization. How do you handle this?

Well, this is the way I do it:

/**
 * Full locale list: https://mcmap.net/q/65857/-what-is-the-list-of-supported-languages-locales-on-android-closed
 * @param lang language code (e.g. en_US)
 * @return the context
 * PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
 */
public Context setLanguage(String lang/*, Context c*/){
    Context c = AndroidLauncher.this;//remove if the context argument is passed. This is a utility line, can be removed totally by replacing calls to c with the activity (if argument Context isn't passed)
    int API = Build.VERSION.SDK_INT;
    if(API >= 17){
        return setLanguage17(lang, c);
    }else{
        return setLanguageLegacy(lang, c);
    }
}

/**
 * Set language for API 17
 * @param lang
 * @param c
 * @return
 */
@TargetApi(17)
public Context setLanguage17(String lang, Context c){
    Configuration overrideConfiguration = c.getResources().getConfiguration();
    Locale locale = new Locale(lang);
    Locale.setDefault(locale);
    overrideConfiguration.setLocale(locale);
    //the configuration can be used for other stuff as well
    Context context  = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
    //Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
    return context;
}

public Context setLanguageLegacy(String lang, Context c){
    Resources res = c.getResources();
    // Change locale settings in the app.
    DisplayMetrics dm = res.getDisplayMetrics();//Utility line
    android.content.res.Configuration conf = res.getConfiguration();

    conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
    Locale.setDefault(conf.locale);
    res.updateConfiguration(conf, dm);

    //Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
    //target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
    //supplied for both things
    return c;
}

This code works by having one method that makes calls to the appropriate method based on what API. This is something I have done with a lot of different deprecated calls (including Html.fromHtml). You have one method that takes in the arguments needed, which then splits it into one of two (or three or more) methods and returns the appropriate result based on API level. It is flexible as you do't have to check multiple times, the "entry" method does it for you. The entry-method here is setLanguage

PLEASE READ THIS BEFORE USING IT

You need to use the Context returned when you get resources. Why? I have seen other answers here who use createConfigurationContext and doesn't use the context it returns. To get it to work like that, updateConfiguration has to be called. Which is deprecated. Use the context returned by the method to get resources.

Example usage:

Constructor or somewhere similar:

ctx = getLanguage(lang);//lang is loaded or generated. How you get the String lang is not something this answer handles (nor will handle in the future)

And then, whereever you want to get resources you do:

String fromResources = ctx.getString(R.string.helloworld);

Using any other context will (in theory) break this.

AFAIK you still have to use an activity context to show dialogs or Toasts. for that you can use an instance of an activity (if you are outside)


And finally, use recreate() on the activity to refresh the content. Shortcut to not have to create an intent to refresh.

Boiling answered 19/7, 2017 at 17:8 Comment(1)
Some may wonder if the created context will cost your memory. However according to Android Official Documentation: "Each call to this method returns a new instance of a Context object; Context objects are not shared, however common state (ClassLoader, other Resources for the same configuration) may be so the Context itself can be fairly lightweight." So I think Android does expect you to use a separate context object for locale things.Clo
S
10

For Android 7.0 Nougat (and lower) follow this article:

Change Language Programatically in Android

Old answer
This include RTL/LTR support:

public static void changeLocale(Context context, Locale locale) {
    Configuration conf = context.getResources().getConfiguration();
    conf.locale = locale;
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
       conf.setLayoutDirection(conf.locale);
    }

    context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());
}
Sherbet answered 31/8, 2016 at 11:22 Comment(1)
updateConfiguration is deprecated. The link is useful, please add it into your answer. (Link only answers are not good, as the link may be taken down. If that happens, this answer is useless)Boiling
O
9

If you write

android:configChanges="locale"

In every activity (in the manifest file) then no need to set it every time you enter Activity.

Outright answered 20/7, 2010 at 12:50 Comment(5)
If it's in the manifest then how does this constitute a change at runtime, which appeared to be what the O.P. wanted?Transcendent
@Transcendent It indicates to Android that the app will handle all matters regarding locale configuration internally, not that the locale is static. I'm not sure if that would prevent Android from setting the locale when changing between Activities, though, as I've only seen configChanges used for a hack to preserve Activity state on rotations/etc.Shaylynn
how to set the language only to english specific?Standardize
... until Android kills your activity because it needs more RAMQuery
@Brijesh If we have change the app language then if we have some searching option within app, and if we search in that then, how app will show data, should we develop some different database for each language or some android code setting is there so that app could show data according to search ?Buskined
R
8

The only solution that fully works for me is a combination of Alex Volovoy's code with application restart mechanism:

void restartApplication() {
    Intent i = new Intent(MainTabActivity.context, MagicAppRestart.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MainTabActivity.context.startActivity(i);
}


/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        startActivityForResult(new Intent(this, MainTabActivity.class), 0);         
    }
}
Revision answered 29/4, 2013 at 8:4 Comment(2)
after locale change you can also call activity.recreate()Medulla
I dont want to restart my app becasue app is doing some task like recording screen . so without restarting app is there any solution for Android 7.0Runnels
A
8

I was facing the same issue. On GitHub I found the Android-LocalizationActivity library.

This library makes it very simple to change the language of your app at runtime, as you can see in the code sample below. A sample project including the sample code below and more information can be found at the github page.

The LocalizationActivity extends AppCompatActivity, so you can also use it when you are using Fragments.

public class MainActivity extends LocalizationActivity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);

        findViewById(R.id.btn_th).setOnClickListener(this);
        findViewById(R.id.btn_en).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.btn_en) {
            setLanguage("en");
        } else if (id == R.id.btn_th) {
            setLanguage("th");
        }
    }
}
Archy answered 15/4, 2016 at 22:27 Comment(0)
T
8

You can ask the user to select the language in first screen and save it in SharedPreferences

SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("lang", "si");
editor.apply();
    
recreate();

Then you can take it in every Activity in your application. Here I have set English and Sinhala languages.

@Override
protected void attachBaseContext(Context base) {
    SharedPreferences prefs = base.getSharedPreferences("uinfo", MODE_PRIVATE);
    String restoredText = prefs.getString("lang", "No name defined");

    if (restoredText.equals("si")){
        super.attachBaseContext(LocaleHelper.localeUpdateResources(base, "si"));
    }else{
        super.attachBaseContext(LocaleHelper.localeUpdateResources(base, "en"));
    }
}

And this is your localUpdateResources method. Place it in LocalHelper class

public class LocaleHelper {
    public static Context localeUpdateResources(Context context, String languageCode) {

        Context newContext = context;

        Locale locale = new Locale(languageCode);
        Locale.setDefault(locale);

        Resources resources = context.getResources();
        Configuration config = new Configuration(resources.getConfiguration());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {

            config.setLocale(locale);
            newContext = context.createConfigurationContext(config);

        } else {

            config.locale = locale;
            resources.updateConfiguration(config, resources.getDisplayMetrics());
        }

        return newContext;

    }
}
Towny answered 21/6, 2021 at 5:18 Comment(0)
B
8

Resources.updateConfiguration() has been deprecated and I have resolved this without creating any custom ContextWrapper.

First I created an extension function

fun Context.setAppLocale(language: String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = resources.configuration
    config.setLocale(locale)
    config.setLayoutDirection(locale)
    return createConfigurationContext(config)
}

Then in the activity's attachBaseContext method, simply replacing the context with the new one.

override fun attachBaseContext(newBase: Context) {
  super.attachBaseContext(ContextWrapper(newBase.setAppLocale("bn")))
}
Berlin answered 26/6, 2021 at 4:59 Comment(7)
Your code works fine but in my scenario I want to change language upon language selection from the drop down menu. So after drop down value change how can I call that attachBaseContext(context: Context) method? And how can I use that language througout the whole app?Chacon
In that case you have to call the recreate() method of the activity when a language is being selected from dropdown.Berlin
Thanks for pointing it out. I'd already done that and it's working fine.Chacon
How do you update locale for application context? It's working for me for activity contexts, but some strings (that are using resources from application context) are still not translated.Mccarron
I don't think you can change for an application context, unless you change the language settings of the device, as the application is the first thing to launch, even before updating the application locale, once it's created you can't change it. So it will be best not to use application context for string res. Try to use activity context.Berlin
Perfect work this code :)Enlarger
@Mccarron you can do it if you override application on create an change locale also there as shown in some other examples...Moyna
D
7

The support to Per-app language preferences was just added to API 33 (Android 13, Tiramisu currently on Developer Preview).

To change the app's locale just call setApplicationLocales from LocaleManager:

// Set app locale to pt-BR (Portuguese, Brazil)
getSystemService(LocaleManager::class.java)
    .applicationLocales = LocaleList(Locale.forLanguageTag("pt-BR"))

See more at https://developer.android.com/about/versions/13/features/app-languages#api-impl

I've wrote an article about this feature https://proandroiddev.com/exploring-the-new-android-13-per-app-language-preferences-8d99b971b578

Dissogeny answered 17/2, 2022 at 2:15 Comment(1)
@Moyna setApplicationLocales backward compatibilityDayfly
F
6

For Arabic/RTL support

  1. You must update your language settings through - attachBaseContext()
  2. For android version N and above you must use createConfigurationContext() & updateConfiguration() - else RTL layout not working properly

 @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(updateBaseContextLocale(newBase));
    }

    public Context updateBaseContextLocale(Context context) {
        String language = SharedPreference.getInstance().getValue(context, "lan");//it return "en", "ar" like this
        if (language == null || language.isEmpty()) {
            //when first time enter into app (get the device language and set it
            language = Locale.getDefault().getLanguage();
            if (language.equals("ar")) {
                SharedPreference.getInstance().save(mContext, "lan", "ar");
            }
        }
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            updateResourcesLocale(context, locale);
            return  updateResourcesLocaleLegacy(context, locale);
        }

        return updateResourcesLocaleLegacy(context, locale);
    }

    @TargetApi(Build.VERSION_CODES.N)
    private Context updateResourcesLocale(Context context, Locale locale) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private Context updateResourcesLocaleLegacy(Context context, Locale locale) {
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        return context;
    }
Fink answered 18/5, 2020 at 8:23 Comment(1)
This should be the correct answer. Just test it and works (22/02/2021). Thank you my friend.Futilitarian
P
6

This feature is officially launched by Google for Android 13 (and has backward support too). Android now lets you choose language per app.

Official documentation here - https://developer.android.com/guide/topics/resources/app-languages

To set a user's preferred language, you would ask the user to select a locale in the language picker, then set that value in the system:

// 1. Inside an activity, in-app language picker gets an input locale "xx-YY"
// 2. App calls the API to set its locale
mContext.getSystemService(LocaleManager.class
    ).setApplicationLocales(newLocaleList(Locale.forLanguageTag("xx-YY")));
// 3. The system updates the locale and restarts the app, including any configuration updates
// 4. The app is now displayed in "xx-YY" language

To get a user's current preferred language to display in the language picker, your app can get the value back from the system:


// 1. App calls the API to get the preferred locale
LocaleList currentAppLocales =
    mContext.getSystemService(LocaleManager.class).getApplicationLocales();
// 2. App uses the returned LocaleList to display languages to the user
Pentathlon answered 23/8, 2022 at 2:59 Comment(0)
S
5

At first create multi string.xml for different languages; then use this block of code in onCreate() method:

super.onCreate(savedInstanceState);
String languageToLoad  = "fr"; // change your language here
Locale locale = new Locale(languageToLoad); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
  getBaseContext().getResources().getDisplayMetrics());
this.setContentView(R.layout.main);
Sibbie answered 6/2, 2017 at 10:20 Comment(1)
Thank you, this code works great, I tested on Android 5.x and 6.x without any problemsConker
M
5
Locale locale = new Locale("en");
Locale.setDefault(locale);

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

Important update:

context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());

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

Monies answered 12/5, 2017 at 13:7 Comment(6)
updateConfiguration is deprecated. AFAIK you use createConfigurationContext and apply the context you have to it (Context ctx = createConfigurationContext(args); and get resources from thatBoiling
I know that it is deprecated. But anyway I don`t know any solution which can work on android 5 and higher.Monies
Then you clearly didn't check the javadoc. you call the context created from createConfigurationContextBoiling
Ok, but anyway we should call updateConfiguration(), right?Monies
Don't use the deprecated call. Meaning no calling updateConfigurationBoiling
Even if we call recreate() activity method, it doesn`t update language on the devices >= 21. Did you try to call recreate after your variants on devices >= 21? Is it work?Monies
J
5

None of the solutions listed here helped me.

The language did not switch on android >= 7.0 if AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

This LocaleUtils works just fine: https://gist.github.com/GigigoGreenLabs/7d555c762ba2d3a810fe

LocaleUtils

public class LocaleUtils {

public static final String LAN_SPANISH      = "es";
public static final String LAN_PORTUGUESE   = "pt";
public static final String LAN_ENGLISH      = "en";

private static Locale sLocale;

public static void setLocale(Locale locale) {
    sLocale = locale;
    if(sLocale != null) {
        Locale.setDefault(sLocale);
    }
}

public static void updateConfig(ContextThemeWrapper wrapper) {
    if(sLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Configuration configuration = new Configuration();
        configuration.setLocale(sLocale);
        wrapper.applyOverrideConfiguration(configuration);
    }
}

public static void updateConfig(Application app, Configuration configuration) {
    if(sLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        //Wrapping the configuration to avoid Activity endless loop
        Configuration config = new Configuration(configuration);
        config.locale = sLocale;
        Resources res = app.getBaseContext().getResources();
        res.updateConfiguration(config, res.getDisplayMetrics());
    }
}
}

Added this code to Application

public class App extends Application {
public void onCreate(){
    super.onCreate();

    LocaleUtils.setLocale(new Locale("iw"));
    LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    LocaleUtils.updateConfig(this, newConfig);
}
}

Code in Activity

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}
Jordon answered 1/7, 2019 at 21:50 Comment(1)
This works, thank you. Also, it doesn't have anything to do with Calligraphy library while changing the font which is so great.Spada
I
4

Locale configuration should be set in each activity before setting the content - this.setContentView(R.layout.main);

Informality answered 13/11, 2012 at 14:48 Comment(2)
But what if you want to toggle it on the fly, after setContentView() has been called?Suboxide
after locale change you can also call activity.recreate()Medulla
S
4
/*change language at Run-time*/
//use method like that:
//setLocale("en");
 public void setLocale(String lang) { 
  myLocale = new Locale(lang);         
  Resources res = getResources();         
  DisplayMetrics dm = res.getDisplayMetrics();         
  Configuration conf = res.getConfiguration();         
  conf.locale = myLocale;         
  res.updateConfiguration(conf, dm);         
  Intent refresh = new Intent(this, AndroidLocalize.class);         
  startActivity(refresh); 
 }
Sirloin answered 25/2, 2015 at 15:27 Comment(1)
no need to start new activity, just refresh actual activity.recreate()Medulla
K
4

Here is some code that works for me:

public class  MainActivity extends AppCompatActivity {
    public static String storeLang;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        SharedPreferences shp = PreferenceManager.getDefaultSharedPreferences(this);
        storeLang = shp.getString(getString(R.string.key_lang), "");

        // Create a new Locale object
        Locale locale = new Locale(storeLang);

        // Create a new configuration object
        Configuration config = new Configuration();
        // Set the locale of the new configuration
        config.locale = locale;
        // Update the configuration of the Accplication context
        getResources().updateConfiguration(
                config,
                getResources().getDisplayMetrics()
        );

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Source: here

Krakow answered 29/7, 2018 at 12:55 Comment(0)
P
2

I finally figured out how to setup it to work on both =N android versions.

Extend AppCompatActivity with your own abstract class, like:

abstract class MLAppCompatActivity : AppCompatActivity() {
  override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(LocaleHelper.wrap(newBase))
  }

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        LocaleHelper.wrap(this)
    }
  }
}

attachBaseContext is called on Android >=N versions and on this way activity will use the correct context. On Android <N, we have to call this function on one other way, before setting content view. Therefore we override onCreate function to set correct context. Means, whenever you create a new Activity you have to extend your abstract class. Like this one:

class TermsActivity : MLAppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_terms)
  }
}

And finally the LocaleHelper is like this:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;

import com.at_zone.constants.SharedPreferencesKeys;

import java.util.Locale;

public class LocaleHelper extends ContextWrapper {

    public LocaleHelper(Context base) {
        super(base);
    }

    public static Context wrap(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                SharedPreferencesKeys.SHARED_PREFERENCES, Context.MODE_PRIVATE
        );
        String language = sharedPreferences.getString(SharedPreferencesKeys.CURRENT_LANGUAGE, "default");
        if (!language.equals("default")) {
            Configuration config = context.getResources().getConfiguration();
            if (!language.equals("")) {
                Locale locale = new Locale(language);
                Locale.setDefault(locale);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    setSystemLocale(config, locale);
                } else {
                    setSystemLocaleLegacy(context, config, locale);
                }
                config.setLayoutDirection(locale);
                context = context.createConfigurationContext(config);
            }
            return new LocaleHelper(context);
        }
        return context;
    }

    public static String getSystemLanguage(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return getSystemLocale(context).getLanguage().toLowerCase();
        } else {
            return getSystemLocaleLegacy(context).getLanguage().toLowerCase();
        }
    }

    public static Locale getSystemLocaleLegacy(Context context) {
        Configuration config = context.getResources().getConfiguration();
        return config.locale;
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static Locale getSystemLocale(Context context) {
        return context.getResources().getConfiguration().getLocales().get(0);
    }

    public static void setSystemLocaleLegacy(Context context, Configuration config, Locale locale) {
        config.locale = locale;
        Resources res = context.getResources();
        DisplayMetrics dm = res.getDisplayMetrics();
        res.updateConfiguration(config, dm);
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static void setSystemLocale(Configuration config, Locale locale) {
        config.setLocale(locale);
    }

}
Pee answered 18/8, 2020 at 8:24 Comment(0)
J
1

There are some steps that you should implement

First, you need to change the locale of your configuration

Resources resources = context.getResources();

Configuration configuration = resources.getConfiguration();
configuration.locale = new Locale(language);

resources.updateConfiguration(configuration, resources.getDisplayMetrics());

Second, if you want your changes to apply directly to the layout that is visible, you either can update the views directly or you can just call activity.recreate() to restart the current activity.

And also you have to persist your changes because after user closes your application then you would lose the language change.

I explained more detailed solution on my blog post Change Language Programmatically in Android

Basically, you just call LocaleHelper.onCreate() on your application class and if you want to change locale on the fly you can call LocaleHelper.setLocale()

Jaime answered 8/10, 2015 at 12:56 Comment(1)
@LunarWatcher Yes if you actually check the code on github or gist, it is already handled.Jaime
I
1

This is working when i press button to change text language of my TextView.(strings.xml in values-de folder)

String languageToLoad = "de"; // your language
Configuration config = getBaseContext().getResources().getConfiguration();
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
recreate();
Ingenue answered 3/4, 2017 at 12:15 Comment(0)
B
1

Add LocaleHelper class

public class LocaleHelper{ 
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
public static Context onAttach(Context context) {
    String lang = getPersistedData(context, Locale.getDefault().getLanguage());
    return setLocale(context, lang);
}

public static Context onAttach(Context context, String defaultLanguage) {
    String lang = getPersistedData(context, defaultLanguage);
    return setLocale(context, lang);
}

public static String getLanguage(Context context) {
    return getPersistedData(context, Locale.getDefault().getLanguage());
}
public static Context setLocale(Context context, String language) {
    persist(context, language);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, language);
    }

    return updateResourcesLegacy(context, language);
}

private static String getPersistedData(Context context, String defaultLanguage) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}

private static void persist(Context context, String language) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.putString(SELECTED_LANGUAGE, language);
    editor.apply();
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Resources resources = context.getResources();

    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLayoutDirection(locale);
    }

    resources.updateConfiguration(configuration, resources.getDisplayMetrics());

    return context;
}
}

In Activity or Fragment

Context context = LocaleHelper.setLocale(this, App.getSharedPre().getLanguage());
Resource resources = context.getResources();

Now SetText on every text

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));
Bernadette answered 18/10, 2019 at 6:9 Comment(0)
C
1

For me the best solution is this one: https://www.bitcaal.com/how-to-change-the-app-language-programmatically-in-android/

package me.mehadih.multiplelanguage;

import androidx.appcompat.app.AppCompatActivity;

import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;

import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setApplicationLocale("az"); // short name of language. "en" for English
        setContentView(R.layout.activity_main);

    }

    private void setApplicationLocale(String locale) {
        Resources resources = getResources();
        DisplayMetrics dm = resources.getDisplayMetrics();
        Configuration config = resources.getConfiguration();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            config.setLocale(new Locale(locale.toLowerCase()));
        } else {
            config.locale = new Locale(locale.toLowerCase());
        }
        resources.updateConfiguration(config, dm);
    }
}
Ctenidium answered 27/8, 2020 at 15:16 Comment(1)
I see, after finding a better solution I will post in hereCtenidium
W
1

You must make these changes to the attachBaseContext function when you run each Activity.

public Context createConfiguration(Context context, String lan) {
    Locale locale = new Locale(lan);
    Configuration configuration = new Configuration(context.getResources().getConfiguration());
    configuration.setLocale(locale);
    return context.createConfigurationContext(configuration);
}

@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(createConfiguration(newBase, "en"/*LANGUAGE_SELECTED*/)));
}

Alse for the activity you are in, after changing the language, call function recreate();

Westbrook answered 28/1, 2023 at 8:26 Comment(0)
I
1

Things changed and today, relevent solution comes from: Android site.

There are many ways, but the simplest solution is to implement it using the AndroidX support library:

  1. add to the AndroidManifest.xml:

     <service
         android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
         android:enabled="false"
         android:exported="false">
         <meta-data
             android:name="autoStoreLocales"
             android:value="true" />
     </service>
    
  2. in the build.gradle

    dependencies { implementation 'androidx.appcompat:appcompat:1.6.1'`

  3. Add the code where you want to change the locale

     SharedPreferences preferences = getSharedPreferences("priv_settings", Context.MODE_PRIVATE);
     String langCode = preferences.getString("Lang_code", "En");
    
     LocaleListCompat appLocale = LocaleListCompat.forLanguageTags(langCode);  // or use "xx-YY"
     AppCompatDelegate.setApplicationLocales(appLocale);
    

Beware: calling setApplicationLocales() recreates your Activity

Implicative answered 14/9, 2023 at 7:57 Comment(1)
Thx. This works for me. Im using android Upside down cake.Mather
B
1

Android API 26 or upper version:

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

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

but in android 25 or below this also works fine, but may need to update in all activity,

Locale locale = new Locale(lang);
Locale.setDefault(locale);
Configuration configuration = new Configuration();
configuration.locale = locale;
getBaseContext().getResources().updateConfiguration(configuration, getBaseContext().getResources().getDisplayMetrics());
Bushy answered 10/3 at 3:51 Comment(0)
V
0

For androidx.appcompat:appcompat users, above solutions will work after version 1.3.0. As mentioned in here.

Viehmann answered 17/6, 2021 at 11:55 Comment(0)
R
0

if you are using fragments and you want to Change app language programmatically in Android use this method

  public void setLocale(Activity activity, String languageCode) {
    Locale locale = new Locale(languageCode);
    Locale.setDefault(locale);
    Resources resources = activity.getResources();
    Configuration config = resources.getConfiguration();
    config.setLocale(locale);
    resources.updateConfiguration(config, resources.getDisplayMetrics());
     SettingsFragment settingsFragment = new SettingsFragment();
     FragmentManager fragmentManager = requireActivity().getSupportFragmentManager();
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    activity.overridePendingTransition(0,0);
     fragmentTransaction.replace(R.id.main, settingsFragment).commit();
}

and call it like that

setLocale(requireActivity(),"fr");

just change SettingsFragment with your fragment name where you call the method this basically refresh the layout to get the new strings on the view and if you want to set the method on another class just add context like this

public void setLocale(Activity activity, String languageCode,Context context) {
    Locale locale = new Locale(languageCode);
    Locale.setDefault(locale);
    Resources resources = activity.getResources();
    Configuration config = resources.getConfiguration();
    config.setLocale(locale);
    resources.updateConfiguration(config, resources.getDisplayMetrics());
    SettingsFragment settingsFragment = new SettingsFragment();
    FragmentManager fragmentManager = ((AppCompatActivity) context).getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    activity.overridePendingTransition(0,0);
    fragmentTransaction.replace(R.id.main, settingsFragment).commit();
}
Rembrandt answered 16/8, 2022 at 12:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.