How to refresh activity after changing language (Locale) inside application
Asked Answered
S

10

72

My application users can change the language from the app's settings. Is it possible to change the language inside the application without having effect to general language settings ? This question of stackoverflow is very useful to me and i have tried it. After changing language newly created activities display with changed new language, but current activity and previously created activities which are in pause state are not updated.How to update activities ? I have also spent a lot of time trying to make the preference change to be applied immediately but didn't succeed. When application is restarted, all activities created again, so now language changed correctly.

android:configChanges="locale" 

also added in manifest for all activities. and also support all screen. Currently I have not done any thing in activity's onResume() method. Is there any way to refresh or update activity (without finish and starting again) ? Am I missing something to do in onResume() method?

Subsistent answered 8/11, 2011 at 10:47 Comment(1)
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-workDorcy
D
73

After changing language newly created activities display with changed new language, but current activity and previously created activities which are in pause state are not updated.How to update activities ?

Pre API 11 (Honeycomb), the simplest way to make the existing activities to be displayed in new language is to restart it. In this way you don't bother to reload each resources by yourself.

private void restartActivity() {
    Intent intent = getIntent();
    finish();
    startActivity(intent);
}

Register an OnSharedPreferenceChangeListener, in its onShredPreferenceChanged(), invoke restartActivity() if language preference was changed. In my example, only the PreferenceActivity is restarted, but you should be able to restart other activities on activity resume by setting a flag.

Update (thanks @stackunderflow): As of API 11 (Honeycomb) you should use recreate() instead of restartActivity().

public class PreferenceActivity extends android.preference.PreferenceActivity implements
        OnSharedPreferenceChangeListener {

    // ...

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if (key.equals("pref_language")) {
            ((Application) getApplication()).setLocale();
            restartActivity();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }
}

I have a blog post on this topic with more detail, but it's in Chinese. The full source code is on github: PreferenceActivity.java

