Как изменить язык приложения, когда пользователь выбирает язык?

107

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

1) 3 папки с возможностью рисования, drawable-es, drawable-pt, drawable.

2) 3 значения папки values-es, values-pt, values. Измените значения String.xml в соответствии с языками.

У меня есть imageView для выбора языка. При нажатии на него открывается меню, которое состоит из вариантов английский, испанский, португальский.

Я установил языковой стандарт внутри приложения при выборе опции этим кодом

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.en:
             Locale locale = new Locale("en"); 
             Locale.setDefault(locale);
             Configuration config = new Configuration();
             config.locale = locale;
             getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
             Toast.makeText(this, "Locale in English !", Toast.LENGTH_LONG).show();
             break;

        case R.id.pt:
             Locale locale2 = new Locale("pt"); 
             Locale.setDefault(locale2);
             Configuration config2 = new Configuration();
             config2.locale = locale2;
             getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Portugal !", Toast.LENGTH_LONG).show();
             break;

        case R.id.es:
             Locale locale3 = new Locale("es"); 
             Locale.setDefault(locale3);
             Configuration config3 = new Configuration();
             config3.locale = locale3;
             getBaseContext().getResources().updateConfiguration(config3, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Spain !", Toast.LENGTH_LONG).show();
             break;     
    }
    return super.onOptionsItemSelected(item);
}

Я заявляю в манифесте- android: configChanges = "locale"

Это работает, но у него есть проблема.

Проблема: -

1) При выборе языка экран, содержащий изображение выбора языка, не изменяется, но изменяются другие экраны.

2) После смены ориентации приложение восстанавливает язык в соответствии с локалью телефона.

Мукеш
источник
1
Для второй проблемы попробуйте добавить: android:configChanges="locale"для своей деятельности в AndroidManifest.xml
Parth Doshi
Я уже добавил каждую активность в свой манифест.
mukesh
Вы можете использовать следующую библиотеку, которая предоставляет список языков, предпочтения для экрана настроек и переопределяет язык в вашем приложении: github.com/delight-im/Android-Languages
caw

Ответы:

172

Это отрывок для веб-страницы: http://android.programmerguru.com/android-localization-at-runtime/

Изменить язык вашего приложения просто, когда пользователь выберет его из списка языков. Имейте метод, подобный приведенному ниже, который принимает языковой стандарт как String (например, «en» для английского языка, «привет» для хинди), настройте языковой стандарт для своего приложения и обновите текущую активность, чтобы отразить изменение языка. Примененный языковой стандарт не будет изменен, пока вы снова не измените его вручную.

public void setLocale(String lang) { 
    Locale 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); 
    finish();
    startActivity(refresh); 
} 

Убедитесь, что вы импортировали следующие пакеты:

import java.util.Locale; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.content.res.Configuration; 
import android.content.res.Resources; 
import android.util.DisplayMetrics; 

добавить в манифест активности android: configChanges = "locale | Ориентация"

Удхай
источник
2
Да, конечно. Я могу предоставить отрывок с веб-страницы. Где мне нужно предоставить, пожалуйста, дайте мне знать. Спасибо.
Udhay
3
Обязательно добавьте finish (), чтобы у вас не было двух копий вашей активности в стеке навигации.
Джоэл Теплый
6
finish()нужно позвонить раньше startActivity(refresh). В противном случае приложение может выйти вместо перезапуска действия.
Мохаммед Али
10
Привет, у меня получилось, это работает, но когда я перезапускаю приложение, оно возвращается к языку по умолчанию ..
Софиан Хассайни
5
Конфигурация конфигурации = новая конфигурация (newConfig); config.locale = локаль; В моем случае получаю это сообщение. локаль устарела на уровне API 25
Милон,
9

Хорошие решения здесь довольно хорошо объяснены. Но вот еще одно.

Создайте свой собственный CustomContextWrapperкласс-расширение ContextWrapperи используйте его, чтобы изменить настройку Locale для всего приложения. Вот GIST с использованием.

А затем вызовите CustomContextWrapperс сохраненным идентификатором локали, например, 'hi'для языка хинди в методе жизненного цикла активности attachBaseContext. Использование здесь:

