在Android中以编程方式更改应用语言


448

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

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

我想让用户从应用程序中更改应用程序的语言。


4
您可以使用下面的库,它提供的语言列表中,偏好设置屏幕,并覆盖在你的应用程序的语言:github.com/delight-im/Android-Languages
CAW

@MarcoW。您知道Android语言是否可以与Android 5.0 Lollipop一起使用吗?
neu242

1
@ neu242是的,它可以在Android 5.0上正常运行。
caw


1
@ josue.0,该库确实是最干净的解决方案
amitavk

Answers:


376

这是可能的。您可以设置语言环境。但是,我不建议这样做。我们已经在早期阶段进行了尝试,基本上是在与系统抗争。

我们对更改语言有相同的要求,但决定解决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(Activitycontext) {
        Locale locale;
        Sessions session = new Sessions(context);
        //Log.e("Lan",session.getLanguage());
            locale = new Locale(langCode);
        Configuration config = new Configuration(context.getResources().getConfiguration());
        Locale.setDefault(locale);
        config.setLocale(locale);

       context.getBaseContext().getResources().updateConfiguration(config,
              context.getBaseContext().getResources().getDisplayMetrics());
    }

328
简直无法相信Android使之如此困难。我真的不明白为什么电话的语言环境与应用程序的语言之间应该存在STRICT关联。尽管我不是英语母语人士,但我始终使用英语电话。原因是,用我自己的语言翻译的半技术性单词太奇怪了,所以英语要容易得多。这也使我更容易遵循网络上的建议。但这并不意味着我希望手机上的每个应用都使用英语(尽管完全可以,这是默认设置)。我希望能够选择!
peterh 2013年

9
哦,好像引入了API级别17一样Context.createConfigurationContext(),可用于包装具有特定于语言环境的配置的默认上下文,然后调用该上下文getResources,而不必更新资源对象本身的配置。
JAB

8
您需要将其放在每个活动的onCreate()中。否则,它可能会被系统覆盖-例如,当您将设备转到横向并且使用新的(提供的系统)配置重新创建活动时。
Zsolt Safrany 2014年

13
如果您将RTL语言环境设置为“ ar”,并希望您的-ldrtl资源文件夹也能正常工作,则还可以调用conf.setLayoutDirection(locale);。
Zsolt Safrany 2014年

3
@ZsoltSafrany -而不是增加一个呼吁conf.setLayoutDirection(locale),可以替换conf.locale = new Locale(...))使用conf.setLocale(new Locale(...))。它将在内部调用setLayoutDirection
泰德·霍普

179

这段代码确实有效:

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

2
我想在运行时更改语言环境,在您的代码中,将代码放在setContentView()方法之前。因此,您的代码对我没有用,所以如何在运行时更改语言,在我的应用程序中,有两个单选按钮,分别用于英语和另一个用于阿拉伯语,
Dwivedi Ji

2
@Buffalo,它只是方法的第二个参数Resources.updateConfiguration。我已缩进代码以使其更加清晰。
捷克学2013年

5
设置启动活动后,此功能对所有活动均适用。但是,操作栏标题似乎不受影响,并且仍继续显示默认语言。知道我可能错过了什么吗?
AndroidMechanic-Viral Patel

8
Config.locale已弃用
Zoe

2
而不是“ config.locale = locale;” 使用“如果(Build.VERSION.SDK_INT> = 17){config.setLocale(locale);} else {config.locale = locale;}
roghayeh hosseini

36

我一直在寻找以编程方式更改系统语言的方法。尽管我完全理解,普通应用程序绝对不应这样做,而是:

  • 用户应(通过意图)指向系统设置以手动更改它
  • 应用程序应自行处理本地化,就像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
给出异常调用目标异常
Ravi

1
好吧,取决于在哪里抛出invocationTargetException。然后,您应该知道已更改的类。
icyerasor

