Stellen Sie das Gebietsschema programmgesteuert ein


139

Meine App unterstützt 3 (bald 4) Sprachen. Da mehrere Gebietsschemas sehr ähnlich sind, möchte ich dem Benutzer die Möglichkeit geben, das Gebietsschema in meiner Anwendung zu ändern. Beispielsweise könnte eine italienische Person Spanisch gegenüber Englisch bevorzugen.

Gibt es eine Möglichkeit für den Benutzer, unter den für die Anwendung verfügbaren Gebietsschemas auszuwählen und dann zu ändern, welches Gebietsschema verwendet wird? Ich sehe es nicht als Problem an, das Gebietsschema für jede Aktivität festzulegen, da es eine einfache Aufgabe ist, die in einer Basisklasse ausgeführt wird.


Wenn Sie eine Möglichkeit benötigen, das Standardgebietsschema später wiederherzustellen, oder wenn Sie eine Spracheinstellung benötigen, die eine Liste von Sprachen enthält, und wenn Sie das Gebietsschema bequemer ändern möchten, kann dies hilfreich sein: github.com/delight-im/Android -Sprachen
caw

Antworten:


114

Für Personen, die immer noch nach dieser Antwort suchen configuration.locale, können Sie jetzt Folgendes verwenden, da sie von API 24 nicht mehr unterstützt wird:

configuration.setLocale(locale);

Beachten Sie, dass die minSkdVersion für diese Methode API 17 ist.

Vollständiger Beispielcode:

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

Vergessen Sie nicht, dass Sie das Gebietsschema, wenn Sie eine laufende Aktivität ändern, neu starten müssen, damit die Änderungen wirksam werden.

BEARBEITEN 11. MAI 2018

Ab dem Beitrag von @ CookieMonster haben Sie möglicherweise Probleme, die Gebietsschemaänderung in höheren API-Versionen beizubehalten. Wenn ja, fügen Sie Ihrer Basisaktivität den folgenden Code hinzu, damit Sie das Kontextgebietsschema bei jeder Aktivitätserstellung aktualisieren:

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

Wenn Sie dies verwenden, vergessen Sie nicht, die Sprache in SharedPreferences zu speichern, wenn Sie das Gebietsschema mit festlegen setLocate(locale)

EDIT 7. APRIL 2020

Möglicherweise treten Probleme in Android 6 und 7 auf. Dies liegt an einem Problem in den AndroidX-Bibliotheken, während der Nachtmodus ausgeführt wird. Dazu müssen Sie auch applyOverrideConfigurationIhre Basisaktivität überschreiben und das Gebietsschema der Konfiguration aktualisieren, falls ein neues Gebietsschema erstellt wird.

Beispielcode:

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

2
Dies funktioniert für Aktivitäten, aber gibt es eine Möglichkeit, den Anwendungskontext zu aktualisieren?
Alekop

2
Nach dem Wechsel androidx.appcompat:appcompat:Version von 1.0.2zu 1.1.0nicht auf Android 7 arbeiten, aber arbeitet an Android 9.
Bek

4
Das gleiche Problem für mich und 1.1.0Androidx
Alexander Dadukin

2
Gleiches Problem für mich. Nachdem ich zu androidx.appcompat gewechselt habe: appcompat: 1.1.0 'lib
Rahul Jidge

4
Problem mit appcompat:1.1.0kann behoben werden appcompat:1.2.0-alpha02und Code im 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));Inneren@TargetApi(Build.VERSION_CODES.N) updateResourcesLocale()
Vojtech Pohl

178

Hoffe diese Hilfe (in onResume):

Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
      getBaseContext().getResources().getDisplayMetrics());

2
Das muss also für jede Aktivität eingestellt werden?
Tobias

6
1. Es ist obligatorisch, getBaseContext () zu verwenden, oder sollte besser der Anwendungskontex verwendet werden? 2. Dieser Code sollte in jeder Aktivität aufgerufen werden? Vielen Dank.
Paul

10
Ich habe diesen Code in onCreate () meiner Launcher-Aktivität (und nirgendwo anders) platziert und war angenehm überrascht zu sehen, dass das Gebietsschema für die gesamte App gilt. Dies ist in einer App für 4.3 mit einem minSDK von 14 (ICS) vorgesehen.
IAmKale

8
Es ist nicht erforderlich, ein neues Konfigurationsobjekt zu erstellen. Sie können die aktuelle Konfiguration verwenden und aktualisieren: getResources (). GetConfiguration ()
jmart

1
benutze keine neue Konfiguration ();, es ändert textAppearance, fontSize
Jemshit Iskenderov

22

Ich hatte ein Problem beim programmgesteuerten Festlegen des Gebietsschemas mit Geräten mit Android OS N und höher . Für mich bestand die Lösung darin, diesen Code in meine Basisaktivität zu schreiben:

(Wenn Sie keine Basisaktivität haben, sollten Sie diese Änderungen in all Ihren Aktivitäten vornehmen.)

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

