Programowe ustawianie ustawień regionalnych

139

Moja aplikacja obsługuje 3 (wkrótce 4) języki. Ponieważ kilka języków jest dość podobnych, chciałbym dać użytkownikowi możliwość zmiany lokalizacji w mojej aplikacji, na przykład osoba z Włoch może preferować hiszpański od angielskiego.

Czy użytkownik może wybrać spośród ustawień regionalnych dostępnych dla aplikacji, a następnie zmienić używane ustawienia regionalne? Nie widzę problemu w ustawianiu ustawień regionalnych dla każdego działania, ponieważ jest to proste zadanie do wykonania w klasie bazowej.

Roland
źródło
Jeśli potrzebujesz sposobu, aby później przywrócić domyślne ustawienia regionalne lub jeśli potrzebujesz preferencji językowych, które zawierają listę języków, i jeśli chcesz wygodniej zmienić ustawienia regionalne, może to być pomocne: github.com/delight-im/Android -Languages
caw

Odpowiedzi:

114

Osoby, które nadal szukają tej odpowiedzi, ponieważ configuration.localezostały wycofane z API 24, mogą teraz użyć:

configuration.setLocale(locale);

Weź pod uwagę, że minSkdVersion dla tej metody to API 17.

Pełny przykładowy kod:

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

Nie zapominaj, że jeśli zmienisz ustawienia regionalne za pomocą uruchomionego działania, będziesz musiał je ponownie uruchomić, aby zmiany odniosły skutek.

EDYCJA 11 MAJA 2018

Jak wynika z posta @ CookieMonster, możesz mieć problemy z utrzymaniem zmiany ustawień regionalnych w wyższych wersjach API. Jeśli tak, dodaj następujący kod do działania podstawowego, aby zaktualizować ustawienia regionalne kontekstu przy każdym utworzeniu działania:

@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_MR1)
private Context updateResourcesLocale(Context context, Locale locale) {
    Configuration configuration = new 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;
}

Jeśli tego używasz, nie zapomnij zapisać języka w SharedPreferences podczas ustawiania ustawień regionalnych za pomocą setLocate(locale)

EDYCJA 7 KWIETNIA 2020

Mogą występować problemy w systemie Android 6 i 7, a dzieje się tak z powodu problemu w bibliotekach systemu Androidx podczas obsługi trybu nocnego. W tym celu będziesz musiał również nadpisać applyOverrideConfigurationswoje podstawowe działanie i zaktualizować ustawienia regionalne konfiguracji w przypadku utworzenia nowego nowego ustawienia regionalnego.

Przykładowy kod:

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
        // update overrideConfiguration with your locale  
        setLocale(overrideConfiguration) // you will need to implement this
    }
    super.applyOverrideConfiguration(overrideConfiguration);
} 
Ricardo
źródło
2
Działa to w przypadku działań, ale czy istnieje sposób na zaktualizowanie kontekstu aplikacji?
alekop
2
Po zmianie androidx.appcompat:appcompat:wersji z 1.0.2na 1.1.0nie działa na Androidzie 7, ale działa na Androidzie 9.
Bek
4
Ten sam problem dla mnie i 1.1.0androidxa
Alexander Dadukin
2
Dla mnie ten sam problem. Po zmianie na androidx.appcompat: appcompat: 1.1.0 'lib
Rahul Jidge
4
Problem appcompat:1.1.0można rozwiązać appcompat:1.2.0-alpha02i zakodować w Set<Locale> set = new LinkedHashSet<>(); // bring the target locale to the front of the list set.add(locale); LocaleList all = LocaleList.getDefault(); for (int i = 0; i < all.size(); i++) { // append other locales supported by the user set.add(all.get(i)); } Locale[] locales = set.toArray(new Locale[0]); configuration.setLocales(new LocaleList(locales));środku@TargetApi(Build.VERSION_CODES.N) updateResourcesLocale()
Vojtech Pohl
178

Mam nadzieję, że ta pomoc (w onResume):

Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
      getBaseContext().getResources().getDisplayMetrics());
Rubycon
źródło
2
Więc to musi być ustawione dla każdego działania?
Tobias
6
1. użycie getBaseContext () jest obowiązkowe, czy lepiej używać kontekstu aplikacji? 2. ten kod powinien być wywoływany w każdym działaniu? dzięki.
Paul
10
Umieściłem ten kod w onCreate () mojego działania programu uruchamiającego (i nigdzie indziej) i byłem mile zaskoczony, widząc, że ustawienia regionalne są zastosowane do całej aplikacji. Jest to aplikacja przeznaczona dla 4.3 z minSDK 14 (ICS).
IAmKale
8
Nie ma potrzeby tworzenia nowego obiektu konfiguracji. Możesz użyć bieżącej konfiguracji i zaktualizować ją: getResources (). GetConfiguration ()
jmart
1
nie używaj nowej konfiguracji ();, zmienia textAppearance, fontSize
Jemshit Iskenderov
22

