Change app language programmatically in Android

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)
    }
}

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

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);

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.