1
@ Rat-a-tat-a-tat Ratatouille,从Android 4.2开始,android.permission.CHANGE_CONFIGURATION只能由使用Perform键签名的应用授予。

3
我将我的应用程序放在/ system / priv-app中,以解决Android 6.0问题。详细信息在这里
威音2015年

1
@Ravi我必须将我的应用程序从/ system / app移至/ system / priv-app才能正常工作
alexislg

31

如果要保留所有应用程序更改的语言,则必须做两件事。

首先,创建一个基本活动,并从此扩展所有活动:

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

应用程序是应用程序的扩展,不是活动。很抱歉,我不明白您的需要。也许您可以尝试再次向我解释一下:)
Daniel S.

1
对于像我这样的Android初学者来说,来这里学习是什么Application以及如何使用。 mobomo.com/2011/05/如何使用Android的应用程序对象
沉思薇

2
configuration.locate已弃用,setLocale需要API 17+,并且不赞成updateConfiguration
Zoe

19

根据 这篇文章。您将需要下载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"
         .../>
  4. 创建BaseActivity并覆盖onAttach()以更新语言。Android 6+需要

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
  5. 使您应用上的所有活动都从扩展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

1
您可以将另一个包裹起来。super.attachBaseContext(CalligraphyContextWrapper.wrap(LocaleHelper.onAttach(newBase)))
Yeahia2508

15

只是增加了一块让我绊倒的东西。

例如,其他答案可以使用“ 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());

1
如果您要将语言区域更改应用于当前打开的活动呼叫activity.recreate()

我知道我参加晚会很晚,但是我只需要新的Locale(语言,国家/地区)!
Jacob Holloway

activity.recreate()的工作方式,或者如果我们对此进行校准,则String lang =“ fr”; String country =“ BE”; 永远不会超越运行时间
Amitsharma 2015年

使用android.content.res.Configuration conf = res.getConfiguration();而不是创建新Configuration实例怎么办?使用新鲜的有什么好处吗?
比安卡·丹尼库克

14

我的应用程序启动后更改了德语。

这是我的正确代码。任何人都想为我使用这个。.(如何在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

13

我知道回答晚了,但是我在这里找到了这篇文章 。这很好地解释了整个过程,并为您提供了结构良好的代码。

语言环境帮助器类:

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

我不想重新启动我的应用程序,因为应用程序正在执行某些任务,例如录制屏幕。因此,无需重新启动应用程序,Android 7.0是否有任何解决方案
PriyankaChauhan

1
@PriyankaChauhan我认为本文涵盖了这种情况:您有两个选项来更新当前可见的布局: 首先,您可以一个一个地更新文本或任何其他与语言相关的资源。
Maksim Turaev

感谢您添加新的内容createConfigurationContext,这对您有所帮助
jacoballenwood

1
要调用onCreate或onAttach吗?
vanste25年

12

创建一个类扩展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);
}

10

对于Android 7.0牛轧糖(及更低版本),请遵循以下文章:

在Android中以编程方式更改语言

旧答案
这包括RTL / LTR支持:

public static void changeLocale(Context context, Locale locale) {
    Configuration conf = context.getResources().getConfiguration();
    conf.locale = locale;
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
       conf.setLayoutDirection(conf.locale);
    }

    context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());
}

1
不推荐使用updateConfiguration。该链接很有用,请添加到您的答案中。(仅链接的答案不好,因为链接可能会被删除。如果发生这种情况,此答案就没有用了)
Zoe

8

唯一对我完全有效的解决方案是Alex Volovoy的代码与应用程序重新启动机制的组合:

void restartApplication() {
    Intent i = new Intent(MainTabActivity.context, MagicAppRestart.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MainTabActivity.context.startActivity(i);
}


/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        startActivityForResult(new Intent(this, MainTabActivity.class), 0);         
    }
}

2
更改语言环境后,您也可以致电activity.recreate()