Miałem problem z programowym ustawieniem lokalizacji na urządzeniach z systemem Android OS N i nowszym . Dla mnie rozwiązaniem było napisanie tego kodu w mojej podstawowej aktywności:

(jeśli nie masz podstawowej aktywności, powinieneś wprowadzić te zmiany we wszystkich swoich działaniach)

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

zwróć uwagę, że tutaj nie wystarczy zadzwonić

createConfigurationContext(configuration)

musisz również pobrać kontekst, który zwraca ta metoda, a następnie ustawić ten kontekst w attachBaseContextmetodzie.

Ciasteczkowy potwór
źródło
To najłatwiejsze i działające rozwiązanie! To powinna być akceptowana odpowiedź.
Prasad Pawar
3
Ten kod bardzo działa na Androidzie powyżej 7, ale w wersjach poniżej N nie działa. Masz jakieś rozwiązania?
Matin Ashtiani
Nie jestem pewien, ponieważ to działa dla mnie. Czy chcesz przesłać mi swoją realizację, abym mógł rzucić okiem?
CookieMonster
2
Nie działa w wersjach pod Androidem N, ponieważ resources.updateConfiguration musi być wywołane w onCreate () zamiast attachBaseContext ()
Chandler
@Chandler ma rację. W przypadku Androida 6- wywołaj updateBaseContextLocalemetodę w onCreateaktywności rodzica / podstawowej.
Azizjon Kholmatov
22

Ponieważ nie ma pełnej odpowiedzi na temat obecnego sposobu rozwiązania tego problemu, staram się podać instrukcje dotyczące pełnego rozwiązania. Prosimy o komentarz, jeśli czegoś brakuje lub można to zrobić lepiej.

Informacje ogólne

Po pierwsze, istnieją biblioteki, które chcą rozwiązać ten problem, ale wszystkie wydają się przestarzałe lub brakuje im niektórych funkcji:

Ponadto myślę, że pisanie biblioteki może nie być dobrym / łatwym sposobem rozwiązania tego problemu, ponieważ nie ma zbyt wiele do zrobienia, a to, co należy zrobić, to raczej zmiana istniejącego kodu niż użycie czegoś całkowicie oddzielonego. Dlatego ułożyłem następujące instrukcje, które powinny być kompletne.

Moje rozwiązanie opiera się głównie na https://github.com/gunhansancar/ChangeLanguageExample (jak już jest połączone przez localhost ). To najlepszy kod, jaki znalazłem. Kilka uwag:

  • W razie potrzeby zapewnia różne implementacje do zmiany ustawień regionalnych dla Androida N (i nowszych) i niższych
  • Używa metody updateViews()w każdym działaniu, aby ręcznie zaktualizować wszystkie ciągi znaków po zmianie ustawień regionalnych (używając zwykłych getString(id)), co nie jest konieczne w podejściu pokazanym poniżej
  • Obsługuje tylko języki, a nie pełne ustawienia regionalne (które obejmują również kody regionu (kraju) i wariantu)

Zmieniłem to trochę, odsprzęgając część, która utrzymuje się w wybranym locale (jak można to zrobić osobno, jak zasugerowano poniżej).

Rozwiązanie

Rozwiązanie składa się z dwóch następujących kroków:

  • Trwale zmień ustawienia regionalne, które mają być używane przez aplikację
  • Spraw, aby aplikacja używała niestandardowego zestawu ustawień regionalnych bez ponownego uruchamiania

Krok 1: Zmień ustawienia regionalne

Użyj klasy LocaleHelperopartej na LocaleHelper firmy gunhansancar :

  • Dodaj ListPreferencew a PreferenceFragmentz dostępnymi językami (należy zachować, gdy języki mają być dodane później)
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;
    }
}

Utwórz SettingsFragmentpodobny następujący:

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

Utwórz zasób locales.xmlwymieniający wszystkie języki z dostępnymi tłumaczeniami w następujący sposób ( lista kodów regionalnych ):

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

W swoim PreferenceScreenmożesz skorzystać z następującej sekcji, aby pozwolić użytkownikowi wybrać dostępne języki:

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

który używa następujących ciągów z 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>

Krok 2: spraw, aby aplikacja korzystała z niestandardowych ustawień regionalnych

Teraz skonfiguruj każde działanie, aby korzystało z niestandardowego zestawu ustawień regionalnych. Najłatwiejszym sposobem osiągnięcia tego jest posiadanie wspólnej klasy bazowej dla wszystkich działań z następującym kodem (gdzie ważny kod znajduje się w attachBaseContext(Context base)i 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();
        }
    }
}

Co to jest

  • Zastąp, attachBaseContext(Context base)aby użyć ustawień regionalnych, które zostały wcześniej utrwaloneLocaleHelper
  • Wykryj zmianę ustawień regionalnych i ponownie utwórz działanie, aby zaktualizować jego ciągi

