我的应用程序支持3种(即将出现4种)语言。由于几种语言环境非常相似,因此我想为用户提供在我的应用程序中更改语言环境的选项,例如,意大利人可能更喜欢西班牙语而不是英语。

用户是否有办法在可用于该应用程序的语言环境中进行选择,然后更改使用的语言环境?我认为为每个Activity设置区域设置不是问题,因为这是在基类中执行的简单任务。

评论

如果您需要稍后恢复默认语言环境的方法,或者需要包含语言列表的语言首选项,并且想要更方便地更改语言环境,这可能会有所帮助:github.com/delight-im/Android -语言

#1 楼

对于仍在寻找此答案的人们,由于API 43不推荐使用configuration.locale,因此您现在可以使用:

configuration.setLocale(locale);


考虑到此方法的minSkdVersion是API 17 。

完整的示例代码:

@SuppressWarnings("deprecation")
private void setLocale(Locale locale){
    SharedPrefUtils.saveLocale(locale); // optional - Helper method to save the selected language to SharedPreferences in case you might need to attach to activity context (you will need to code this)
    Resources resources = getResources();
    Configuration configuration = resources.getConfiguration();
    DisplayMetrics displayMetrics = resources.getDisplayMetrics();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
        configuration.setLocale(locale);
    } else{
        configuration.locale=locale;
    }
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N){
        getApplicationContext().createConfigurationContext(configuration);
    } else {
        resources.updateConfiguration(configuration,displayMetrics);
    }
}


不要忘记,如果您通过运行Activity来更改语言环境,则需要重新启动它以使更改生效。

编辑2018年5月11日

从@CookieMonster的帖子开始,您可能在将语言环境更改保留在更高版本的API中时遇到问题。如果是这样,请将以下代码添加到您的基本活动中,以便在每次创建活动时都更新上下文区域设置:

@Override
protected void attachBaseContext(Context base) {
     super.attachBaseContext(updateBaseContextLocale(base));
}

private Context updateBaseContextLocale(Context context) {
    String language = SharedPrefUtils.getSavedLanguage(); // Helper method to get saved language from SharedPreferences
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
        return updateResourcesLocale(context, locale);
    }

    return updateResourcesLocaleLegacy(context, locale);
}

@TargetApi(Build.VERSION_CODES.N_MR1)
private Context updateResourcesLocale(Context context, Locale locale) {
    Configuration configuration = new Configuration(context.getResources().getConfiguration())
    configuration.setLocale(locale);
    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private Context updateResourcesLocaleLegacy(Context context, Locale locale) {
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    return context;
}


如果使用此代码,请不要忘记使用setLocate(locale)设置语言环境时,将语言保存为SharedPreferences

编辑2020年4月7日

您可能在Android 6和7中遇到问题,并且由于问题而发生在androidx库中处理夜间模式时。为此,您还需要在基本活动中覆盖applyOverrideConfiguration并更新配置的语言环境,以防创建新的新语言环境。

示例代码:

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
        // update overrideConfiguration with your locale  
        setLocale(overrideConfiguration) // you will need to implement this
    }
    super.applyOverrideConfiguration(overrideConfiguration);
} 


评论


这适用于活动,但是有没有办法更新应用程序上下文?

– alekop
18年6月11日在23:45



将androidx.appcompat:appcompat:版本从1.0.2更改为1.1.0后,不适用于android 7,但适用于android 9。

–贝克
19年9月11日4:24在

对我和1.1.0 androidx来说,同样的问题

–亚历山大·达杜金(Alexander Dadukin)
19年11月25日在15:20

对我来说同样的问题。在我更改为androidx.appcompat:appcompat:1.1.0'后

–拉胡尔·吉奇(Rahul Jidge)
19/12/9在10:37