1
我不想重新启动我的应用程序,因为应用程序正在执行某些任务,例如录制屏幕。因此,无需重新启动应用程序,Android 7.0是否有任何解决方案
PriyankaChauhan

7

我面临着同样的问题。在GitHub上,我找到了Android-LocalizationActivity库

该库使在运行时更改应用程序语言变得非常简单,如下面的代码示例所示。一个示例项目,包括下面的示例代码和更多信息,可以在github页面上找到。

LocalizationActivity扩展了AppCompatActivity,因此在使用片段时也可以使用它。

public class MainActivity extends LocalizationActivity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);

        findViewById(R.id.btn_th).setOnClickListener(this);
        findViewById(R.id.btn_en).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.btn_en) {
            setLanguage("en");
        } else if (id == R.id.btn_th) {
            setLanguage("th");
        }
    }
}

7

进行适当更新的时间。

首先,使用已弃用的API弃用的列表:

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

最近没问题的答案是正确的是新方法的使用

createConfigurationContext是updateConfiguration的新方法。

有些人像这样单独使用它:

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要求您定位到API 17或更高版本。可以通过将其放入方法并添加注释来解决此问题。@TargetApi(17)

可是等等。那旧的API呢?

您需要使用没有TargetApi批注的updateConfiguration创建另一个方法。

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: /programming/7973023/what-is-the-list-of-supported-languages-locales-on-android
 * @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级别返回适当的结果。由于您不必多次检查,因此它很灵活,“输入”方法可以为您完成检查。这里的进入方法是setLanguage

使用前请仔细阅读

获取资源时,需要使用返回的Context。为什么?我在这里看到了其他答案,他们使用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)

7

如果你写

android:configChanges="locale"

在每个活动中(清单文件中),则无需在每次输入时进行设置Activity


11
如果在清单中,那么这将如何构成运行时的更改,这似乎是OP想要的?
user316117

1
@ user316117向Android指示该应用程序将在内部处理与语言环境配置有关的所有事宜,而不是语言环境是静态的。不过,我不确定这是否会阻止Android在Activity之间进行更改时设置区域设置,因为我只见过有人configChanges用hack来保留旋转/ etc上的Activity状态。
JAB 2014年

如何只将语言设置为英语专用?
Kaveesh Kanwal

1
...直到Android因为需要更多RAM而终止您的活动
路易CAD

@Brijesh如果我们更改了应用程序的语言,那么如果我们在应用程序内有一些搜索选项,然后在其中进行搜索,那么应用程序将如何显示数据,是否应该为每种语言开发一些不同的数据库,或者是否有一些android代码设置,所以该应用程序可以根据搜索显示数据?
Vishwa Pratap

5
Locale locale = new Locale("en");
Locale.setDefault(locale);

Configuration config = context.getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);

重要更新:

context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());

请注意,在SDK> = 21上,您需要调用'Resources.updateConfiguration()',否则资源将不会更新。


不推荐使用updateConfiguration。AFAIK使用createConfigurationContext并对其应用上下文(Context ctx = createConfigurationContext(args);并从中获取资源
Zoe

我知道它已被弃用。但是无论如何,我不知道任何可以在android 5及更高版本上运行的解决方案。
МаксимПетлюк

那么您显然没有检查javadoc。您调用从createConfigurationContext创建的上下文
Zoe

好的,但是无论如何,我们应该调用updateConfiguration(),对吗?
МаксимПетлюк

1
不要使用已弃用的呼叫。意味着没有呼叫updateConfiguration
Zoe

4
/*change language at Run-time*/
//use method like that:
//setLocale("en");
 public void setLocale(String lang) { 
  myLocale = new Locale(lang);         
  Resources res = getResources();         
  DisplayMetrics dm = res.getDisplayMetrics();         
  Configuration conf = res.getConfiguration();         
  conf.locale = myLocale;         
  res.updateConfiguration(conf, dm);         
  Intent refresh = new Intent(this, AndroidLocalize.class);         
  startActivity(refresh); 
 }

5
无需开始新的活动,只需刷新实际即可activity.recreate()

4

Locale configurationactivity在设置内容之前,应在每个设置中设置-this.setContentView(R.layout.main);


但是,如果要在调用setContentView()之后立即切换它,该怎么办?
IgorGanapolsky 2014年

2
更改语言环境后,您也可以致电activity.recreate()

4

首先,为不同的语言创建multi string.xml;然后在onCreate()方法中使用以下代码块:

super.onCreate(savedInstanceState);
String languageToLoad  = "fr"; // change your language here
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);