Uwagi dotyczące tego rozwiązania

  • Odtworzenie działania nie aktualizuje tytułu ActionBar (jak już zauważono tutaj: https://github.com/gunhansancar/ChangeLanguageExample/issues/1 ).

    • Można to osiągnąć po prostu mając setTitle(R.string.mytitle)w onCreate()metodzie każdej czynności.
  • Pozwala użytkownikowi wybrać domyślne ustawienia regionalne systemu, a także domyślne ustawienia regionalne aplikacji (które można nazwać w tym przypadku „angielskim”).

  • Do fr-rCAtej pory obsługiwane są tylko kody języków, brak kodów regionu (kraju) i wariantów (takich jak ). Aby obsługiwać pełne specyfikacje regionalne, można użyć parsera podobnego do tego w bibliotece Android-Languages (który obsługuje region, ale nie obsługuje kodów wariantów).

    • Jeśli ktoś znajdzie lub napisał dobry parser, dodaj komentarz, abym mógł dołączyć go do rozwiązania.
user905686
źródło
1
Znakomity, ale król koszmaru
Odys
1
Do diabła, nie, moja aplikacja jest już zbyt złożona, takie podejście byłoby koszmarem do utrzymania w przyszłości.
Josh
@Josh Czy możesz to trochę bardziej wyjaśnić? Właściwie tylko kilka wierszy należy dodać do każdej używanej klasy bazowej Activity. Widzę, że może nie być możliwe użycie tej samej klasy bazowej do wszystkich działań, ale nawet większe projekty powinny dać sobie radę z kilkoma. Programowanie zorientowane aspekt może pomóc tutaj, ale kompozycja (przenieść kod z attachBaseContext(Context base)i onResume()do osobnej klasy) daje rade. Następnie wszystko, co musisz zrobić, to zadeklarować jeden obiekt w każdej klasie bazowej działania i delegować te dwa wywołania.
user905686
Jeśli użytkownik zmieni swoje ustawienia narodowe, czy ustawienia regionalne wszystkich poprzednich stron aktywności również mogą zostać zmienione?
Raju yourPepe
To najlepsza odpowiedź w tej kwestii. Dzięki stary, to działa
Alok Gupta
16
@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);
    }
}

Po prostu użyj tej metody pomocniczej, aby wymusić określone ustawienia regionalne.

UDPATE 22 sierpnia 2017. Lepiej wykorzystaj to podejście .

Lokalny Gospodarz
źródło
4

Dodaj klasę pomocniczą za pomocą następującej metody:

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

    }
}

I nazwij to w swojej działalności startowej, na przykład MainActivity.java:

public void onCreate(Bundle savedInstanceState) {
    ...
    LanguageHelper.setAppLocale("fa", this);
    ...
}
Hadid Graphics
źródło
3

proste i łatwe

Locale locale = new Locale("en", "US");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = locale;
res.updateConfiguration(conf, dm);

gdzie „en” to kod języka, a „US” to kod kraju.

Makvin
źródło
Jak stwierdzono w moim poście, conf.locale=locale;jest przestarzały, a także jest updateConfiguration.
Ricardo
bardzo proste i mniej skomplikowane :)
Ramkesh Yadav
2

Obowiązuje dla API16 do API28 Po prostu umieść tę metodę w miejscu:

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

Wstaw ten kod we wszystkich swoich działaniach za pomocą:

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(localeUpdateResources(base, "<-- language code -->"));
    }

lub wywołaj localeUpdateResources na fragmentach, adapterach itp. tam, gdzie potrzebujesz nowego kontekstu.

Kredyty: Yaroslav Berezanskyi

nnyerges
źródło
2

Jest super prosty sposób.

w BaseActivity, Activity lub Fragment przesłania attachBaseContext

 override fun attachBaseContext(context: Context) {
    super.attachBaseContext(context.changeLocale("tr"))
}

rozbudowa

fun Context.changeLocale(language:String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = this.resources.configuration
    config.setLocale(locale)
    return createConfigurationContext(config)
}
Burak Dizlek
źródło
2

Uważam, że androidx.appcompat:appcompat:1.1.0błąd może być również ustalona po prostu przez wywołanie getResources()wapplyOverrideConfiguration()

@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);
}
Sam Lu
źródło
1
 /**
 * 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
    }
}
Zbigniew Mazur
źródło
1

Dla tych, którzy próbowali wszystkiego, ale nie działali . Proszę sprawdzić, czy ustawienie darkmodez AppCompatDelegate.setDefaultNightModea system nie jest ciemno, to Configuration.setLocalenie będzie działać powyżej Andorid 7.0 .

Dodaj ten kod do każdego działania, aby rozwiązać ten problem:

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
  if (overrideConfiguration != null) {
    val uiMode = overrideConfiguration.uiMode
    overrideConfiguration.setTo(baseContext.resources.configuration)
    overrideConfiguration.uiMode = uiMode
  }
  super.applyOverrideConfiguration(overrideConfiguration)
}
Yeahia2508
źródło
-1

Umieść ten kod w swojej aktywności

 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();
    }
Xurshid Raxmatov
źródło