appcompat:1.1.0的问题可以通过appcompat:1.2.0-alpha02和代码Set set = new LinkedHashSet <>();来解决。 //将目标语言环境置于列表的最前面set.add(locale); LocaleList全部= LocaleList.getDefault(); for(int i = 0; i
–Vojtech Pohl
1月29日22:35



#2 楼

希望此帮助(在onResume中):

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


评论


因此,必须为每个活动设置此设置吗?

– Tobias
2012年3月30日19:50

1.必须使用getBaseContext()还是最好使用应用程序contex? 2.在每个活动中应调用此代码吗?谢谢。

– Paul
2012年6月13日12:47

我将此代码放入启动器Activity的onCreate()中(并且无其他地方),并惊讶地发现该语言环境适用于整个应用程序。这是在定位为4.3且minSDK为14(ICS)的应用程序中。

–IAmKale
13年8月2日在16:30

无需创建新的Configuration对象。您可以使用当前配置并对其进行更新:getResources()。getConfiguration()

– jmart
15年8月5日在17:13

不要使用新的Configuration();,它会更改textAppearance,fontSize

–杰西特·伊斯肯德诺夫(Jemshit Iskenderov)
16年8月12日在9:43

#3 楼

我在使用Android OS N及更高版本的设备
以编程方式设置区域设置时遇到问题。
对我来说,解决方案是在我的基本活动中编写以下代码:

(如果您没有基本活动,则应在所有活动中进行这些更改)。

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(updateBaseContextLocale(base));
}

private Context updateBaseContextLocale(Context context) {
    String language = SharedPref.getInstance().getSavedLanguage();
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResourcesLocale(context, locale);
    }

    return updateResourcesLocaleLegacy(context, locale);
}

