在Android中编程实现应用程序语言的更改

572

在仍然使用Android资源的情况下,是否可能通过编程方式更改应用程序的语言?

如果不行,是否可能以特定语言请求资源?

我希望允许用户从应用程序中更改应用程序的语言。


4
您可以使用以下库,它提供语言列表、设置屏幕的偏好以及覆盖应用程序中的语言:https://github.com/delight-im/Android-Languages。 - caw
1
@neu242 是的,它在Android 5.0上运行没有任何问题。 - caw
我已经在另一个帖子中回答了这个问题,请在这里查看: https://dev59.com/MY3da4cB1Zd3GeqP7Pkf#33079919 - Sindri Þór
2
您可以使用以下库:https://github.com/zeugma-solutions/locale-helper-android - josue.0
1
@josue.0,这个库确实是解决这个问题最干净的方案。 - amitavk
显示剩余4条评论
35个回答

459

是可以做到的。您可以设置区域设置。然而,我不建议这样做。我们早期尝试过,基本上这是在与系统作斗争。

我们有更改语言的相同要求,但决定接受UI应该与手机UI相同的事实。通过设置区域设置可以工作,但存在太多错误。并且从我的经验来看,您必须每次进入活动(每个活动)时设置它。如果您仍需要此代码,则以下是代码(再次强调,我不建议这样做)

Resources res = context.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.setLocale(new Locale(language_code.toLowerCase())); // API 17+ only.
// Use conf.locale = new Locale(...) if targeting lower versions
res.updateConfiguration(conf, dm);

如果您有特定语言的内容,可以根据设置进行更改。


2020年3月26日更新

    public static void setLocale(Activity activity, String languageCode) {
        Locale locale = new Locale(languageCode);
        Locale.setDefault(locale);
        Resources resources = activity.getResources();
        Configuration config = resources.getConfiguration();
        config.setLocale(locale);
        resources.updateConfiguration(config, resources.getDisplayMetrics());
    }
  • 注意:语言代码不能包含'-',且必须为两个小写字母。

481
Android让这件事情变得如此困难,真令人难以置信。我并不真正明白为什么手机的语言环境和应用程序之间应该有严格的关联。虽然我不是以英语为母语的人,但我总是将手机设置为英语语言。原因是翻译后的半技术性单词在我的母语中听起来很奇怪,而英语则更加容易理解。这也使我更容易遵循网上的建议。但这并不意味着我希望手机上的每个应用程序都使用英语(虽然默认设置是完全可以接受的)。我希望能够进行选择!!! - peterh
15
看起来API级别17引入了Context.createConfigurationContext(),它可以用于使用特定于语言环境的配置包装默认上下文,然后在不必更新资源对象本身的配置的情况下在其上调用getResources - JAB
14
否则可能会被系统覆盖,例如当您将设备转向横向并重新创建具有新(由系统提供的)配置的活动时。因此您需要将此代码放入每个活动的 onCreate() 方法中。 - Zsolt Safrany
19
如果您设置了RTL语言环境,例如“ar”,并希望您的-ldrtl资源文件夹也能正常工作,则还需要调用conf.setLayoutDirection(locale)。 - Zsolt Safrany
6
与其添加一个调用conf.setLayoutDirection(locale)的语句,你可以将conf.locale = new Locale(...)替换为conf.setLocale(new Locale(...))。它会在内部调用setLayoutDirection - Ted Hopp
显示剩余27条评论

229

这段代码确实有效:

fa代表波斯语,en代表英语

  • 注意:语言代码不能包含'-',只能是两个小写字母

languageToLoad变量中输入您的语言代码:

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;

public class Main extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String languageToLoad  = "fa"; // your language
    Locale locale = new Locale(languageToLoad); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
      getBaseContext().getResources().getDisplayMetrics());
    this.setContentView(R.layout.main);
  }
}

2021年6月更新(Kotlin):

class Main : Activity() {
    // Called when the activity is first created.
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val config = resources.configuration
        val lang = "fa" // your language code
        val locale = Locale(lang)
        Locale.setDefault(locale)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
            config.setLocale(locale)
        else
            config.locale = locale

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            createConfigurationContext(config)
        resources.updateConfiguration(config, resources.displayMetrics)

        this.setContentView(R.layout.main)
    }
}

