Change language programmatically (Android N 7.0 - API 24)

谁说胖子不能爱 提交于 2019-12-03 18:45:55

问题


I'm using the following code to set specific language in my app. Language is saved into SharedPreferences within the app. And it works perfectly up to API level 23. With Android N SharedPreferences works well too, it returns the correct language code-string, but it does not change the locale (sets default language of the phone). What could be wrong?

Update 1: When I use Log.v("MyLog", config.locale.toString()); immediately after res.updateConfiguration(config, dm) it returns correct locale, but language of the app does not changed.

Update 2: I also mentioned that if I change locale and then restart the activity (using new intent and finish on the old one), it changes the language properly, it even shows correct language after rotation. But when I close the app and open it again, I get default language. It's weird.

public class ActivityMain extends AppCompatActivity {

    //...
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        // Set locale
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
        String lang = pref.getString(ActivityMain.LANGUAGE_SAVED, "no_language");
        if (!lang.equals("no_language")) {
            Resources res = context.getResources();
            Locale locale = new Locale(lang);
            Locale.setDefault(locale);
            DisplayMetrics dm = res.getDisplayMetrics();
            Configuration config = res.getConfiguration();
            if (Build.VERSION.SDK_INT >= 17) {
                config.setLocale(locale);
            } else {
                config.locale = locale;
            }
        }
        res.updateConfiguration(config, dm);

        setContentView(R.layout.activity_main);
        //...
    } 
    //... 
}

Update 3: THE ANSWER IS ALSO HERE: https://stackoverflow.com/a/40849142/3935063


回答1:


Create a new class extends ContextWrapper

public class MyContextWrapper extends ContextWrapper {
    public MyContextWrapper(Context base) {
        super(base);
    }

    @TargetApi(Build.VERSION_CODES.N)
    public static ContextWrapper wrap(Context context, Locale newLocale) {
        Resources res = context.getResources();
        Configuration configuration = res.getConfiguration();

        if (VersionUtils.isAfter24()) {
            configuration.setLocale(newLocale);

            LocaleList localeList = new LocaleList(newLocale);
            LocaleList.setDefault(localeList);
            configuration.setLocales(localeList);

            context = context.createConfigurationContext(configuration);

        } else if (VersionUtils.isAfter17()) {
            configuration.setLocale(newLocale);
            context = context.createConfigurationContext(configuration);

        } else {
            configuration.locale = newLocale;
            res.updateConfiguration(configuration, res.getDisplayMetrics());
        }

        return new ContextWrapper(context);
    }
}

override Activity's attachBaseContext method

@Override
protected void attachBaseContext(Context newBase) {
    Locale languageType = LanguageUtil.getLanguageType(mContext);
    super.attachBaseContext(MyContextWrapper.wrap(newBase, languageType));
}

finish the activity and start it again,new locale will become effective.

demo:https://github.com/fanturbo/MultiLanguageDemo




回答2:


 This approach will work on all api level device, Make sure to recreate activity on changing language programatically.

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

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

}



2. Use Application attachBaseContext and onConfigurationChanged to set the locale language

 public class MyApplication extends Application {
private static MyApplication application;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    public static MyApplication getApplication() {
        return 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) {

/*** also handle chnage language if device language chnaged **/

        super.onConfigurationChanged(newConfig);

    }



3. Use Locale Helper  for handling language changes ,this approch work on all device 

object LocaleHelper {


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


来源:https://stackoverflow.com/questions/38997356/change-language-programmatically-android-n-7-0-api-24

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!