Despiteful answered 13/12, 2012 at 15:1 Comment(5)
I used this together with overridePendingTransition(0,0); Ugly but it worked and looks okay =)Shamrock
As of API 11 (Honeycomb) you should use recreate() instead of your restartActivity method.Acrimonious
@stackunderflow Thanks for that. Unlike finishing and restarting the activity yourself, recreate() doesn't destroy your retained headless fragments. Hallelujah!Archimage
Since i have used spinner everytime i do this it infinitely finishes and restarts my activity.Sample
Don`t work actuality ((Application) getApplication()).setLocale();Bagpipe
P
24

If I imagined that you set android:configChanges in manifest.xml and create several directory for several language such as: values-fr OR values-nl, I could suggest this code(In Activity class):

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

    Button btn = (Button) findViewById(R.id.btn);
    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // change language by onclick a button
             Configuration newConfig = new Configuration();
             newConfig.locale = Locale.FRENCH;
             onConfigurationChanged(newConfig);
        }
    });
}

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

    getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
    setContentView(R.layout.main);
    setTitle(R.string.app_name);

    // Checks the active language
    if (newConfig.locale == Locale.ENGLISH) {
        Toast.makeText(this, "English", Toast.LENGTH_SHORT).show();
    } else if (newConfig.locale == Locale.FRENCH){
        Toast.makeText(this, "French", Toast.LENGTH_SHORT).show();
    }
}

I tested this code, It is correct.

Periwinkle answered 23/7, 2012 at 10:39 Comment(0)
S
12

Since the string resources will have already been loaded for the existing locale, the activities already opened will not automatically display using strings from the new locale. The only way to solve this is to reload all of the strings and set them again on the views. Typically, a call to setContentView(...) will be able to cover this (depending on your Activity structure), but of course it has the side-effect of losing any view state you had.

public void onResume() {
    super.onResume();
    ...
    if (localeHasChanged) {
        setContentView(R.layout.xxx);
    }
    ...
}

You will probably not want to reload the views every single time in onResume(), but only when the locale has changed. Checking when to update the views (i.e. localeHasChanged) is a matter of propagating the locale change event to the previous activities. This could be done in many ways, such as using static singleton-esque state or persisting this event to storage.

You could also try to minimise the number of Activities that can be opened when you can change the locale, e.g. by having the selection be at one of the initial screens.

Salvador answered 11/3, 2012 at 1:16 Comment(0)
M
12

For Android 4.2 (API 17), you need to use android:configChanges="locale|layoutDirection" in your AndroidManifest.xml. See onConfigurationchanged is not called over jellybean(4.2.1)

Mesics answered 11/4, 2013 at 18:24 Comment(0)
S
7

You can use recreate(); to restart your activity when Language change.

I am using following code to restart activity when language change:

SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Configuration config = getBaseContext().getResources().getConfiguration();

String lang = settings.getString("lang_list", "");

if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang)) {
      recreate();  //this is used for recreate activity
      Locale locale = new Locale(lang);
      Locale.setDefault(locale);
      config.locale = locale;
      getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
}
Samuels answered 22/7, 2016 at 16:32 Comment(1)
Why does this code go? It doesn't go in the subclass of Application.Otranto
M
5

The way we have done it was using Broadcasts:

  1. Send the broadcast every time the user changes language
  2. Register the broadcast receiver in the AppActivity.onCreate() and unregister in AppActivity.onDestroy()
  3. In BroadcastReceiver.onReceive() just restart the activity.

AppActivity is the parent activity which all other activities subclass.


Below is the snippet from my code, not tested outside the project, but should give you a nice idea.

When the user changes the language

sendBroadcast(new Intent("Language.changed"));

And in the parent activity

public class AppActivity extends Activity {

    /**
     * The receiver that will handle the change of the language.
     */
    private BroadcastReceiver mLangaugeChangedReceiver;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...
        // Other code here
        // ...

        // Define receiver
        mLangaugeChangedReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(final Context context, final Intent intent) {
                startActivity(getIntent());
                finish();
            }
        };

        // Register receiver
        registerReceiver(mLangaugeChangedReceiver, new IntentFilter("Language.changed"));
    }

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

        // ...
        // Other cleanup code here
        // ...

        // Unregister receiver
        if (mLangaugeChangedReceiver != null) {
            try {
                unregisterReceiver(mLangaugeChangedReceiver);
                mLangaugeChangedReceiver = null;
            } catch (final Exception e) {}
        }
    }
}

This will also refresh the activity which changed the language (if it subclasses the above activity).

This will make you lose any data, but if it is important you should already have taken care of this using Actvity.onSaveInstanceState() and Actvity.onRestoreInstanceState() (or similar).

Let me know your thoughts about this.

Cheers!

Mchail answered 7/4, 2015 at 10:8 Comment(1)
What is the reference of the sendBroadcast method ?Cannikin
H
4

Step by Step Approach Complete Approach which will work on all API level device.

Using this apporach, It will work without Recreating the existing Activity on screen

  1. Use Base Activity for attachBaseContext to set the locale language and extend this activity for all activities

    open class  BaseAppCompactActivity() : AppCompatActivity() {
      override fun attachBaseContext(newBase: Context) {
          super.attachBaseContext(LocaleHelper.onAttach(newBase))    
      }
    }
    
  2. Use Application attachBaseContext and onConfigurationChanged to set the locale language

    public class MyApplication extends Application {
    
      /**
       * overide to change local sothat language can be chnaged from android device  nogaut and above
       */
      @Override
      protected void attachBaseContext(Context base) {
          super.attachBaseContext(LocaleHelper.INSTANCE.onAttach(base));
      }
    
      @Override
      public void onConfigurationChanged(Configuration newConfig) {
          setLanguageFromNewConfig(newConfig);
          super.onConfigurationChanged(newConfig);
      }
    
      /*** also handle chnage  language if  device language chnaged **/
      private void setLanguageFromNewConfig(Configuration newConfig){
          Prefs.putSaveLocaleLanguage(this,  selectedLocaleLanguage );
          LocaleHelper.INSTANCE.onAttach(this);
      }
    }
    
  3. Use Locale Helper for handling language changes, this approach work on all device

    object LocaleHelper {
      private var defaultLanguage  :String = KycUtility.KYC_LANGUAGE.ENGLISH.languageCode
    
      fun onAttach(context: Context, defaultLanguage: String): Context {
          return setLocale(context, defaultLanguage)
      }
    
    
    
      fun setLocale(context: Context, language: String): Context {
          return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
              updateResources(context, language)
          } else updateResourcesLegacy(context, language)
    
      }
    
    
      @TargetApi(Build.VERSION_CODES.N)
      private fun updateResources(context: Context, language: String): Context {
          val locale = Locale(language)
          Locale.setDefault(locale)
          val configuration = context.getResources().getConfiguration()
          configuration.setLocale(locale)
          configuration.setLayoutDirection(locale)
          return context.createConfigurationContext(configuration)
      }
    
      private fun updateResourcesLegacy(context: Context, language: String): Context {
          val locale = Locale(language)
          Locale.setDefault(locale)
          val resources = context.getResources()
          val 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
      }
    }
    
Homogony answered 6/8, 2019 at 7:32 Comment(0)
S
2

I solved my problem with this code

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

        onConfigurationChanged(conf);
    }



    @Override
    public void onConfigurationChanged(Configuration newConfig) 
    {
        iv.setImageDrawable(getResources().getDrawable(R.drawable.keyboard));
        greet.setText(R.string.greet);
        textView1.setText(R.string.langselection);

        super.onConfigurationChanged(newConfig);

    }
Savoury answered 19/3, 2014 at 12:8 Comment(1)
When I press back button, the previous activity does not change its localeAbshire
E
2

Call this method to change app locale:

public void settingLocale(Context context, String language) {

    Locale locale;

    Configuration config = new Configuration();

     if(language.equals(LANGUAGE_ENGLISH)) {

        locale = new Locale("en");

        Locale.setDefault(locale);

        config.locale = locale;

    }else if(language.equals(LANGUAGE_ARABIC)){

        locale = new Locale("hi");

        Locale.setDefault(locale);

        config.locale = locale;

    }

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

    // Here again set the text on view to reflect locale change

    // and it will pick resource from new locale

    tv1.setText(R.string.one); //tv1 is textview in my activity

}

Note: Put your strings in value and values- folder.

Ecclesiasticism answered 3/6, 2015 at 9:5 Comment(0)
I
-1

//for Kotlin->

fun setLang(languageCode: String){ AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(languageCode)) }

Inexperienced answered 8/12, 2023 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.