4
我希望您能在运行时更改语言环境,在您的代码中,您将代码放置在setContentView()方法之前。所以您的代码对我没有用,那么如何在运行时更改语言呢?在我的应用程序中,有两个单选按钮,一个用于英语,另一个用于阿拉伯语。 - Ashish Dwivedi
2
@Buffalo,这只是 Resources.updateConfiguration 方法的第二个参数。我缩进了代码以使其更清晰。 - Czechnology
7
在启动活动中设置后,所有活动都可以正常工作。但是,操作栏标题似乎没有受到影响,仍然显示默认语言。你有什么想法我可能错过了什么? - Viral Patel
11
Config.locale已被弃用。 - Zoe stands with Ukraine
5
使用以下代码替代"config.locale = locale;":if (Build.VERSION.SDK_INT >= 17) { config.setLocale(locale); } else { config.locale = locale; }这将确保您的应用程序在不同版本的 Android 上正确设置语言环境。 - roghayeh hosseini
显示剩余10条评论

39

我正在寻找一种以编程方式更改系统语言的方法。虽然我充分理解普通应用程序永远不应该这样做,而应该:

  • 通过Intent将用户指向系统设置手动更改
  • 应用程序应该像Alex的答案中所描述的那样处理其本地化

但是,确实有必要以编程方式真正更改系统语言。

这是未经记录的API,因此不应用于市场/最终用户应用程序!

无论如何,这是我找到的解决方案:

  Locale locale = new Locale(targetLocaleAsString);

  Class amnClass = Class.forName("android.app.ActivityManagerNative");
  Object amn = null;
  Configuration config = null;

  // amn = ActivityManagerNative.getDefault();
  Method methodGetDefault = amnClass.getMethod("getDefault");
  methodGetDefault.setAccessible(true);
  amn = methodGetDefault.invoke(amnClass);

  // config = amn.getConfiguration();
  Method methodGetConfiguration = amnClass.getMethod("getConfiguration");
  methodGetConfiguration.setAccessible(true);
  config = (Configuration) methodGetConfiguration.invoke(amn);

  // config.userSetLocale = true;
  Class configClass = config.getClass();
  Field f = configClass.getField("userSetLocale");
  f.setBoolean(config, true);

  // set the locale to the new value
  config.locale = locale;

  // amn.updateConfiguration(config);
  Method methodUpdateConfiguration = amnClass.getMethod("updateConfiguration", Configuration.class);
  methodUpdateConfiguration.setAccessible(true);
  methodUpdateConfiguration.invoke(amn, config);

2
给出异常InvocationTargetException。 - Ravi
1
这取决于 invocationTargetException 抛出的位置。然后你应该知道被更改的类。 - icyerasor
3
我将我的应用程序放在/system/priv-app中,以解决Android 6.0的问题。详情请见 - weiyin
3
从API级别24开始,可以使用setLocales设置多种语言。 - Juuso Ohtonen
1
@nimamoradi 这里显示了所需的更改heregetConfiguration已移至内部类Proxy,该类扩展了ActivityManagerNative。更改应仅在API 26及以上版本中进行,请检查Build版本。请参见Fastlane here使用的代码以澄清。最后,弃用的.locale =应替换为setLocale - Nicolas
显示剩余9条评论

36

如果您想在整个应用程序中保持语言更改,您需要执行两个操作。

首先,创建一个基础 Activity,并使所有的活动都继承自此 Activity:

public class BaseActivity extends AppCompatActivity {

    private Locale mCurrentLocale;

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

        mCurrentLocale = getResources().getConfiguration().locale;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Locale locale = getLocale(this);

        if (!locale.equals(mCurrentLocale)) {

            mCurrentLocale = locale;
            recreate();
        }
    }

    public static Locale getLocale(Context context){
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        String lang = sharedPreferences.getString("language", "en");
        switch (lang) {
            case "English":
                lang = "en";
                break;
            case "Spanish":
                lang = "es";
                break;
        }
        return new Locale(lang);
    }
}

请注意,我将新语言保存在sharedPreference中。

其次,创建一个Application的扩展,如下所示:

    public class App extends Application {

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

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

    private void setLocale() {

        final Resources resources = getResources();
        final Configuration configuration = resources.getConfiguration();
        final Locale locale = getLocale(this);
        if (!configuration.locale.equals(locale)) {
            configuration.setLocale(locale);
            resources.updateConfiguration(configuration, null);
        }
    }
}

请注意,getLocale()与上面的相同。

就这些! 我希望这可以帮助某人。