Beachten Sie, dass es hier nicht ausreicht, anzurufen

createConfigurationContext(configuration)

Sie müssen auch den Kontext abrufen, den diese Methode zurückgibt, und diesen Kontext dann in der attachBaseContextMethode festlegen .


Dies ist die einfachste und funktionierendste Lösung! Dies sollte die akzeptierte Antwort sein.
Prasad Pawar

3
Dieser Code funktioniert sehr gut auf Android über 7, aber in Versionen unter N funktioniert nicht. Hast du irgendwelche Lösungen?
Matin Ashtiani

Ich bin mir nicht sicher, weil es bei mir funktioniert. Möchten Sie mir Ihre Implementierung senden, damit ich einen Blick darauf werfen kann?
CookieMonster

2
Funktioniert nicht in Versionen unter Android N, da resources.updateConfiguration in onCreate () anstelle von attachBaseContext () aufgerufen werden muss
Chandler

@ Handler ist richtig. Rufen Sie für Android 6 die updateBaseContextLocaleMethode onCreateIhrer Eltern- / Basisaktivität auf.
Azizjon Kholmatov

22

Da für den aktuellen Weg zur Lösung dieses Problems keine Antwort vollständig ist, versuche ich, Anweisungen für eine vollständige Lösung zu geben. Bitte kommentieren Sie, wenn etwas fehlt oder besser gemacht werden könnte.

Allgemeine Information

Erstens gibt es einige Bibliotheken, die das Problem lösen möchten, aber alle scheinen veraltet zu sein oder es fehlen einige Funktionen:

Außerdem denke ich, dass das Schreiben einer Bibliothek möglicherweise keine gute / einfache Möglichkeit ist, dieses Problem zu lösen, da nicht viel zu tun ist und der vorhandene Code eher geändert werden muss, als etwas vollständig Entkoppeltes zu verwenden. Deshalb habe ich die folgenden Anweisungen verfasst, die vollständig sein sollten.

Meine Lösung basiert hauptsächlich auf https://github.com/gunhansancar/ChangeLanguageExample (wie bereits von localhost verlinkt ). Es ist der beste Code, an dem ich mich orientieren konnte. Einige Anmerkungen:

  • Bei Bedarf werden verschiedene Implementierungen bereitgestellt, um das Gebietsschema für Android N (und höher) und darunter zu ändern
  • updateViews()In jeder Aktivität wird eine Methode verwendet , um alle Zeichenfolgen nach dem Ändern des Gebietsschemas (unter Verwendung des üblichen getString(id)) manuell zu aktualisieren, was bei dem unten gezeigten Ansatz nicht erforderlich ist
  • Es werden nur Sprachen und keine vollständigen Gebietsschemas unterstützt (einschließlich Regions- (Land) und Variantencodes).

Ich habe es ein wenig geändert und den Teil entkoppelt, der das ausgewählte Gebietsschema beibehält (da man dies möglicherweise separat tun möchte, wie unten vorgeschlagen).

Lösung

Die Lösung besteht aus den folgenden zwei Schritten:

  • Ändern Sie dauerhaft das Gebietsschema, das von der App verwendet werden soll
  • Lassen Sie die App das benutzerdefinierte Gebietsschemaset verwenden, ohne es neu zu starten

Schritt 1: Ändern Sie das Gebietsschema

Verwenden Sie die Klasse LocaleHelper, die auf gunhansancars LocaleHelper basiert :

  • Fügen Sie ein ListPreferencein a PreferenceFragmentmit den verfügbaren Sprachen hinzu (muss beibehalten werden, wenn Sprachen später hinzugefügt werden sollen)
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;
    }
}

Erstellen Sie SettingsFragmentwie folgt:

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

Erstellen Sie eine Ressource, locales.xmlin der alle Gebietsschemas mit verfügbaren Übersetzungen wie folgt aufgelistet sind ( Liste der Gebietsschemacodes ):

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

In Ihrem können PreferenceScreenSie den folgenden Abschnitt verwenden, damit der Benutzer die verfügbaren Sprachen auswählen kann:

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

Dabei werden die folgenden Zeichenfolgen verwendet 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>

Schritt 2: Lassen Sie die App das benutzerdefinierte Gebietsschema verwenden

Richten Sie nun jede Aktivität so ein, dass das benutzerdefinierte Gebietsschemaset verwendet wird. Der einfachste Weg, dies zu erreichen, besteht darin, eine gemeinsame Basisklasse für alle Aktivitäten mit dem folgenden Code zu haben (wobei sich der wichtige Code in attachBaseContext(Context base)und befindet 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();
        }
    }
}

Was es tut ist

  • Überschreiben attachBaseContext(Context base), um das zuvor beibehaltene Gebietsschema zu verwendenLocaleHelper
  • Erkennen Sie eine Änderung des Gebietsschemas und erstellen Sie die Aktivität neu, um die Zeichenfolgen zu aktualisieren

