14

We have an Android app that functions as a client for a remote PC program. We'd like to add a feature so the PC can instruct the Android app to change its locale at runtime, i.e., start the app; put it in communication with the PC; sometime later the PC tells the app to switch to, say, Spanish or Chinese.

We already have all the layout and string resources set up for their respective locales. Our app is the only app the user sees so it doesn't matter if the rest of the device stays in English.

There is another thread on this at Change language programmatically in Android but it doesn't seem to reach a conclusion.

I can put . . .

Locale locale = new Locale(sTheNewLocale);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
      getBaseContext().getResources().getDisplayMetrics());

. . . in onCreate() before the setContentView() but that doesn't really help if I want to change the locale after my screen is up and running. Is there a way to REload the content view after the Activity is already running? So is there any practical way to change locales on-the-fly reliably or do I have to tell my boss it can't be done except for setting the whole device to the new locale before starting the app?

Community
  • 1
  • 1
user316117
  • 7,971
  • 20
  • 83
  • 158

4 Answers4

18

Since API 11 you can use recreate so can make this method in your activity:

private void restartInLocale(Locale locale)
{
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    Resources resources = getResources();
    resources.updateConfiguration(config, resources.getDisplayMetrics());
    recreate();
}
weston
  • 54,145
  • 21
  • 145
  • 203
3

You can start a new instance of your activity and exit the old one. Here is a full (untested) example how you can store any desired language and restart your app. You just need to call restartInLanguage with your prefered language.

public class YourMainActivity extends Activity {
    private static final String APP_SHARED_PREFS = "com.example.test";
    private SharedPreferences settings;
    private Editor editor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        settings=getSharedPreferences(APP_SHARED_PREFS, Activity.MODE_PRIVATE);
        editor=settings.edit();

        Locale locale = new Locale(settings.getString("lang", "default-lang"));
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.locale = locale;
        getResources().updateConfiguration(config, getResources().getDisplayMetrics());

        // your stuff...
    }

    public void restartInLanguage(String lang) {
        editor.putString("lang", lang);
        editor.commit();
        Intent intent = getIntent();
        finish();
        startActivity(intent);
    }

    // ...
}
rekire
  • 47,260
  • 30
  • 167
  • 264
  • Where would I do this from? The program starts in the main activity so how would this change the locale of the main screen? Or do you mean to start a new instance of the Main activity from the Main activity and then have the old Main activity kill itself? (can that even be done?) – user316117 Nov 01 '12 at 17:55
  • Yes so it is... You put that code above in the *language changed handler* which restarts your main activity. – rekire Nov 01 '12 at 20:24
  • I still can't parse your answer. Are you saying I can restart my main activity *from* my main activity? How do I do that? – user316117 Nov 05 '12 at 15:52
  • Try the added example hope that will help you. – rekire Nov 05 '12 at 19:22
1

I have combined @weston and @rekire (both +1) and extendet it to handle this use-case:

  • ActivityA => ActivityB => SettingsActivity-changeLocale

After changeLocale in SettingsActivity the parent activities ActivityA and ActivityB should also be recreated to reflect the new locale.

My solution: ActivityA and ActivityB inherit from LocalizedActivity which checks in onResume if the locale has changed and trigger a recreate() if necessary

So every activity that inherits from LocalizedActivity automatically handles app specific locale change.

/**
 * An activity that can change the locale (language) of its content.
 *
 * Inspired by http://stackoverflow.com/questions/13181847/change-the-locale-at-runtime
 *
 * Created by k3b on 07.01.2016.
 */
public class LocalizedActivity extends Activity {
    /** if myLocale != Locale.Default : activity must be recreated in on resume */
    private Locale myLocale = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        fixLocale(this);
        super.onCreate(savedInstanceState);
    }

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

        // Locale has changed by other Activity ?
        if ((myLocale != null) && (myLocale.getLanguage() != Locale.getDefault().getLanguage())) {
            myLocale = null;
            recreate();
        }
    }

    /**
     * Set Activity-s locale to SharedPreferences-setting.
     * Must be called before onCreate
     * @param context
     */
    public static void fixLocale(Context context)
    {
        final SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(context);
        String language = prefs.getString(Global.PREF_KEY_USER_LOCALE, "");
        Locale locale = Global.systemLocale; // in case that setting=="use android-locale"
        if ((language != null) && (!language.isEmpty())) {
            locale = new Locale(language); // overwrite "use android-locale"
        }

        if (locale != null) {
            Locale.setDefault(locale);
            Configuration config = new Configuration();
            config.locale = locale;
            Resources resources = context.getResources();
            resources.updateConfiguration(config, resources.getDisplayMetrics());
            // recreate();

            if (context instanceof LocalizedActivity) {
                ((LocalizedActivity) context).myLocale = locale;
            }
        }
    }
}

Here is the source of LocalizedActivity.java and SettingsActivity.java that are used in my A Photo Manager project

k3b
  • 14,517
  • 7
  • 53
  • 85
0

The solution is to use setContentView and controlLanguage (you can also call this method from a Global class) methods in EVERY activity in onResume method after setting your locale. Example:

@Override
    public void onClick(View v) {
        SharedPreferences.Editor editor;
        editor = sharedPref.edit();
        Configuration config = new Configuration(getBaseContext().getResources().getConfiguration());
        String language = "";
        switch (v.getId()){
            case R.id.turkceButton:
                editor.putString("language", "tr");
                language="tr";
                break;
            case R.id.englishButton:
                editor.putString("language", "en");
                language="en";
                break;
        }
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
        config.locale = locale;
        getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
        editor.commit();


@Override
    protected void onResume() {
        super.onResume();
        controlLanguage(getApplicationContext(), getResources());
        setContentView(R.layout.main);
    }

public void controlLanguage(Context context, Resources res){
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
        String language = sharedPref.getString("language","en");
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
        res.getConfiguration().locale = locale;
        res.updateConfiguration(res.getConfiguration(), res.getDisplayMetrics());
    }