Измените язык приложения программно в Android


448

Можно ли программно изменить язык приложения, все еще используя ресурсы Android?

Если нет, можно ли запросить ресурс на определенном языке?

Я хотел бы позволить пользователю изменить язык приложения из приложения.


4
Вы можете использовать следующую библиотеку, которая предоставляет список языков, предпочтения для экрана настроек и переопределяет язык в вашем приложении: github.com/delight-im/Android-Languages
caw

@MarcoW. Знаете ли вы, работает ли Android-Languages ​​с Android 5.0 Lollipop?
neu242

1
@ neu242 Да, он работает на Android 5.0 без проблем.
воскликнул

1
Вы можете использовать следующую библиотеку: github.com/zeugma-solutions/locale-helper-android
josue.0

1
@ josue.0 эта библиотека действительно является самым чистым решением для этого
amitavk

Ответы:


376

Возможно. Вы можете установить локаль. Однако я бы не рекомендовал это. Мы попробовали это на ранних стадиях, это в основном борьба с системой.

У нас есть такое же требование для изменения языка, но мы решили согласиться с тем, что пользовательский интерфейс должен совпадать с пользовательским интерфейсом телефона. Он работал через настройку локали, но был слишком глючным. И вы должны устанавливать его каждый раз, когда вы входите в действие (каждое действие) из моего опыта. вот код, если вам все еще нужно это (опять же, я не рекомендую это)

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

Если у вас есть контент для конкретного языка - вы можете изменить эту базу в зависимости от настроек.


Обновление от 26 марта 2020 года

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

329
Не могу поверить, что Android делает это так сложно. Я действительно не понимаю, почему должна быть СТРОЧНАЯ связь между локалью телефона и приложением. У меня всегда есть телефон с использованием английского языка, хотя я не являюсь носителем английского языка. Причина в том, что переведенные полутехнические слова на моем родном языке становятся слишком странными, поэтому английский намного проще. Это также облегчает мне следовать советам из Сети. Но это не значит, что я хочу, чтобы КАЖДОЕ приложение на моем телефоне использовало английский язык (хотя это нормально, по умолчанию). Я хочу иметь возможность выбирать !!!
петер

9
О, похоже на введенный уровень API 17 Context.createConfigurationContext(), который можно использовать для обертывания контекста по умолчанию с помощью конфигурации, специфичной для локали, а затем вызывать ее getResources, не обновляя конфигурацию самих объектов ресурсов.
JAB

8
Вы должны поместить это в onCreate () каждого действия. В противном случае он может быть переопределен системой - например, когда вы переключаете ваше устройство в горизонтальное положение и ваша деятельность воссоздается с новой (предоставленной системой) конфигурацией.
Жольт Сафрани

14
Если вы установили RTL-локаль, например «ar», и хотите, чтобы папки ресурсов -ldrtl работали так же, тогда также вызовите conf.setLayoutDirection (locale);
Жолт Сафрани

3
@ZsoltSafrany - вместо добавления вызова conf.setLayoutDirection(locale)вы можете заменить conf.locale = new Locale(...))на conf.setLocale(new Locale(...)). Это будет внутренне звонить setLayoutDirection.
Тед Хопп

180

Этот код действительно работает:

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метода. Я отступил в коде, чтобы сделать его более понятным.
Chechnology

5
Это работает хорошо для всех действий после установки в стартовом действии. Но заголовок панели действий кажется незатронутым и продолжает отображать язык по умолчанию. Есть идеи, что я мог пропустить?
AndroidMechanic - Вирусный Патель

8
Config.locale устарела
Zoe

2
вместо "config.locale = locale;" use "if (Build.VERSION.SDK_INT> = 17) {config.setLocale (locale);} else {config.locale = locale;}
roghayeh hosseini

36

Я искал способ изменить язык системы программно. Хотя я полностью понимаю, что нормальное приложение никогда не должно этого делать, а вместо этого:

  • пользователь должен указать (через намерение) на настройки системы, чтобы изменить его вручную
  • приложение должно обрабатывать свою локализацию самостоятельно, как описано в ответе Алекса.

возникла необходимость реально изменить язык системы программно.

Это недокументированный 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
исключение invocationtarget exception
Ravi

1
Хорошо зависит от того, где выбрасывается invocationTargetException. Тогда вы должны знать класс, который был изменен.
icyerasor

1
@ Rat-a-tat-a-tat Ratatouille, начиная с Android 4.2, android.permission.CHANGE_CONFIGURATIONможет быть предоставлено только приложением, подписанным с ключом выполнения.
Yeung

3
Я поместил свое приложение в / system / priv-app, чтобы обойти проблему с Android 6.0. Подробности здесь .
Вейин

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? например, я могу решить это в setLocale () в моем методе onCreate ()?
Морозов

Приложение - это расширение приложения, а не активность. Я не понимаю, что вам нужно, извините. Может быть, вы можете попытаться объяснить мне снова :)
Даниэль С.

1
для тех Android-нубов, как я, иди сюда, чтобы узнать, что это Applicationтакое и как использовать. mobomo.com/2011/05/how-to-use-application-object-of-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

Просто добавляю лишнюю часть, которая сбила меня с толку.

В то время как другие ответы хорошо работают с "де", например

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 (язык, страна) был всем, что мне было нужно!
Джейкоб Холлоуэй

activity.recreate () как это работает, или если мы это называем, то String lang = "fr"; String country = "BE"; никогда не переопределит то, как он будет работать
Amitsharma