应用程序活动是主要活动,就像MainActivity一样?例如,我可以在我的onCreate()方法中解决这个问题,使用setLocale()函数? - Morozov
应用程序(App)是应用的扩展,不是活动(Activity)。很抱歉,我不明白你需要什么。也许你可以再解释一遍 :) - Daniel S.
3
对于像我这样的Android新手,来这里学习Application是什么以及如何使用它。https://www.mobomo.com/2011/05/how-to-use-application-object-of-android/ - Siwei
2
configuration.locate已被弃用,setLocale需要API 17+,updateConfiguration也已被弃用。 - Zoe stands with Ukraine

27
根据这篇文章,您需要下载在那篇文章中提到的LocaleHelper.java文件。
  1. 创建一个名为MyApplication的类,继承Application
  2. 重写attachBaseContext()方法来更新语言。
  3. 在清单文件中注册该类。

public class MyApplication extends Application {
   @Override
   protected void attachBaseContext(Context base) {
    super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
   }
}

<application
     android:name="com.package.MyApplication"
     .../>
  • 创建BaseActivity,并重写onAttach()方法以更新语言。 在Android 6及以上版本中需要。

  • public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
    
    使您的应用程序中的所有活动都继承自BaseActivity
    public class LocaleHelper {
    
    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    
    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }
    
    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }
    
    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }
    
    public static Context setLocale(Context context, String language) {
        persist(context, language);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
    
        return updateResourcesLegacy(context, language);
    }
    
    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }
    
    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
    
        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }
    
    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
    
        return context.createConfigurationContext(configuration);
    }
    
    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(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;
    }
    }
    

    不能使用super.attachBaseContext(LocaleHelper.onAttach(newBase)),因为我已经在使用super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))。 - Rasel
    2
    你可以将一个包装在另一个里面。super.attachBaseContext(CalligraphyContextWrapper.wrap(LocaleHelper.onAttach(newBase))) - Yeahia2508

    16
    创建一个继承自 Application 的类,并创建一个静态方法。然后,在所有活动中的 setContentView() 之前调用此方法。
    public class MyApp extends Application {
    
    @Override
    public void onCreate() {
        super.onCreate();
    }
    
    public static void setLocaleFa (Context context){
        Locale locale = new Locale("fa"); 
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.locale = locale;
        context.getApplicationContext().getResources().updateConfiguration(config, null);
    }
    
    public static void setLocaleEn (Context context){
        Locale locale = new Locale("en_US"); 
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.locale = locale;
        context.getApplicationContext().getResources().updateConfiguration(config, null);
    }
    
    }
    

    在活动中的使用:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MyApp.setLocaleFa(MainActivity.this);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
    }
    

    16

    我只想额外添加一个让我困扰的细节。

    虽然其他回答中使用 "de" 是可以的,例如

    String lang = "de";
    Locale locale = new Locale(lang); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
        getBaseContext().getResources().getDisplayMetrics());
    
    上面的方法无法与例如"fr_BE"区域设置一起使用,因此它将使用values-fr-rBE文件夹或类似文件夹。
    需要进行以下轻微更改才能与"fr_BE"一起使用。
    String lang = "fr";
    
    //create a string for country
    String country = "BE";
    //use constructor with country
    Locale locale = new Locale(lang, country);
    
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
        getBaseContext().getResources().getDisplayMetrics());
    

    2
    如果您想将区域设置更改应用于当前打开的活动,请调用 activity.recreate() - To Kra
    我知道我来晚了,但新的Locale(lang, country)正是我所需要的! - Jacob Holloway
    activity.recreate()的工作原理是什么?如果我们调用它,那么String lang = "fr"; String country = "BE";将永远不会覆盖它的运行方式。 - Amitsharma
    1
    使用 android.content.res.Configuration conf = res.getConfiguration(); 而不是创建一个新的 Configuration 实例怎么样?使用全新实例有什么好处吗? - Bianca Daniciuc
    layoutDirection='locale' 怎么样? - nAkhmedov
    但是,如果您更新了地区设置,并尝试访问Locale.getDefault().country/context.resources.configuration.locales[0].language,您将得到空白的响应。 这是什么原因?有解决办法吗? - SaurabhG

    15

    我为我的应用启动自身而更改了德语语言。

    这是我的正确代码。任何人想要使用相同的代码可以参考以下内容。 (如何在Android中以编程方式更改语言)

    我的代码:

    Configuration config ; // variable declaration in globally
    
    // this part is given inside onCreate Method starting and before setContentView()
    
    public void onCreate(Bundle icic) 
    {
        super.onCreate(icic);
        config = new Configuration(getResources().getConfiguration());
        config.locale = Locale.GERMAN ;
        getResources().updateConfiguration(config,getResources().getDisplayMetrics());
    
        setContentView(R.layout.newdesign);
    }
    

    1
    @harikrishnan,对我来说不起作用,键盘也没有更改为指定的语言。你在清单文件中如何声明活动? - Avadhani Y

    14
    我知道回答已经很晚了,但我找到了这篇文章。它很好地解释了整个过程,并为您提供了一个良好结构化的代码。
    Locale Helper类:
    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;
    
    /**
     * This class is used to change your application locale and persist this change for the next time
     * that your app is going to be used.
     * <p/>
     * You can also change the locale of your application on the fly by using the setLocale method.
     * <p/>
     * Created by gunhansancar on 07/10/15.
     */
    public class LocaleHelper {
    
        private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    
        public static Context onAttach(Context context) {
            String lang = getPersistedData(context, Locale.getDefault().getLanguage());
            return setLocale(context, lang);
        }
    
        public static Context onAttach(Context context, String defaultLanguage) {
            String lang = getPersistedData(context, defaultLanguage);
            return setLocale(context, lang);
        }
    
        public static String getLanguage(Context context) {
            return getPersistedData(context, Locale.getDefault().getLanguage());
        }
    
        public static Context setLocale(Context context, String language) {
            persist(context, language);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                return updateResources(context, language);
            }
    
            return updateResourcesLegacy(context, language);
        }
    
        private static String getPersistedData(Context context, String defaultLanguage) {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
            return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
        }
    
        private static void persist(Context context, String language) {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
            SharedPreferences.Editor editor = preferences.edit();
    
            editor.putString(SELECTED_LANGUAGE, language);
            editor.apply();
        }
    
        @TargetApi(Build.VERSION_CODES.N)
        private static Context updateResources(Context context, String language) {
            Locale locale = new Locale(language);
            Locale.setDefault(locale);
    
            Configuration configuration = context.getResources().getConfiguration();
            configuration.setLocale(locale);
            configuration.setLayoutDirection(locale);
    
            return context.createConfigurationContext(configuration);
        }
    
        @SuppressWarnings("deprecation")
        private static Context updateResourcesLegacy(Context context, String language) {
            Locale locale = new Locale(language);
            Locale.setDefault(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;
        }
    }
    

    您需要覆盖attachBaseContext并调用LocaleHelper.onAttach()来初始化应用程序中的语言环境设置。

    import android.app.Application;
    import android.content.Context;
    
    import com.gunhansancar.changelanguageexample.helper.LocaleHelper;
    
    public class MainApplication extends Application {
        @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
        }
    }
    

    你所要做的就是添加

    LocaleHelper.onCreate(this, "en");
    

    在你想要更改地区设置的任何地方。


    LocaleHelper是一篇文章中的一个类。任何链接都有被删除的风险,请将代码添加到您的答案中。 - Zoe stands with Ukraine
    我不想重启我的应用程序,因为应用程序正在执行一些任务,例如录制屏幕。所以,在Android 7.0上,除了重新启动应用程序之外,是否有任何解决方案? - PriyankaChauhan
    1
    @PriyankaChauhan 我认为这篇文章涵盖了这种情况:您有两个选项来更新当前可见布局:首先,您可以逐个更新文本或任何其他语言相关资源。 - Maksim Turaev
    感谢您添加新的createConfigurationContext,这非常有帮助。 - jacoballenwood
    2
    调用onCreate还是onAttach? - vanste25

    12

    需要更新了。

    首先,API中已经弃用的列表如下:

    • configuration.locale (API 17)
    • updateConfiguration(configuration, displaymetrics) (API 17)

    最近没有一个问题得到正确回答的是新方法的使用方式。

    createConfigurationContextupdateConfiguration 的新方法。

    有些人将其独立地使用,像这样:

    Configuration overrideConfiguration = ctx.getResources().getConfiguration();
    Locale locale = new Locale("en_US");
    overrideConfiguration.setLocale(locale);
    createConfigurationContext(overrideConfiguration);
    

    但是那样做并不起作用。为什么呢?该方法返回一个上下文,然后用于处理Strings.xml翻译和其他本地化资源(图像,布局等)。

    正确的用法如下:

    Configuration overrideConfiguration = ctx.getResources().getConfiguration();
    Locale locale = new Locale("en_US");
    overrideConfiguration.setLocale(locale);
    //the configuration can be used for other stuff as well
    Context context  = createConfigurationContext(overrideConfiguration);
    Resources resources = context.getResources();
    

    如果你将它复制粘贴到IDE中,可能会看到一个警告,API要求你以API17或更高版本为目标。你可以通过将其放入方法并添加注释@TargetApi(17)来解决这个问题。

    但是等等,旧的API怎么办?

    你需要创建另一个方法,使用updateConfiguration而不带TargetApi注释。

    Resources res = YourApplication.getInstance().getResources();
    // Change locale settings in the app.
    DisplayMetrics dm = res.getDisplayMetrics();
    android.content.res.Configuration conf = res.getConfiguration();
    conf.locale = new Locale("th");
    res.updateConfiguration(conf, dm);
    

    这里不需要返回上下文。

    现在,管理这些内容可能会很困难。在API 17+中,您需要创建上下文(或从创建的上下文中获取资源)以根据本地化获取适当的资源。如何处理呢?

    嗯,这是我处理的方式:

    /**
     * Full locale list: https://dev59.com/92sz5IYBdhLWcg3wVGLJ
     * @param lang language code (e.g. en_US)
     * @return the context
     * PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
     */
    public Context setLanguage(String lang/*, Context c*/){
        Context c = AndroidLauncher.this;//remove if the context argument is passed. This is a utility line, can be removed totally by replacing calls to c with the activity (if argument Context isn't passed)
        int API = Build.VERSION.SDK_INT;
        if(API >= 17){
            return setLanguage17(lang, c);
        }else{
            return setLanguageLegacy(lang, c);
        }
    }
    
    /**
     * Set language for API 17
     * @param lang
     * @param c
     * @return
     */
    @TargetApi(17)
    public Context setLanguage17(String lang, Context c){
        Configuration overrideConfiguration = c.getResources().getConfiguration();
        Locale locale = new Locale(lang);
        Locale.setDefault(locale);
        overrideConfiguration.setLocale(locale);
        //the configuration can be used for other stuff as well
        Context context  = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
        //Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
        return context;
    }
    
    public Context setLanguageLegacy(String lang, Context c){
        Resources res = c.getResources();
        // Change locale settings in the app.
        DisplayMetrics dm = res.getDisplayMetrics();//Utility line
        android.content.res.Configuration conf = res.getConfiguration();
    
        conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
        Locale.setDefault(conf.locale);
        res.updateConfiguration(conf, dm);
    
        //Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
        //target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
        //supplied for both things
        return c;
    }
    

    这段代码的工作原理是有一个方法根据API调用适当的方法。我已经使用了许多不同的弃用调用(包括Html.fromHtml)。您有一个方法接收所需的参数,然后将其分成两个(或三个或更多)方法,并根据API级别返回适当的结果。它很灵活,因为您不必多次检查,“entry”方法会为您完成。这里的入口方法是setLanguage

    在使用之前请阅读此内容

    您需要使用获取资源时返回的上下文。为什么?我已经看到其他答案在此处使用createConfigurationContext并且没有使用它返回的上下文。要使它像那样工作,必须调用updateConfiguration。这已被弃用。使用该方法返回的上下文来获取资源。

    示例用法

    构造函数或类似位置:

    ctx = getLanguage(lang);//lang is loaded or generated. How you get the String lang is not something this answer handles (nor will handle in the future)
    

    然后,无论您想要获取资源的地方都可以执行以下操作:

    String fromResources = ctx.getString(R.string.helloworld);
    

    使用其他上下文(理论上)会破坏此功能。

    AFAIK,您仍然需要使用活动上下文来显示对话框或Toast。为此,您可以使用活动的实例(如果在外部)


    最后,使用recreate()在活动上刷新内容。这是不必创建意图以刷新的快捷方式。


    1
    有些人可能会想知道创建上下文是否会占用内存。然而,根据Android官方文档:“每次调用此方法都会返回一个Context对象的新实例;Context对象不是共享的,但是常见状态(ClassLoader、其他相同配置的资源)可能是共享的,因此Context本身可以相当轻量级。”因此,我认为Android确实希望您为区域设置使用单独的上下文对象。 - Sira Lam

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接