谢谢,这段代码很好用,我在Android 5.x和6.x上进行了测试,没有任何问题
innovaciones

4

这是一些对我有用的代码:

public class  MainActivity extends AppCompatActivity {
    public static String storeLang;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        SharedPreferences shp = PreferenceManager.getDefaultSharedPreferences(this);
        storeLang = shp.getString(getString(R.string.key_lang), "");

        // Create a new Locale object
        Locale locale = new Locale(storeLang);

        // Create a new configuration object
        Configuration config = new Configuration();
        // Set the locale of the new configuration
        config.locale = locale;
        // Update the configuration of the Accplication context
        getResources().updateConfiguration(
                config,
                getResources().getDisplayMetrics()
        );

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

资料来源:这里


3

这里列出的解决方案都没有帮助我。

如果AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES),则语言无法在android> = 7.0上打开

这个LocaleUtils可以正常工作: https ://gist.github.com/GigigoGreenLabs/7d555c762ba2d3a810fe

语言工具

public class LocaleUtils {

public static final String LAN_SPANISH      = "es";
public static final String LAN_PORTUGUESE   = "pt";
public static final String LAN_ENGLISH      = "en";

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);
        config.locale = sLocale;
        Resources res = app.getBaseContext().getResources();
        res.updateConfiguration(config, res.getDisplayMetrics());
    }
}
}

将此代码添加到应用程序

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

活动中的代码

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}

2

Alex Volovoy答案仅在活动的onCreate方法中对我有用。

适用于所有方法的答案在另一个线程中

在Android中以编程方式更改语言

这是代码的改编



    Resources standardResources = getBaseContext().getResources();

    AssetManager assets = standardResources.getAssets();

    DisplayMetrics metrics = standardResources.getDisplayMetrics();

    Configuration config = new Configuration(standardResources.getConfiguration());

    config.locale = new Locale(languageToLoad);

    Resources defaultResources = new Resources(assets, metrics, config);

希望对您有所帮助。


19
您说“在所有方法中都有效的答案是在另一个线程中”,但您的链接指向该线程!”
user316117 2012年

1
config.locale已弃用
Zoe

2
递归答案,可能是StackOverflow
tamtom

2

请注意,这种使用的解决方案updateConfiguration 在几周后不再适用于Android M版本。现在,新方法是使用参见API文档中applyOverrideConfiguration方法ContextThemeWrapper

自从我自己遇到问题以来,您可以在这里找到我的完整解决方案:https : //stackoverflow.com/a/31787201/2776572


我尝试在Android 6.0.1上使用updateConfiguration代码,并且工作正常,我不知道Google是否已解决此问题,但我可以毫无问题地使用它
innovaciones

1
@innovaciones不推荐使用的方法已经存在了一段时间。最终,它将被删除。这需要很长时间,但是最好尽快移至新的API,以防止出现问题
Zoe

1

您应该执行一些步骤

首先,您需要更改配置的语言环境

Resources resources = context.getResources();

Configuration configuration = resources.getConfiguration();
configuration.locale = new Locale(language);

resources.updateConfiguration(configuration, resources.getDisplayMetrics());

其次,如果您希望将更改直接应用于可见的布局,则可以直接更新视图,也可以只调用activity.recreate()重新启动当前活动。

