Установите Locale программно
Мое приложение поддерживает 3 (скоро 4) языка. Поскольку несколько локалей очень похожи, я бы хотел дать пользователю возможность изменить локаль в моем приложении, например, итальянец может предпочесть испанский, а не английский.
Есть ли способ для пользователя выбрать один из языковых стандартов, доступных для приложения, а затем изменить используемый языковой стандарт? Я не вижу проблемы в настройке локали для каждого действия, поскольку это простая задача для базового класса.
18 ответов
Для людей, которые все еще ищут этот ответ, так как configuration.locale
устарела, теперь вы можете использовать из API 24:
configuration.setLocale(locale);
Примите во внимание, что minSkdVersion для этого метода - API 17.
Полный пример кода:
@SuppressWarnings("deprecation")
private void setLocale(Locale locale){
SharedPrefUtils.saveLocale(locale); // optional - Helper method to save the selected language to SharedPreferences in case you might need to attach to activity context (you will need to code this)
Resources resources = getResources();
Configuration configuration = resources.getConfiguration();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
configuration.setLocale(locale);
} else{
configuration.locale=locale;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
getApplicationContext().createConfigurationContext(configuration);
} else {
resources.updateConfiguration(configuration,displayMetrics);
}
}
Не забывайте, что если вы меняете локаль с запущенным Activity, вам нужно будет перезапустить его, чтобы изменения вступили в силу.
РЕДАКТИРОВАТЬ 11 мая 2018
Начиная с поста @CookieMonster, у вас могут возникнуть проблемы с сохранением изменения локали в более высоких версиях API. Если это так, добавьте следующий код в базовую активность, чтобы обновлять контекстную локаль при каждом создании действия:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(updateBaseContextLocale(base));
}
private Context updateBaseContextLocale(Context context) {
String language = SharedPrefUtils.getSavedLanguage(); // Helper method to get saved language from SharedPreferences
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResourcesLocale(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;
}
Если вы используете это, не забудьте сохранить язык в SharedPreferences, когда вы устанавливаете локаль с setLocate(locale)
Надеюсь, что это поможет (в onResume):
Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
У меня была проблема с программной настройкой локали на устройствах с ОС Android N и выше. Для меня решением было написать этот код в моей основной деятельности:
(если у вас нет базовой активности, вы должны внести эти изменения во все ваши действия)
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(updateBaseContextLocale(base));
}
private Context updateBaseContextLocale(Context context) {
String language = SharedPref.getInstance().getSavedLanguage();
Locale locale = new Locale(language);
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResourcesLocale(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;
}
обратите внимание, что здесь недостаточно позвонить
createConfigurationContext(configuration)
вам также нужно получить контекст, который возвращает этот метод, а затем установить этот контекст в attachBaseContext
метод.
Поскольку пока нет полного ответа на текущий способ решения этой проблемы, я пытаюсь дать инструкции для полного решения. Пожалуйста, прокомментируйте, если что-то отсутствует или может быть сделано лучше.
Основная информация
Во-первых, существуют библиотеки, которые хотят решить проблему, но все они кажутся устаревшими или не имеют некоторых функций:
- https://github.com/delight-im/Android-Languages
- Устаревший (см. Вопросы)
- При выборе языка в пользовательском интерфейсе всегда отображаются все языки (жестко заданные в библиотеке), а не только те, где существуют переводы.
- https://github.com/akexorcist/Android-LocalizationActivity
- Кажется довольно сложным и может использовать аналогичный подход, как показано ниже
Кроме того, я думаю, что написание библиотеки не может быть хорошим / легким способом решения этой проблемы, потому что не так уж много нужно сделать, и что нужно сделать, это скорее изменить существующий код, чем использовать что-то полностью отделенное. Поэтому я составил следующие инструкции, которые должны быть завершены.
Мое решение в основном основано на https://github.com/gunhansancar/ChangeLanguageExample (как уже связано с localhost). Это лучший код для поиска. Некоторые замечания:
- При необходимости, он предоставляет различные реализации для изменения локали для Android N (и выше) и ниже
- Он использует метод
updateViews()
в каждом действии вручную обновлять все строки после изменения локали (используя обычныеgetString(id)
) что не является необходимым в подходе, показанном ниже - Поддерживаются только языки, а не полные локали (которые также включают код региона (страны) и варианта)
Я немного его изменил, отделив часть, которая сохраняет выбранную локаль (как можно было бы сделать это отдельно, как предложено ниже).
Решение
Решение состоит из следующих двух шагов:
- Навсегда изменить локаль, которая будет использоваться приложением
- Заставьте приложение использовать пользовательский набор языковых настроек без перезапуска
Шаг 1: Измените локаль
Используйте класс LocaleHelper
, основанный на LocaleHelper Gunhansancar:
- Добавить
ListPreference
вPreferenceFragment
с доступными языками (необходимо сохранить, когда языки должны быть добавлены позже)
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;
import mypackage.SettingsFragment;
/**
* Manages setting of the app's locale.
*/
public class LocaleHelper {
public static Context onAttach(Context context) {
String locale = getPersistedLocale(context);
return setLocale(context, locale);
}
public static String getPersistedLocale(Context context) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(SettingsFragment.KEY_PREF_LANGUAGE, "");
}
/**
* Set the app's locale to the one specified by the given String.
*
* @param context
* @param localeSpec a locale specification as used for Android resources (NOTE: does not
* support country and variant codes so far); the special string "system" sets
* the locale to the locale specified in system settings
* @return
*/
public static Context setLocale(Context context, String localeSpec) {
Locale locale;
if (localeSpec.equals("system")) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
locale = Resources.getSystem().getConfiguration().getLocales().get(0);
} else {
//noinspection deprecation
locale = Resources.getSystem().getConfiguration().locale;
}
} else {
locale = new Locale(localeSpec);
}
Locale.setDefault(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return updateResources(context, locale);
} else {
return updateResourcesLegacy(context, locale);
}
}
@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, Locale locale) {
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(locale);
configuration.setLayoutDirection(locale);
return context.createConfigurationContext(configuration);
}
@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, Locale 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;
}
}
Создать SettingsFragment
как следующее:
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import mypackage.LocaleHelper;
import mypackage.R;
/**
* Fragment containing the app's main settings.
*/
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String KEY_PREF_LANGUAGE = "pref_key_language";
public SettingsFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_settings, container, false);
return view;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
switch (key) {
case KEY_PREF_LANGUAGE:
LocaleHelper.setLocale(getContext(), PreferenceManager.getDefaultSharedPreferences(getContext()).getString(key, ""));
getActivity().recreate(); // necessary here because this Activity is currently running and thus a recreate() in onResume() would be too late
break;
}
}
@Override
public void onResume() {
super.onResume();
// documentation requires that a reference to the listener is kept as long as it may be called, which is the case as it can only be called from this Fragment
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
}
Создать ресурс locales.xml
перечисление всех локалей с доступными переводами следующим образом ( список кодов локали):
<!-- Lists available locales used for setting the locale manually.
For now only language codes (locale codes without country and variant) are supported.
Has to be in sync with "settings_language_values" in strings.xml (the entries must correspond).
-->
<resources>
<string name="system_locale" translatable="false">system</string>
<string name="default_locale" translatable="false"></string>
<string-array name="locales">
<item>@string/system_locale</item> <!-- system setting -->
<item>@string/default_locale</item> <!-- default locale -->
<item>de</item>
</string-array>
</resources>
В вашем PreferenceScreen
Вы можете использовать следующий раздел, чтобы позволить пользователю выбирать доступные языки:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/preferences_category_general">
<ListPreference
android:key="pref_key_language"
android:title="@string/preferences_language"
android:dialogTitle="@string/preferences_language"
android:entries="@array/settings_language_values"
android:entryValues="@array/locales"
android:defaultValue="@string/system_locale"
android:summary="%s">
</ListPreference>
</PreferenceCategory>
</PreferenceScreen>
который использует следующие строки из strings.xml
:
<string name="preferences_category_general">General</string>
<string name="preferences_language">Language</string>
<!-- NOTE: Has to correspond to array "locales" in locales.xml (elements in same orderwith) -->
<string-array name="settings_language_values">
<item>Default (System setting)</item>
<item>English</item>
<item>German</item>
</string-array>
Шаг 2. Заставьте приложение использовать пользовательский язык
Теперь настройте каждое действие, чтобы использовать пользовательский набор языковых стандартов. Самый простой способ сделать это - иметь общий базовый класс для всех действий со следующим кодом (где важен код attachBaseContext(Context base)
а также onResume()
):
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import mypackage.LocaleHelper;
import mypackage.R;
/**
* {@link AppCompatActivity} with main menu in the action bar. Automatically recreates
* the activity when the locale has changed.
*/
public class MenuAppCompatActivity extends AppCompatActivity {
private String initialLocale;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialLocale = LocaleHelper.getPersistedLocale(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocaleHelper.onAttach(base));
}
@Override
protected void onResume() {
super.onResume();
if (initialLocale != null && !initialLocale.equals(LocaleHelper.getPersistedLocale(this))) {
recreate();
}
}
}
Что это делает
- Override
attachBaseContext(Context base)
использовать локаль, ранее сохраненную сLocaleHelper
- Обнаружьте изменение языкового стандарта и заново создайте Activity, чтобы обновить его строки
Примечания к этому решению
Воссоздание Действия не обновляет заголовок ActionBar (как уже наблюдалось здесь: https://github.com/gunhansancar/ChangeLanguageExample/issues/1).
- Это может быть достигнуто простым
setTitle(R.string.mytitle)
вonCreate()
метод каждой деятельности.
- Это может быть достигнуто простым
Это позволяет пользователю выбрать системный языковой стандарт по умолчанию, а также языковой стандарт приложения по умолчанию (который может быть назван, в данном случае "английский").
Только коды языков, без региона (страны) и кодов вариантов (например,
fr-rCA
) поддерживаются до сих пор. Для поддержки полных спецификаций локали можно использовать синтаксический анализатор, подобный таковому в библиотеке Android-Languages (который поддерживает регион, но без кодов вариантов).- Если кто-то найдет или написал хороший анализатор, добавьте комментарий, чтобы я мог включить его в решение.
@SuppressWarnings("deprecation")
public static void forceLocale(Context context, String localeCode) {
String localeCodeLowerCase = localeCode.toLowerCase();
Resources resources = context.getApplicationContext().getResources();
Configuration overrideConfiguration = resources.getConfiguration();
Locale overrideLocale = new Locale(localeCodeLowerCase);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
overrideConfiguration.setLocale(overrideLocale);
} else {
overrideConfiguration.locale = overrideLocale;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.getApplicationContext().createConfigurationContext(overrideConfiguration);
} else {
resources.updateConfiguration(overrideConfiguration, null);
}
}
Просто используйте этот вспомогательный метод для принудительного определения конкретной локали.
UDPATE 22 августа 2017 года. Лучше использовать этот подход.
Есть супер простой способ.
в BaseActivity, Activity или Fragment переопределить attachBaseContext
override fun attachBaseContext(context: Context) {
super.attachBaseContext(context.changeLocale("tr"))
}
расширение
fun Context.changeLocale(language:String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val config = this.resources.configuration
config.setLocale(locale)
return createConfigurationContext(config)
}
Добавьте вспомогательный класс с помощью следующего метода:
public class LanguageHelper {
public static final void setAppLocale(String language, Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Resources resources = activity.getResources();
Configuration configuration = resources.getConfiguration();
configuration.setLocale(new Locale(language));
activity.getApplicationContext().createConfigurationContext(configuration);
} else {
Locale locale = new Locale(language);
Locale.setDefault(locale);
Configuration config = activity.getResources().getConfiguration();
config.locale = locale;
activity.getResources().updateConfiguration(config,
activity.getResources().getDisplayMetrics());
}
}
}
И назовите это в своей деятельности запуска, как MainActivity.java
:
public void onCreate(Bundle savedInstanceState) {
...
LanguageHelper.setAppLocale("fa", this);
...
}
Действительно для API16 - API28 Просто разместите этот метод где-нибудь:
Context newContext = context;
Locale locale = new Locale(languageCode);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration config = new Configuration(resources.getConfiguration());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
config.setLocale(locale);
newContext = context.createConfigurationContext(config);
} else {
config.locale = locale;
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
return newContext;
}
Вставьте этот код во все свои действия, используя:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(localeUpdateResources(base, "<-- language code -->"));
}
или вызовите localeUpdateResources для фрагментов, адаптеров и т. д., где вам нужен новый контекст.
Кредиты: Ярослав Березанский
Я нашел androidx.appcompat:appcompat:1.1.0
ошибку также можно исправить, просто позвонив getResources()
в applyOverrideConfiguration()
@Override public void
applyOverrideConfiguration(Configuration cfgOverride)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// add this to fix androidx.appcompat:appcompat 1.1.0 bug
// which happens on Android 6.x ~ 7.x
getResources();
}
super.applyOverrideConfiguration(cfgOverride);
}
Просто и легко
Locale locale = new Locale("en", "US");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = locale;
res.updateConfiguration(conf, dm);
где "en" - это код языка, а "US" - код страны.
В Android 13 представлены языковые настройки для каждого приложения, которые значительно упрощают обработку изменений локали в приложении.
Отказ от ответственности: Android 13 в настоящее время находится в «Предварительной версии для разработчиков» на момент написания, и часть упомянутого здесь находится в альфа-версии (таким образом, может быть изменена).
Как видно из документов, есть несколько новых способов обработки таких изменений, для совместимости лучший из них, по-видимому, через
AppCompatDelegate
:
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("xx-YY")
// Call this on the main thread as it may require Activity.restart()
AppCompatDelegate.setApplicationLocales(appLocale)
(Метод доступен с
androidx.appcompat:appcompat:1.6.0-alpha01
)
Это позаботится о настройке локали на
appLocale
и перезапустите любые действия по мере необходимости. Более того, как упоминалось в документах setApplicationLocales
На уровне API 33 и выше этот API будет автоматически обрабатывать хранилище.
Это означает, что для работы пользовательской локали в приложении нужно просто предложить пользователю средство выбора языка и вызвать
setApplicationLocales
один раз при выполнении выбора.
А как насчет API < 33?
В документах на developer.android.com упоминается, что разработчики могут требовать автоматического сохранения этого значения на более старых уровнях API.
.. добавив специальную запись метаданных в свой AndroidManifest, например:
но на момент написания этой статьи фактические необходимые метаданные не упоминались (возможно, что-то пошло не так при создании документа).
Вместо этого он был виден в исходном коде AppCompatDelegate , опубликованном здесь, и выглядит следующим образом .
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
Добавление вышеуказанного в ваш манифест должно заставить это решение работать для всех уровней API.
Существует новый способ позволить пользователям выбирать язык приложения по умолчанию, начиная с Appcompat 1.6.0-alpha04 и более поздних версий. Допустим, у вас есть кнопка, которая должна менять язык приложения на итальянский , когда пользователь нажимает на нее:
binding.button.setOnClickListener {
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags("it")
AppCompatDelegate.setApplicationLocales(appLocale)
}
Кроме того, чтобы добавить поддержку старых устройств (<уровень API 32), добавьте следующееservice
внутри<application>
тег вашегоAndroidManifest.xml
файл:
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
Убедитесь, что у вас есть последняяAppCompat
зависимость:
implementation 'androidx.appcompat:appcompat:1.6.0-alpha05'
Ссылка: https://developer.android.com/about/versions/13/features/app-languages
/**
* Requests the system to update the list of system locales.
* Note that the system looks halted for a while during the Locale migration,
* so the caller need to take care of it.
*/
public static void updateLocales(LocaleList locales) {
try {
final IActivityManager am = ActivityManager.getService();
final Configuration config = am.getConfiguration();
config.setLocales(locales);
config.userSetLocale = true;
am.updatePersistentConfiguration(config);
} catch (RemoteException e) {
// Intentionally left blank
}
}
С 2020 года управлять языком стало проще! Все, что вам нужно сделать, это:
- Позвонить
Activity.applyOverrideConfiguration
- И позвонить
Locale.setDefault
Вы должны вызывать их из конструктора активности, так как вы можете вызывать
applyOverrideConfiguration
только один раз, и система вызывает это довольно рано.
И будьте осторожны с наборами приложений, Google автоматически разделит ваш APK по языковым ресурсам при использовании наборов приложений. Ознакомьтесь с новым API и обходным путем здесь.
Я создал вспомогательный класс, чтобы помочь вам с этим. В моей реализации
G.app
контекст приложения. Кроме того, мне нужно получить доступ к ресурсам из контекста приложения, поэтому я использую
Res
class для него, это необязательно, но я также предоставляю его код.
Применение
public BaseActivity(){
LanguageUtility.init(this);
}
public void changeLanguage(Local local){
// you must recreat your activity after you call this
LanguageUtillity.setDefaultLanguage(local, this);
}
Исходный код
public class LanguageUtility {
private static Configuration configuration;
public static void setDefaultLanguage(Locale locale, Context context) {
Locale.setDefault(locale);
context.getSharedPreferences("LocaleSettings", Context.MODE_PRIVATE)
.edit()
.putString("language", locale.getLanguage())
.putString("country", locale.getCountry())
.putString("variant", locale.getVariant())
.apply();
configuration = createConfiguration(context);
Res.updateContext();
}
/**
* Used to update your app context in case you cache it.
*/
public static Context createConfigurationContext(Context context) {
return context.createConfigurationContext(getConfiguration(context));
}
public static void init(Activity activity) {
activity.applyOverrideConfiguration(LanguageUtility.getConfiguration(G.app));
// you can't access sharedPrefferences from activity constructor
// with activity context, so I used the app context.
Locale.setDefault(getLocale(G.app));
}
@NotNull
private static Configuration getConfiguration(Context context) {
if (configuration == null) {
configuration = createConfiguration(context);
}
return configuration;
}
@NotNull
private static Configuration createConfiguration(Context context) {
Locale locale = getLocale(context);
Configuration configuration = new Configuration();
configuration.setLocale(locale);
LanguageUtility.configuration = configuration;
return configuration;
}
@NotNull
private static Locale getLocale(Context context) {
Locale aDefault = Locale.getDefault();
SharedPreferences preferences =
context.getSharedPreferences("LocaleSettings", Context.MODE_PRIVATE);
String language = preferences.getString("language", aDefault.getLanguage());
String country = preferences.getString("country", aDefault.getCountry());
String variant = preferences.getString("variant", aDefault.getVariant());
return new Locale(language, country, variant);
}
}
Необязательный класс Res.
public class Res {
@SuppressLint("StaticFieldLeak")
public static Context appLocalContext = LanguageUtility.createConfigurationContext(G.app);
public static void updateContext() {
appLocalContext = LanguageUtility.createConfigurationContext(G.app);
}
public static String getString(@StringRes int id, Object... formatArgs) {
return appLocalContext.getResources().getString(id, formatArgs);
}
public static int getColor(@ColorRes int id) {
return G.app.getColor(id);
}
}
Вызовите этот метод в BaseActivity -> onCreate () и BaseFragment -> OnCreateView ()
Протестировано на API 22, 23, 24, 25, 26, 27, 28, 29... в последней версии
fun Context.updateLang() {
val resources = resources
val config = Configuration(resources.configuration)
config.setLocale(PreferenceManager(this).getAppLanguage()) // language from preference
val dm = resources.displayMetrics
createConfigurationContext(config)
resources.updateConfiguration(config, dm)
}
Для тех, кто все пробовал, но не работает. Убедитесь, что если вы установилиdarkmode
с AppCompatDelegate.setDefaultNightMode
а система не тёмная, то Configuration.setLocale
не будет работать выше Andorid 7.0.
Добавьте этот код в каждое действие, чтобы решить эту проблему:
override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
if (overrideConfiguration != null) {
val uiMode = overrideConfiguration.uiMode
overrideConfiguration.setTo(baseContext.resources.configuration)
overrideConfiguration.uiMode = uiMode
}
super.applyOverrideConfiguration(overrideConfiguration)
}
@SuppressWarnings("deprecation")
private void setLocale(Locale locale){
SharedPrefUtils.saveLocale(locale); // optional - Helper method to save the selected language to SharedPreferences in case you might need to attach to activity context (you will need to code this)
Resources resources = getResources();
Configuration configuration = resources.getConfiguration();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
configuration.setLocale(locale);
} else{
configuration.locale=locale;
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N){
getApplicationContext().createConfigurationContext(configuration);
} else {
resources.updateConfiguration(configuration,displayMetrics);
}
}
Поместите этот код в вашу деятельность
if (id==R.id.uz)
{
LocaleHelper.setLocale(MainActivity.this, mLanguageCode);
//It is required to recreate the activity to reflect the change in UI.
recreate();
return true;
}
if (id == R.id.ru) {
LocaleHelper.setLocale(MainActivity.this, mLanguageCode);
//It is required to recreate the activity to reflect the change in UI.
recreate();
}