Как насчет использования 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

Я знаю, что уже поздно отвечать, но я нашел эту статью здесь . Что очень хорошо объясняет весь процесс и дает вам хорошо структурированный код.

Класс 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 - это класс из статьи. Любые ссылки могут быть удалены. Пожалуйста, добавьте код в свой ответ.
Зои

Я не хочу перезапускать свое приложение, потому что приложение выполняет какую-то задачу, например экран записи. так что без перезапуска приложения есть ли решение для Android 7.0
PriyankaChauhan

1
@PriyankaChauhan Я думаю, что статья описывает этот случай: у вас есть два варианта обновления отображаемого в данный момент макета: во- первых , вы можете просто обновить текст или любые другие зависящие от языка ресурсы по одному.
Максим Тураев

спасибо за добавление нового createConfigurationContext, что было полезно
jacoballenwood

1
На создание или на присоединение звонить?
vanste25

12

Создать класс Extennds 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 Nougat (и ниже) следуйте этой статье:

Изменить язык программно в 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

Единственное решение, которое полностью работает для меня, - это сочетание кода Алексея Волового с механизмом перезапуска приложения:

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?

Вам нужно создать другой метод, используя 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: /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. Он гибкий, так как вам не нужно проверять несколько раз, метод "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, вы все равно должны использовать контекст деятельности, чтобы показать диалоги или тосты. для этого вы можете использовать экземпляр действия (если вы находитесь за пределами)


И, наконец, используйте recreate()упражнение для обновления содержимого. Ярлык, чтобы не создавать намерение обновить.


1
Некоторые могут задаться вопросом, будет ли созданный контекст стоить вашей памяти. Однако в соответствии с официальной документацией Android: «Каждый вызов этого метода возвращает новый экземпляр объекта Context; объекты Context не являются общими, однако общее состояние (ClassLoader, другие ресурсы для той же конфигурации) может быть таким, что сам контекст может быть справедливым легкий «. Поэтому я думаю, что Android действительно ожидает, что вы будете использовать отдельный объект контекста для локали.
Сира Лам

7

Если ты пишешь

android:configChanges="locale"

В каждом действии (в файле манифеста) нет необходимости устанавливать его каждый раз при вводе Activity.


11
Если это в манифесте, то как это может измениться во время выполнения, что, по-видимому, и было целью ОП?
user316117

1
@ user316117 Android указывает, что приложение будет обрабатывать все вопросы, связанные с настройкой локали внутри, а не то, что локаль является статической. Я не уверен, что это помешает Android установить языковой стандарт при переключении между действиями, хотя, как я видел, configChangesиспользовался только для взлома, чтобы сохранить состояние активности при поворотах / и т.д.
JAB

Как установить язык только для конкретного английского?
Kaveesh Kanwal

1
... пока Android не убьет вашу активность, потому что ему нужно больше оперативной памяти
Louis CAD

@Brijesh Если мы изменим язык приложения, тогда, если у нас будет какая-то опция поиска в приложении, и если мы будем искать в ней, то, как приложение будет показывать данные, следует ли нам разработать какую-то другую базу данных для каждого языка или какая-то настройка кода Android есть так это приложение может показывать данные в соответствии с поиском?
Вишва Пратап

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 configurationдолжны быть установлены в каждом activityперед настройкой содержимого -this.setContentView(R.layout.main);


Но что, если вы хотите переключить его на лету после вызова setContentView ()?
Игорь Ганапольский

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

Ни одно из перечисленных здесь решений не помогло мне.

Язык не включал android> = 7.0, если AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE_NIGHT_YES)

Этот LocaleUtils работает просто отлично: https://gist.github.com/GigigoGreenLabs/7d555c762ba2d3a810fe

LocaleUtils

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

Ответ Алексея Волового работает только для меня, если он используется в методе действия 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

1
config.locale устарела
Zoe

2
рекурсивный ответ, возможный из StackOverflow
тамтом

2

Обратите внимание, что использование этого решения updateConfiguration больше не будет работать с выпуском Android M через несколько недель. Новый способ сделать это теперь использует applyOverrideConfigurationметод изContextThemeWrapper см. API документ

Вы можете найти мое полное решение здесь, так как я сам столкнулся с проблемой: https://stackoverflow.com/a/31787201/2776572


Я пытаюсь обновить код конфигурации на Android 6.0.1, и он работает нормально, я не знаю, исправил ли это 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());

Во-вторых, если вы хотите, чтобы ваши изменения применялись непосредственно к отображаемому макету, вы можете либо обновить представления напрямую, либо просто вызвать action.recreate (), чтобы перезапустить текущее действие.

А также вы должны сохранить ваши изменения, потому что после того, как пользователь закроет ваше приложение, вы потеряете изменение языка.

Более подробное решение я объяснил в своем блоге « Смена языка программно в Android»

По сути, вы просто вызываете LocaleHelper.onCreate () для своего класса приложения, и если вы хотите изменить локаль на лету, вы можете вызвать LocaleHelper.setLocale ()


@LunarWatcher Да, если вы действительно проверяете код на github или gist, он уже обработан.
Ганхан

1

Это работает, когда я нажимаю кнопку, чтобы изменить язык текста моего TextView. (Strings.xml в папке values-de)

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

Теперь установите текст на каждый текст

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

0

аналогично принятой версии с ответом, но версии 2017 года и добавленному перезапуску (без перезапуска, иногда следующее действие по-прежнему отображает английский):

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.