How to change language of app when user selects language?
Asked Answered
P

12

124

I want my app to support three languages Spanish,Portuguese & English. And give option to select language in app.I have made

1) 3 drawable folders drawable-es,drawable-pt,drawable.

2) 3 values folder values-es,values-pt,values.Change String.xml values according to languages.

I have imageView to select language.When click it menu open that consists option English,Spanish,Portuguese.

I set Locale inside app on option selection by this code

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.en:
             Locale locale = new Locale("en"); 
             Locale.setDefault(locale);
             Configuration config = new Configuration();
             config.locale = locale;
             getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
             Toast.makeText(this, "Locale in English !", Toast.LENGTH_LONG).show();
             break;

        case R.id.pt:
             Locale locale2 = new Locale("pt"); 
             Locale.setDefault(locale2);
             Configuration config2 = new Configuration();
             config2.locale = locale2;
             getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Portugal !", Toast.LENGTH_LONG).show();
             break;

        case R.id.es:
             Locale locale3 = new Locale("es"); 
             Locale.setDefault(locale3);
             Configuration config3 = new Configuration();
             config3.locale = locale3;
             getBaseContext().getResources().updateConfiguration(config3, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Spain !", Toast.LENGTH_LONG).show();
             break;     
    }
    return super.onOptionsItemSelected(item);
}

I have declare in Manifest- android:configChanges="locale"

It work but it have some issue.

Problem:-

1)When language selected, screen that consists image of language selection not change but other screens are change.

2)After orientation change app restore language according to locale of phone.

Psoriasis answered 16/10, 2012 at 5:46 Comment(3)
For the 2nd problem try adding: android:configChanges="locale" for your Activity inside the AndroidManifest.xmlAlleviative
i have already add in every activitiy in my manifest.Psoriasis
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-LanguagesElectrician
P
188

It's excerpt for the webpage: http://android.programmerguru.com/android-localization-at-runtime/

It's simple to change the language of your app upon user selects it from list of languages. Have a method like below which accepts the locale as String (like 'en' for English, 'hi' for hindi), configure the locale for your App and refresh your current activity to reflect the change in language. The locale you applied will not be changed until you manually change it again.

public void setLocale(String lang) { 
    Locale 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); 
    finish();
    startActivity(refresh); 
} 

Make sure you imported following packages:

import java.util.Locale; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.content.res.Configuration; 
import android.content.res.Resources; 
import android.util.DisplayMetrics; 

add in manifest to activity android:configChanges="locale|orientation"

Paedo answered 18/10, 2012 at 11:55 Comment(12)
Yeah sure. I can provide the excerpt of the web page. Where I need to provide please let me know. Thanks.Paedo
As an additional information for you, my AVD became error. So I deleted Intent refresh = new Intent(this, AndroidLocalize.class); startActivity(refresh); and placed it in onSharedPreferenceChange method. Simply, I placed it out of setLocale(String lang) subclass. And it worked now.Hower
How to add polish in language translation, as the local.class dosnt have the polish entry in it. How to do that?Goodale
Be sure to add finish() so that you don't have two copies of your activity in the navigation stack.Lebaron
finish() needs to be called before startActivity(refresh). Otherwise App may exit instead of the Activity being restarted.Merill
Hi, I did it, it works, but when I restart the app, it returns to the default language ..Aruabea
Yeah, It's working fine but I'm facing one issue in this code. Suppose I change my app language English to arabic using this code.It's working fine but Once I kill application then restart this app my application language will be automatically reset.I active with english language.Is it possible to my application language remain same which user previously selected without using Shared Preferance?Sanctitude
Configuration config = new Configuration(newConfig); config.locale = locale; In my case getting this message. locale deprecated in API level 25Sudhir
This answer needs to be updated since some of the APIs used are now deprecated.Bremen
@Paedo 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 ?Inject
In case you set a RTL locale like Arabic "ar" and want your -ldrtl resource folders to work as well then also call conf.setLayoutDirection(locale); under conf.locale = myLocale;Trichosis
Instead of finish and startActivity , you can simply use activity.recreate()Harlamert
M
12

all the above @Uday's code is perfect but only one thing is missing(default config in build.gradle)