@Override
protected void attachBaseContext(Context newBase) {
    // fetch from shared preference also save the same when applying. Default here is en = English
    String language = MyPreferenceUtil.getInstance().getString("saved_locale", "en");
    super.attachBaseContext(MyContextWrapper.wrap(newBase, language));
}
Sud007
источник
Спасибо за ссылку она работает , но я не понял несколько вещей, я просто назвал MyContextWrapper.warpв onAttachтолько одного фрагмента моего приложения , но язык был изменен для всего приложения, но названия активности не изменились, я думаю , что это потому что заголовки манифеста имеют приоритет, но если я вызываю тот же метод в onAttachBaseContexсвоем подклассе приложения, заголовки действий также меняются на выбранный язык, но тогда изменения применяются только к фрагменту, который я вызвал в методе деформации, почему это ?
Абхинав Чаухан
@AbhinavChauhan Я не уверен, что это правда. Мне нужно это проверить. Я никогда не сталкивался с этой проблемой, когда реализовывал это решение. Однако прошло много времени и могут быть некоторые изменения в реализации Android для более новых версий. В качестве альтернативы попробуйте несколько новых ответов на этот пост.
sud007
Я пробовал много решений, но ни одно из них не сработало, или, возможно, я реализовал их неправильно, может ваш класс хорошо работает с действиями, я использую его warpметод во onAttachфрагменте, ранее я сказал, что мне просто нужно было сделать это с фрагментом mainactivity, и язык был изменен в все приложение это правда, но для всех других фрагментов язык меняется на английский при изменении конфигурации, поэтому мне нужно вставить onattachвсе фрагменты, и вместо манифеста я установил заголовки панели действий в коде, теперь приложение работает, как ожидалось. спасибо
Абхинав Чаухан
Ладно! Я уверен, что вам не нужно делать это для каждого экрана, только для первого запускаемого действия и только внутри attachBaseContextфункции. И это касается всех экранов. Вы создали «BaseActivity» для всех действий в своем приложении?
sud007
Нет, я пытался сделать это в своем подклассе приложения, думая, что он будет применяться ко всему приложению, а затем ко всем фрагментам, но оказалось, что wrap()код должен выполняться при каждом изменении конфигурации, поэтому я поместил его в Абстрактная деятельность, из которой простираются все остальные виды деятельности, теперь она работает
Абхинав Чаухан
6

Вы должны либо удалить android:configChanges="locale"из манифеста, что приведет к перезагрузке активности, либо переопределить onConfigurationChangedметод:

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
    // your code here, you can use newConfig.locale if you need to check the language
    // or just re-set all the labels to desired string resource
}
Фране Поляк
источник
Удаление android: configChanges = "locale" из манифеста не препятствует перезапуску приложения. Он перезапустится независимо от того, добавлен он в манифест или нет.
portfoliobuilder
Я не говорю, что удаление android: configChanges = "locale" из манифеста предотвращает перезапуск приложения, я говорю с точностью до наоборот. Теперь, в случае, когда в манифесте есть android: configChanges = "locale", который использовался для предотвращения перезагрузки приложения во время написания этого ответа, я не могу точно сказать, что это так сейчас.
Frane Poljak
6

весь вышеперечисленный код @Uday идеален, но отсутствует только одна вещь (конфигурация по умолчанию в build.gradle)

public void setLocale(String lang) { 
Locale 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); 
finish();
startActivity(refresh); 

}

Мой не работал только потому, что языки не были упомянуты в файле конфигурации (build.gradle)

 defaultConfig {
    resConfigs "en", "hi", "kn"
}

после этого все языки начали работать

Локеш Тивари
источник
3
ЭТО НЕ РАБОТАЕТ
Крунал Шах
Это действительно нужно?
JCarlosR,
1
@JCarlosR да. когда я добавил языки в файл конфигурации, код Udhay начал работать
Локеш Тивари
3

Те, у кого проблема с версией, пробуют этот код ..

public static void switchLocal(Context context, String lcode, Activity activity) {
        if (lcode.equalsIgnoreCase(""))
            return;
        Resources resources = context.getResources();
        Locale locale = new Locale(lcode);
        Locale.setDefault(locale);
        android.content.res.Configuration config = new 
        android.content.res.Configuration();
        config.locale = locale;
        resources.updateConfiguration(config, resources.getDisplayMetrics());
        //restart base activity 
        activity.finish();
        activity.startActivity(activity.getIntent());
    }
Вахаб Хан Джадон
источник
3

Пример кода Udhay работает хорошо. За исключением вопроса Софиан Хассаини и Чирага Соланки, для повторного входа это не работает. Я пытаюсь вызвать код Udhay без перезапуска активности в onCreate () перед super.onCreate (savedInstanceState) ;. Тогда нормально! Только небольшая проблема, строки меню все еще не изменены на установленную локаль.

    public void setLocale(String lang) { //call this in onCreate()
      Locale 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); 
      //finish();
    } 
Фишер
источник
та же проблема со строками меню. Вы решаете проблему?
AlexS
@AlexS, я не нашел способов исправить проблему в строке меню. Но при выходе из приложения и повторном входе строки меню обычно можно изменить на новый языковой стандарт.
Fisher
ты имеешь ввиду Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS 02
2
@AlexS, нет! добавление новых Intent () и startActivity () может вернуть его к языку по умолчанию при перезапуске приложения. Я имею в виду, что если пользователи выходят из приложения и повторно входят в него, строки меню могут быть изменены на новый языковой стандарт.
Fisher