Changing Locale within the app itself

前端 未结 6 1827
遇见更好的自我
遇见更好的自我 2020-11-22 01:31

My users can change the Locale within the app (they may want to keep their phone settings in English but read the content of my app in French, Dutch or any other language ..

相关标签:
6条回答
  • 2020-11-22 01:33

    This is for my comment on Andrey's answer but I cant include code in the comments.

    Is you preference activity being called from you main activity? you could place this in the on resume...

    @Override
    protected void onResume() {
        if (!(PreferenceManager.getDefaultSharedPreferences(
                getApplicationContext()).getString("listLanguage", "en")
                .equals(langPreference))) {
            refresh();
        }
        super.onResume();
    }
    
    private void refresh() {
        finish();
        Intent myIntent = new Intent(Main.this, Main.class);
        startActivity(myIntent);
    }
    
    0 讨论(0)
  • 2020-11-22 01:42

    If you want to effect on the menu options for changing the locale immediately.You have to do like this.

    //onCreate method calls only once when menu is called first time.
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        //1.Here you can add your  locale settings . 
        //2.Your menu declaration.
    }
    //This method is called when your menu is opend to again....
    @Override
    public boolean onMenuOpened(int featureId, Menu menu) {
        menu.clear();
        onCreateOptionsMenu(menu);
        return super.onMenuOpened(featureId, menu);
    }
    
    0 讨论(0)
  • In Android M the top solution won't work. I've written a helper class to fix that which you should call from your Application class and all Activities (I would suggest creating a BaseActivity and then make all the Activities inherit from it.

    Note: This will also support properly RTL layout direction.

    Helper class:

    public class LocaleUtils {
    
        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);
                // We must use the now-deprecated config.locale and res.updateConfiguration here,
                // because the replacements aren't available till API level 24 and 17 respectively.
                config.locale = sLocale;
                Resources res = app.getBaseContext().getResources();
                res.updateConfiguration(config, res.getDisplayMetrics());
            }
        }
    }
    

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

    BaseActivity:

    public class BaseActivity extends Activity {
        public BaseActivity() {
            LocaleUtils.updateConfig(this);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:51

    Through the original question is not exactly about the locale itself all other locale related questions are referencing to this one. That's why I wanted to clarify the issue here. I used this question as a starting point for my own locale switching code and found out that the method is not exactly correct. It works, but only until any configuration change (e.g. screen rotation) and only in that particular Activity. Playing with a code for a while I have ended up with the following approach:

    I have extended android.app.Application and added the following code:

    public class MyApplication extends Application
    {
        private Locale locale = null;
    
        @Override
        public void onConfigurationChanged(Configuration newConfig)
        {
            super.onConfigurationChanged(newConfig);
            if (locale != null)
            {
                newConfig.locale = locale;
                Locale.setDefault(locale);
                getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
            }
        }
    
        @Override
        public void onCreate()
        {
            super.onCreate();
    
            SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
    
            Configuration config = getBaseContext().getResources().getConfiguration();
    
            String lang = settings.getString(getString(R.string.pref_locale), "");
            if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang))
            {
                locale = new Locale(lang);
                Locale.setDefault(locale);
                config.locale = locale;
                getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
            }
        }
    }
    

    This code ensures that every Activity will have custom locale set and it will not be reset on rotation and other events.

    I have also spent a lot of time trying to make the preference change to be applied immediately but didn't succeed: the language changed correctly on Activity restart, but number formats and other locale properties were not applied until full application restart.

    Changes to AndroidManifest.xml

    Don't forget to add android:configChanges="layoutDirection|locale" to every activity at AndroidManifest, as well as the android:name=".MyApplication" to the <application> element.

    0 讨论(0)
  • 2020-11-22 01:52

    I couldn't used android:anyDensity="true" because objects in my game would be positioned completely different... seems this also does the trick:

    // creating locale
    Locale locale2 = new Locale(loc); 
    Locale.setDefault(locale2);
    Configuration config2 = new Configuration();
    config2.locale = locale2;
    
    // updating locale
    mContext.getResources().updateConfiguration(config2, null);
    
    0 讨论(0)
  • 2020-11-22 01:57

    After a good night of sleep, I found the answer on the Web (a simple Google search on the following line "getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());"), here it is :

    link text => this link also shows screenshots of what is happening !

    Density was the issue here, I needed to have this in the AndroidManifest.xml

    <supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="true"
    android:anyDensity="true"
    />
    

    The most important is the android:anyDensity =" true ".

    Don't forget to add the following in the AndroidManifest.xml for every activity (for Android 4.1 and below):

    android:configChanges="locale"
    

    This version is needed when you build for Android 4.2 (API level 17) explanation here:

    android:configChanges="locale|layoutDirection"
    
    0 讨论(0)
提交回复
热议问题