而且您还必须坚持所做的更改,因为在用户关闭应用程序之后,您将丢失语言更改。

我在我的博客文章Android中以编程方式更改语言中介绍了更详细的解决方案

基本上,您只需在应用程序类上调用LocaleHelper.onCreate()即可,如果您想即时更改语言环境,则可以调用LocaleHelper.setLocale()


@LunarWatcher是的,如果您实际上在github或gist上检查了代码,则该代码已被处理。
Gunhan '17

1

当我按下按钮更改TextView的文本语言时,此方法有效。(values-de文件夹中的strings.xml)

String languageToLoad = "de"; // your language
Configuration config = getBaseContext().getResources().getConfiguration();
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
recreate();

1

添加LocaleHelper

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

活动中或片段中

Context context = LocaleHelper.setLocale(this, App.getSharedPre().getLanguage());
Resource resources = context.getResources();

现在在每个文本上设置SetText

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));

0

类似于已接受的答案,但为2017版本,并添加了重新启动(不重新启动,有时下一个Activity仍呈现英语):

// Inside some activity...
private void changeDisplayLanguage(String langCode) {
// Step 1. Change the locale in the app's configuration
    Resources res = getResources();
    android.content.res.Configuration conf = res.getConfiguration();
    conf.setLocale(currentLocale);
    createConfigurationContext(conf);
// Step 2. IMPORTANT! you must restart the app to make sure it works 100%
    restart();
}
private void restart() {
    PackageManager packageManager = getPackageManager();
    Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
    ComponentName componentName = intent.getComponent();
    Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
    mainIntent.putExtra("app_restarting", true);
    PrefUtils.putBoolean("app_restarting", true);
    startActivity(mainIntent);
    System.exit(0);
}

1)使用finish()代替2)重新启动应用程序,您可以使用activity.recreate()3)返回的上下文我认为必须用于获取资源
Zoe

我不想重新启动我的应用程序,因为应用程序正在执行某些任务,例如录制屏幕。因此,无需重新启动应用程序,Android 7.0是否有任何解决方案
PriyankaChauhan

0

首先,您要创建目录名称值-“印地语”(类似于印地语),而不是在此目录中写入“ hi”和相同的字符串文件名副本,并且在按钮等操作中设置以下代码后,更改值不会更改参数。

Locale myLocale = new Locale("hi");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
Intent refresh = new Intent(Home.this, Home.class);
startActivity(refresh);
finish(); 

1
conf.locale已弃用
Zoe

0
private void setLanguage(String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        config.setLocale(locale);
    } else {
        config.locale = locale;
    }
    getResources().updateConfiguration(config,
            getResources().getDisplayMetrics());

}

1
我不想重新启动我的应用程序,因为应用程序正在执行某些任务,例如录制屏幕。因此,无需重新启动应用程序,Android 7.0是否有任何解决方案
PriyankaChauhan

是的,在6.0上对我来说工作正常,无需重新启动应用程序,更改了语言,但是我没有在7.0上进行测试
Adeeb karim 17-10-6

0

在示例中,我们设置英语:

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

请记住,只有在“设备”系统中也找到了语言,这不仅适用于应用程序


0

对于阿拉伯语/ RTL支持

  1. 您必须通过-attachBaseContext()更新语言设置
  2. 对于Android版本N及更高版本,您必须使用createConfigurationContext()和updateConfiguration()-否则RTL布局无法正常工作

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

    public Context updateBaseContextLocale(Context context) {
        String language = SharedPreference.getInstance().getValue(context, "lan");//it return "en", "ar" like this
        if (language == null || language.isEmpty()) {
            //when first time enter into app (get the device language and set it
            language = Locale.getDefault().getLanguage();
            if (language.equals("ar")) {
                SharedPreference.getInstance().save(mContext, "lan", "ar");
            }
        }
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            updateResourcesLocale(context, locale);
            return  updateResourcesLocaleLegacy(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;
    }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.