@TargetApi(Build.VERSION_CODES.N)
private Context updateResourcesLocale(Context context, Locale locale) {
    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private Context updateResourcesLocaleLegacy(Context context, Locale locale) {
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    return context;
}


请注意,在这里仅调用

createConfigurationContext(configuration)


还需要获取此方法返回的上下文,然后在attachBaseContext方法中设置此上下文。

评论


这是最简单且可行的解决方案!这应该是公认的答案。

– Prasad Pawar
18年5月8日在15:01

此代码在高于7的android上非常有效,但在低于N的版本中不起作用。你有什么解决方案?

–马丁阿什蒂亚尼
18年5月29日在13:56

不确定,因为它对我有用。您是否想将实施情况发送给我,以便让我看看?

–CookieMonster
18年5月31日在6:07



在Android N下的版本中不起作用,因为必须在onCreate()而不是attachBaseContext()中调用resources.updateConfiguration

–钱德勒
19-10-29在1:56

@钱德勒是正确的。对于Android 6-,请在您的父/基本活动的onCreate中调用updateBaseContextLocale方法。

–阿齐琼·霍尔马托夫(Azizjon Kholmatov)
2月28日16:00

#4 楼

由于当前解决此问题的方法尚无答案,因此,我尝试给出完整解决方案的说明。如果缺少某些内容或可以做得更好,请发表评论。

一般信息

首先,存在一些想要解决该问题的库,但它们似乎都已过时或丢失一些功能:



https://github.com/delight-im/Android-Languages


过时(请参阅问题)
在用户界面中选择一种语言时,它始终显示所有语言(在库中进行了硬编码),不仅显示存在翻译的那些语言



https:/ /github.com/akexorcist/Android-LocalizationActivity


似乎很复杂,可能会使用如下所示的类似方法



此外,我认为编写库可能不是解决此问题的好/容易方法,因为要做的事情不多,而且要做的是更改现有代码而不是使用完全脱钩的方法。
因此,我组成了以下应完整的说明。

我的解决方案是主要基于https://github.com/gunhansancar/ChangeLanguageExample(已由localhost链接)。这是我发现的最佳代码。一些说明:


必要时,它提供了不同的实现来更改Android N(及更高版本)及以下版本的语言环境
它在每个Activity中使用方法updateViews()手动更新所有更改语言环境后的字符串(使用通常的getString(id)),在下面显示的方法中是不必要的
。它仅支持语言,不支持完整的语言环境(还包括区域(国家/地区)和变体代码)

我进行了一些更改,将保留所选语言环境的部分解耦(因为可能要单独这样做,如下所示)。

解决方案

解决方案包括以下两个步骤之一:


永久更改应用程序要使用的语言环境
使应用程序使用自定义语言环境集,而无需重新启动

步骤1:更改语言环境

使用该类LocaleHelper,基于gunhansancar的LocaleHelper:


ListPreference中添加带有可用语言的PreferenceFragment(以后应添加语言时必须保留)

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;

import java.util.Locale;

import mypackage.SettingsFragment;

/**
 * Manages setting of the app's locale.
 */
public class LocaleHelper {

    public static Context onAttach(Context context) {
        String locale = getPersistedLocale(context);
        return setLocale(context, locale);
    }

    public static String getPersistedLocale(Context context) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SettingsFragment.KEY_PREF_LANGUAGE, "");
    }

    /**
     * Set the app's locale to the one specified by the given String.
     *
     * @param context
     * @param localeSpec a locale specification as used for Android resources (NOTE: does not
     *                   support country and variant codes so far); the special string "system" sets
     *                   the locale to the locale specified in system settings
     * @return
     */
    public static Context setLocale(Context context, String localeSpec) {
        Locale locale;
        if (localeSpec.equals("system")) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                locale = Resources.getSystem().getConfiguration().getLocales().get(0);
            } else {
                //noinspection deprecation
                locale = Resources.getSystem().getConfiguration().locale;
            }
        } else {
            locale = new Locale(localeSpec);
        }
        Locale.setDefault(locale);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, locale);
        } else {
            return updateResourcesLegacy(context, locale);
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, Locale locale) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);

        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, Locale locale) {
        Resources resources = context.getResources();

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


创建一个如下所示的SettingsFragment

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import mypackage.LocaleHelper;
import mypackage.R;

/**
 * Fragment containing the app's main settings.
 */
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_LANGUAGE = "pref_key_language";

    public SettingsFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_settings, container, false);
        return view;
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        switch (key) {
            case KEY_PREF_LANGUAGE:
                LocaleHelper.setLocale(getContext(), PreferenceManager.getDefaultSharedPreferences(getContext()).getString(key, ""));
                getActivity().recreate(); // necessary here because this Activity is currently running and thus a recreate() in onResume() would be too late
                break;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        // documentation requires that a reference to the listener is kept as long as it may be called, which is the case as it can only be called from this Fragment
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }
}


创建资源locales.xml列出所有具有可用翻译的语言环境,其方式如下:代码):

<!-- Lists available locales used for setting the locale manually.
     For now only language codes (locale codes without country and variant) are supported.
     Has to be in sync with "settings_language_values" in strings.xml (the entries must correspond).
  -->
<resources>
    <string name="system_locale" translatable="false">system</string>
    <string name="default_locale" translatable="false"></string>
    <string-array name="locales">
        <item>@string/system_locale</item> <!-- system setting -->
        <item>@string/default_locale</item> <!-- default locale -->
        <item>de</item>
    </string-array>
</resources>


在您的PreferenceScreen中,您可以使用以下部分让用户选择可用的语言:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
        android:title="@string/preferences_category_general">
        <ListPreference
            android:key="pref_key_language"
            android:title="@string/preferences_language"
            android:dialogTitle="@string/preferences_language"
            android:entries="@array/settings_language_values"
            android:entryValues="@array/locales"
            android:defaultValue="@string/system_locale"
            android:summary="%s">
        </ListPreference>
    </PreferenceCategory>
</PreferenceScreen>


,它使用来自strings.xml的以下字符串:

