Изменить язык приложения программно в Android - PullRequest
385 голосов
/ 25 мая 2010

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

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

Ответы [ 30 ]

8 голосов
/ 20 июля 2010

Если вы напишите

android:configChanges="locale"

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

7 голосов
/ 29 апреля 2013

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

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);         
    }
}
5 голосов
/ 12 мая 2017
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 ()' , иначе ресурсы не будут обновлены.

5 голосов
/ 16 апреля 2016

Я столкнулся с той же проблемой. На 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");
        }
    }
}
4 голосов
/ 19 июля 2017

Время для обновления.

Прежде всего, устаревший список с 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: https://stackoverflow.com/questions/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() в действии, чтобы обновить содержимое. Ярлык, чтобы не создавать намерения для обновления.

4 голосов
/ 06 февраля 2017

Сначала создайте 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);
4 голосов
/ 13 ноября 2012

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

4 голосов
/ 29 июля 2018

Вот код, который работает для меня:

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

Источник: здесь

4 голосов
/ 25 февраля 2015
/*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); 
 }
2 голосов
/ 03 августа 2015

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...