public void setLocale(String lang) { 
    Locale 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); 
    finish();
    startActivity(refresh); 
} 

Mine was not working just because the languages were not mentioned in the config file(build.gradle)

 defaultConfig {
    resConfigs "en", "hi", "kn"
}

after that, all languages started running

Madly answered 1/10, 2018 at 9:50 Comment(3)
itS NOT WORKINGAbm
Is it really needed?Toughminded
@Toughminded yes. when I added languages in config file Udhay's code started runningMadly
S
11

Good solutions explained pretty well here. But Here is one more.

Create your own CustomContextWrapper class extending ContextWrapper and use it to change Locale setting for the complete application. Here is a GIST with usage.

And then call the CustomContextWrapper with saved locale identifier e.g. 'hi' for Hindi language in activity lifecycle method attachBaseContext. Usage here:

@Override
protected void attachBaseContext(Context newBase) {
    // fetch from shared preference also save the same when applying. Default here is en = English
    String language = MyPreferenceUtil.getInstance().getString("saved_locale", "en");
    super.attachBaseContext(MyContextWrapper.wrap(newBase, language));
}
Serilda answered 3/9, 2017 at 15:1 Comment(5)
Thanks for the link it is working but i didn't understand a few things , i just called the MyContextWrapper.warp in onAttach of just one fragment of my app but the language was changed for the whole app, but the activity titles were not changed , i think it is because the manifest titles takes precedence , but if i call the same method in onAttachBaseContex on my subclass of application the activity titles also changes to selected language , but then the changes are only applied to the fragment i called in the warp method, why is that ?Bastardize
@AbhinavChauhan I am not sure about this to be true. I need to check that one. I have never faced this issue when I implemented this solution. However, It has been long time and there may be some changes in the Android implementation for newer versions. Alternatively try some newest answers on this post.Serilda
i tried many solution but non of them worked or maybe i implemented them incorrectly , may your class works good with activities , i am using it warp method in onAttach of the fragment ,previously i said i just needed to do it with mainactivity fragment and language changed in whole app it is true, but for all other fragments language changes to english on configuration change so i need to put in onattach of all the fragments and instead of manifest i set the actionbar titles in code , now the app is working as expected. thanksBastardize
Okay! I am sure you do not have to do this for every screen, just the first activity that launches and inside the attachBaseContext function only. And that does it for all the screens. Have you created a `BaseActivity' for all activities in your app?Serilda
No i was trying to do it in the my subclass of application thinking that it will be applied to whole application , then in all fragments, but it turns out that the wrap() code needs to be executed at every configuration changes , so i putted it in the Abstract activity from which all other activities extends , now it is workingBastardize
S
6

You should either remove android:configChanges="locale" from manifest, which will cause activity to reload, or override onConfigurationChanged method:

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
    // your code here, you can use newConfig.locale if you need to check the language
    // or just re-set all the labels to desired string resource
}
Sennacherib answered 29/10, 2013 at 21:8 Comment(2)
Removing android:configChanges="locale" from manifest does not prevent app from restarting. It will restart regardless of if that is added to manifest or not.Lipps
I'm not saying that removing android:configChanges="locale" from manifest prevents the app from restarting, I'm saying exactly the opposite. Now, for the case when we have android:configChanges="locale" in the manifest, it used to prevent the app from reloading at the time I wrote this answer, I can't say for sure it's the case now.Sennacherib
L
5

Kotlin solution using context extension

fun Context.applyNewLocale(locale: Locale): Context {
    val config = this.resources.configuration
    val sysLocale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        config.locales.get(0)
    } else {
        //Legacy
        config.locale
    }
    if (sysLocale.language != locale.language) {
        Locale.setDefault(locale)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            config.setLocale(locale)
        } else {
            //Legacy
            config.locale = locale
        }
        resources.updateConfiguration(config, resources.displayMetrics)
    }
    return this
}

Usage

override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase?.applyNewLocale(Locale("es", "MX")))
}
Linnie answered 16/9, 2020 at 15:13 Comment(0)
H
3

Udhay's sample code works well. Except the question of Sofiane Hassaini and Chirag SolankI, for the re-entrance, it doesn't work. I try to call Udhay's code without restart the activity in onCreate() , before super.onCreate(savedInstanceState);. Then it is OK! Only a little problem, the menu strings still not changed to the set Locale.

    public void setLocale(String lang) { //call this in onCreate()
      Locale 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); 
      //finish();
    } 
Hornet answered 28/9, 2017 at 19:58 Comment(4)
same problem with menu strings. Do you solve the problem?Piled
@AlexS, I didn't find ways to fix the problem in menu string. But found to exit the app and then reenter , the menu strings can be normally changed to the new Locale.Hornet
you mean Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?Piled
@AlexS, No! adding the new Intent() and startActivity() may make it return to the default language when restart the app. What I mean is if users exit the app and reenter the app, the menu strings can be changed to the new Locale.Hornet
G
3

Those who getting the version issue try this code ..

public static void switchLocal(Context context, String lcode, Activity activity) {
        if (lcode.equalsIgnoreCase(""))
            return;
        Resources resources = context.getResources();
        Locale locale = new Locale(lcode);
        Locale.setDefault(locale);
        android.content.res.Configuration config = new 
        android.content.res.Configuration();
        config.locale = locale;
        resources.updateConfiguration(config, resources.getDisplayMetrics());
        //restart base activity 
        activity.finish();
        activity.startActivity(activity.getIntent());
    }
Gehman answered 23/2, 2019 at 11:55 Comment(0)
Q
2

There's a new (and better) implementation for in-app language pickers since Appcompat 1.6.0-alpha04 and later: https://developer.android.com/about/versions/13/features/app-languages#androidx-impl

Methods used in custom implementations suggested by others are deprecated in API level 25.

Quicklime answered 19/7, 2022 at 4:52 Comment(0)
R
0
    Locale locale = new Locale(langCode);
    Locale.setDefault(locale);
    Configuration configuration = context.getResources().getConfiguration();
    configuration.locale = locale;
    configuration.setLayoutDirection(locale); // for RTL changes
    preferences.setLocalePref(langCode);
    context.getResources().updateConfiguration(configuration, context.getResources().getDisplayMetrics());

Here, langCode is the required language code. You can save the language code as string in sharedPreferences. and you can call this code super.onCreate(savedInstanceState) in onCreate.

Rennes answered 18/2, 2021 at 12:31 Comment(0)
L
0

My experience: Changing language must be called before setContentView to make sure all text are changed

Lymphadenitis answered 12/2 at 6:47 Comment(1)
After chaging locale call onConfigurationChanges(configuration) which will kill recreate the activity.Sherleysherline
R
0

Try using below library:

implementation("com.github.YarikSOffice:lingver:1.3.0")

You can change language using this line:

Lingver.getInstance().setLocale(context, languageList[languageAdapter.selectedPos].code)

also restart your main activity on language Change.

Raft answered 12/2 at 10:56 Comment(0)
J
0

Answers in this thread mostly are outdated and do not work. I've figured out that there is a more or less working solution, which is described in the Google doc. However it's quite complex and has downsides, so I'll just write down this step-by-step guide, which works for most Android versions to date:

(1) Create a file called res/xml/locales_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
   <locale android:name="en"/>
   <locale android:name="de"/>
<locale-config/>

(2) Add reference to this file to AndroidManifest.xml:

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

(3) Also, add a service to support Android 12 and below:

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

(4) Add languages to app/build.gradle:

android {
      defaultConfig {
          ...
          resConfigs("en", "de")
      }
  }

(5) Change language in code:

AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags("de"))

To make this method work, you'll need ot ensure that following are true:

  • targetSdk 33 and minSdk 24 (not a big deal nowadays for most apps);
  • Your activities extend AppCompatActivity and have the AppCompat* theme;
  • AppCompatDelegate is available from implementation 'androidx.appcompat:appcompat:1.6.0'.

IMPORTANT: When accessing your String (or any other localized resource), make sure that you use Context of the Activity, and not of the Application. Strings (or other resources) you will get via. Application Context will not be affected by this method, so they will be in the system language!

Juice answered 5/3 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.