Hinweise zu dieser Lösung

  • Durch das erneute Erstellen einer Aktivität wird der Titel der Aktionsleiste nicht aktualisiert (wie hier bereits erwähnt: https://github.com/gunhansancar/ChangeLanguageExample/issues/1 ).

    • Dies kann durch einfach ein mit erreicht werden setTitle(R.string.mytitle)in dem onCreate()Verfahren jeder Aktivität.
  • Hiermit kann der Benutzer das Standardgebietsschema des Systems sowie das Standardgebietsschema der App auswählen (das benannt werden kann, in diesem Fall "Englisch").

  • fr-rCABisher werden nur Sprachcodes, keine Region (Land) und Variantencodes (wie ) unterstützt. Zur Unterstützung der vollständigen Gebietsschemaspezifikationen kann ein Parser verwendet werden, der dem in der Android-Languages-Bibliothek ähnelt (der Regions-, aber keine Variantencodes unterstützt).

    • Wenn jemand einen guten Parser findet oder geschrieben hat, fügen Sie einen Kommentar hinzu, damit ich ihn in die Lösung aufnehmen kann.

1
Ausgezeichnet, aber König des Alptraums
Odys

1
Zur Hölle, nein, meine App ist bereits zu komplex. Dieser Ansatz wäre ein Albtraum, um ihn in Zukunft beizubehalten.
Josh

@ Josh Kannst du das etwas näher erläutern? Tatsächlich müssen jeder verwendeten Aktivitätsbasisklasse nur wenige Zeilen hinzugefügt werden. Ich sehe, dass es möglicherweise nicht möglich ist, für alle Aktivitäten dieselbe Basisklasse zu verwenden, aber auch größere Projekte sollten mit einigen auskommen können. Aspektorientierte Programmierung könnte hier helfen, aber Komposition (Verschieben des Codes von attachBaseContext(Context base)und onResume()in eine separate Klasse) kann den Trick tun. Dann müssen Sie nur noch ein Objekt in jeder Aktivitätsbasisklasse deklarieren und diese beiden Aufrufe delegieren.
user905686

Wenn der Benutzer sein Gebietsschema ändert, kann das Gebietsschema aller vorherigen Aktivitätsseiten auch geändert werden?
Raju yourPepe

Dies ist die beste Antwort zu diesem Thema. Danke Bruder, es funktioniert
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);
    }
}

Verwenden Sie einfach diese Hilfsmethode, um ein bestimmtes Gebietsschema zu erzwingen.

UDPATE 22 AUG 2017. Verwenden Sie diesen Ansatz besser .


4

Fügen Sie eine Hilfsklasse mit der folgenden Methode hinzu:

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

    }
}

Und nennen Sie es in Ihrer Startaktivität wie MainActivity.java:

public void onCreate(Bundle savedInstanceState) {
    ...
    LanguageHelper.setAppLocale("fa", this);
    ...
}

3

simpel und einfach

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

Dabei ist "en" der Sprachcode und "US" der Ländercode.


Wie in meinem Beitrag angegeben, conf.locale=locale;ist veraltet und ist es auch updateConfiguration.
Ricardo

sehr einfach und weniger kompliziert :)
Ramkesh Yadav

2

Gültig für API16 bis API28 Platzieren Sie diese Methode einfach an einer Stelle, an der:

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

Fügen Sie diesen Code in alle Ihre Aktivitäten ein, indem Sie:

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

oder rufen Sie localeUpdateResources für Fragmente, Adapter usw. auf, in denen Sie den neuen Kontext benötigen.

Credits: Jaroslaw Berezanskyi


2

Es gibt einen super einfachen Weg.

In BaseActivity überschreiben Activity oder Fragment attachBaseContext

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

Erweiterung

fun Context.changeLocale(language:String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = this.resources.configuration
    config.setLocale(locale)
    return createConfigurationContext(config)
}

2

Ich fand den androidx.appcompat:appcompat:1.1.0Fehler kann auch einfach durch Aufruf fixiert werden getResources()inapplyOverrideConfiguration()

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

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

1

Für diejenigen, die alles versucht haben, aber nicht funktionieren . Bitte überprüfen Sie, dass , wenn Sie setzen darkmodemit AppCompatDelegate.setDefaultNightModeund das System nicht dunkel ist, dann Configuration.setLocalewird nicht funktionieren über Andorid 7.0 .

Fügen Sie diesen Code in jede Aktivität ein, um dieses Problem zu lösen:

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
  if (overrideConfiguration != null) {
    val uiMode = overrideConfiguration.uiMode
    overrideConfiguration.setTo(baseContext.resources.configuration)
    overrideConfiguration.uiMode = uiMode
  }
  super.applyOverrideConfiguration(overrideConfiguration)
}

-1

Fügen Sie diesen Code in Ihre Aktivität ein

 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();
    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.