<string name="preferences_category_general">General</string>
<string name="preferences_language">Language</string>
<!-- NOTE: Has to correspond to array "locales" in locales.xml (elements in same orderwith) -->
<string-array name="settings_language_values">
    <item>Default (System setting)</item>
    <item>English</item>
    <item>German</item>
</string-array>


步骤2:使应用使用自定义语言环境

现在设置每个活动以使用自定义语言环境集。最简单的方法是使用以下代码(其中重要的代码在attachBaseContext(Context base)onResume()中)为所有活动提供通用基类:

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import mypackage.LocaleHelper;
import mypackage.R;

/**
 * {@link AppCompatActivity} with main menu in the action bar. Automatically recreates
 * the activity when the locale has changed.
 */
public class MenuAppCompatActivity extends AppCompatActivity {
    private String initialLocale;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initialLocale = LocaleHelper.getPersistedLocale(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_settings:
                Intent intent = new Intent(this, SettingsActivity.class);
                startActivity(intent);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (initialLocale != null && !initialLocale.equals(LocaleHelper.getPersistedLocale(this))) {
            recreate();
        }
    }
}





重写attachBaseContext(Context base)以使用以前与LocaleHelper保持一致的语言环境

检测语言环境的变化并重新创建Activity以更新其字符串

关于此解决方案的说明



重新创建活动不会更新ActionBar的标题(如此处已观察到:https://github.com/ gunhansancar / ChangeLanguageExample / issues / 1)。


只需在每个活动的setTitle(R.string.mytitle)方法中使用onCreate()即可实现。


它使用户可以选择系统的默认语言环境以及应用程序的默认语言环境(可以命名,在本例中为“英语”)。

到目前为止,仅支持语言代码,不支持地区(国家/地区)和变体代码(例如fr-rCA)。为了支持完整的语言环境规范,可以使用类似于Android语言库中的解析器(该解析器支持区域,但不提供变体代码)。


如果有人发现或写得很好解析器,添加注释,以便可以将其包含在解决方案中。




评论


很棒,但噩梦之王

–奥德斯
18年1月9日,12:34

天哪,我的应用程序已经太复杂了,这种方法将来会成为噩梦。

–乔什
18-2-28在9:06

@Josh您能进一步解释一下吗?实际上,只需将几行添加到您使用的每个Activity基类。我看到不可能对所有活动都使用相同的基类,但是更大的项目也应该能够与之相处。面向方面的编程可以在这里有所帮助,但是组合(将代码从attachBaseContext(Context base)和onResume()移到单独的类)可以解决问题。然后,您要做的就是在每个活动基类中声明一个对象,并委派这两个调用。

–user905686
18 Mar 8 '18 at 14:02

如果用户更改了语言环境,是否也可以更改所有先前活动页面的语言环境?

– Raju yourPepe
18/09/13在5:22

这是此问题上的最佳答案。谢谢兄弟,它有效

– Alok Gupta
19年10月10日在9:12

#5 楼

@SuppressWarnings("deprecation")
public static void forceLocale(Context context, String localeCode) {
    String localeCodeLowerCase = localeCode.toLowerCase();

    Resources resources = context.getApplicationContext().getResources();
    Configuration overrideConfiguration = resources.getConfiguration();
    Locale overrideLocale = new Locale(localeCodeLowerCase);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        overrideConfiguration.setLocale(overrideLocale);
    } else {
        overrideConfiguration.locale = overrideLocale;
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        context.getApplicationContext().createConfigurationContext(overrideConfiguration);
    } else {
        resources.updateConfiguration(overrideConfiguration, null);
    }
}


只需使用此辅助方法来强制特定的语言环境。

UPDATE 2017年8月22日。
更好地使用此方法。

#6 楼

使用以下方法添加帮助器类:

public class LanguageHelper {
    public static final void setAppLocale(String language, Activity activity) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Resources resources = activity.getResources();
            Configuration configuration = resources.getConfiguration();
            configuration.setLocale(new Locale(language));
            activity.getApplicationContext().createConfigurationContext(configuration);
        } else {
            Locale locale = new Locale(language);
            Locale.setDefault(locale);
            Configuration config = activity.getResources().getConfiguration();
            config.locale = locale;
            activity.getResources().updateConfiguration(config,
                    activity.getResources().getDisplayMetrics());
        }

    }
}


并在启动活动中调用它,例如MainActivity.java

public void onCreate(Bundle savedInstanceState) {
    ...
    LanguageHelper.setAppLocale("fa", this);
    ...
}


#7 楼

对于从API16到API28的API有效,只需将此方法放在以下位置:
Context newContext = context;

Locale locale = new Locale(languageCode);
Locale.setDefault(locale);

Resources resources = context.getResources();
Configuration config = new Configuration(resources.getConfiguration());

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    config.setLocale(locale);
    newContext = context.createConfigurationContext(config);
} else {
    config.locale = locale;
    resources.updateConfiguration(config, resources.getDisplayMetrics());
}

return newContext;

使用以下代码在所有活动中插入此代码:
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(localeUpdateResources(base, "<-- language code -->"));
    }

,或在片段,适配器上调用localeUpdateResources等需要新上下文的地方。
信用:Yaroslav Berezanskyi

#8 楼

简单易行

Locale locale = new Locale("en", "US");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = locale;
res.updateConfiguration(conf, dm);


其中“ en”是语言代码,“ US”是国家代码。

评论


如我的帖子所述conf.locale = locale;已弃用,也是updateConfiguration。

–里卡多
17 Mar 23 '17 at 13:43

非常简单,不太复杂:)

–拉姆克什·雅达夫(Ramkesh Yadav)
5月23日14:33



#9 楼

有一种超级简单的方法。

在BaseActivity,Activity或Fragment中覆盖attachBaseContext

 override fun attachBaseContext(context: Context) {
    super.attachBaseContext(context.changeLocale("tr"))
}


fun Context.changeLocale(language:String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = this.resources.configuration
    config.setLocale(locale)
    return createConfigurationContext(config)
}


#10 楼

我发现androidx.appcompat:appcompat:1.1.0错误也可以通过简单地在getResources()中调用applyOverrideConfiguration()来解决。

@Override public void
applyOverrideConfiguration(Configuration cfgOverride)
{
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
      Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    // add this to fix androidx.appcompat:appcompat 1.1.0 bug
    // which happens on Android 6.x ~ 7.x
    getResources();
  }

  super.applyOverrideConfiguration(cfgOverride);
}


#11 楼

 /**
 * Requests the system to update the list of system locales.
 * Note that the system looks halted for a while during the Locale migration,
 * so the caller need to take care of it.
 */
public static void updateLocales(LocaleList locales) {
    try {
        final IActivityManager am = ActivityManager.getService();
        final Configuration config = am.getConfiguration();

        config.setLocales(locales);
        config.userSetLocale = true;

        am.updatePersistentConfiguration(config);
    } catch (RemoteException e) {
        // Intentionally left blank
    }
}


#12 楼

对于那些尝试了所有但都无法正常工作的人。请检查是否将darkmode设置为AppCompatDelegate.setDefaultNightMode,并且系统不是黑暗的,则Configuration.setLocale将无法在Andorid 7.0之上运行。

在您的每个活动中添加此代码以解决此问题:

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
  if (overrideConfiguration != null) {
    val uiMode = overrideConfiguration.uiMode
    overrideConfiguration.setTo(baseContext.resources.configuration)
    overrideConfiguration.uiMode = uiMode
  }
  super.applyOverrideConfiguration(overrideConfiguration)
}


#13 楼

截至2020年,语言管理变得轻而易举!您所需要做的就是:

调用Activity.applyOverrideConfiguration

并调用Locale.setDefault


您必须从活动构造函数中调用它们由于您只能调用一次applyOverrideConfiguration,而且系统会很早调用它。
并注意应用程序捆绑包,因此当使用应用程序捆绑包时,Google会自动按语言资源拆分APK。在此处查看新的API和解决方法。

我创建了一个帮助器类来帮助您。在我的实现中,G.app是应用程序上下文。另外,我需要从应用程序上下文访问资源,因此我使用Res类,该类是可选的,但我也提供了它的代码。
用法
public BaseActivity(){
    LanguageUtility.init(this);
}

public void changeLanguage(Local local){
    // you must recreat your activity after you call this
    LanguageUtillity.setDefaultLanguage(local, this);
}

源代码
public class LanguageUtility {

    private static Configuration configuration;

    public static void setDefaultLanguage(Locale locale, Context context) {
        Locale.setDefault(locale);

        context.getSharedPreferences("LocaleSettings", Context.MODE_PRIVATE)
                .edit()
                .putString("language", locale.getLanguage())
                .putString("country", locale.getCountry())
                .putString("variant", locale.getVariant())
                .apply();

        configuration = createConfiguration(context);
        Res.updateContext();
    }

    /**
     * Used to update your app context in case you cache it.
     */
    public static Context createConfigurationContext(Context context) {
        return context.createConfigurationContext(getConfiguration(context));
    }

    public static void init(Activity activity) {
        activity.applyOverrideConfiguration(LanguageUtility.getConfiguration(G.app));
        // you can't access sharedPrefferences from activity constructor 
        // with activity context, so I used the app context.
        Locale.setDefault(getLocale(G.app));
    }

    @NotNull
    private static Configuration getConfiguration(Context context) {
        if (configuration == null) {
            configuration = createConfiguration(context);
        }
        return configuration;
    }

    @NotNull
    private static Configuration createConfiguration(Context context) {
        Locale locale = getLocale(context);
        Configuration configuration = new Configuration();
        configuration.setLocale(locale);
        LanguageUtility.configuration = configuration;
        return configuration;
    }

    @NotNull
    private static Locale getLocale(Context context) {
        Locale aDefault = Locale.getDefault();
        SharedPreferences preferences =
                context.getSharedPreferences("LocaleSettings", Context.MODE_PRIVATE);
        String language = preferences.getString("language", aDefault.getLanguage());
        String country = preferences.getString("country", aDefault.getCountry());
        String variant = preferences.getString("variant", aDefault.getVariant());
        return new Locale(language, country, variant);
    }
}

可选的Res类。
public class Res {

    @SuppressLint("StaticFieldLeak")
    public static Context appLocalContext = LanguageUtility.createConfigurationContext(G.app);

    public static void updateContext() {
        appLocalContext = LanguageUtility.createConfigurationContext(G.app);
    }

    public static String getString(@StringRes int id, Object... formatArgs) {
        return appLocalContext.getResources().getString(id, formatArgs);
    }

    public static int getColor(@ColorRes int id) {
        return G.app.getColor(id);
    }
}


#14 楼

在BaseActivity-> onCreate()和BaseFragment-> OnCreateView()上调用此方法
在API 22、23、24、25、26、27、28、29上进行了测试...最新版本
fun Context.updateLang() {
    val resources = resources
    val config = Configuration(resources.configuration)
    config.setLocale(PreferenceManager(this).getAppLanguage()) // language from preference
    val dm = resources.displayMetrics
    createConfigurationContext(config)
    resources.updateConfiguration(config, dm)
}


#15 楼

将此代码放在您的活动中

 if (id==R.id.uz)
    {
        LocaleHelper.setLocale(MainActivity.this, mLanguageCode);

        //It is required to recreate the activity to reflect the change in UI.
        recreate();
        return true;
    }
    if (id == R.id.ru) {

        LocaleHelper.setLocale(MainActivity.this, mLanguageCode);

        //It is required to recreate the activity to reflect the change in UI.
        recreate();
    }