Question

Mon application prend en charge 3 (bientôt 4) langues.Depuis plusieurs paramètres régionaux sont assez similaires, je tiens à donner à l'utilisateur la possibilité de modifier les paramètres régionaux dans mon application, par exemple une personne italienne pourrait préférer espagnol en plus de l'anglais.

Est-il un moyen pour l'utilisateur de choisir parmi les paramètres régionaux disponibles pour l'application, puis de changer ce qui locale est utilisée?Je ne vois pas cela comme un problème pour définir les paramètres régionaux pour chaque Activité, car elle est une tâche simple à réaliser dans une classe de base.

Était-ce utile?

La solution

Pour les personnes recherchées toujours cette réponse, car configuration.locale a été obsolète d'API 24, vous pouvez maintenant utiliser:

configuration.setLocale(locale);

Prenez en considération que la MINSKDVersion pour cette méthode est l'API 17.

Exemple complet Code:

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

N'oubliez pas que si vous modifiez les paramètres régionaux avec une activité en cours d'exécution, vous devrez le redémarrer pour que les modifications prennent effet.

Modifier le 11 mai 2018

A partir de @ Cookiemonster's Post, vous pourriez avoir des problèmes de conserver le changement de localisation dans les versions d'API supérieures.Si tel est le cas, ajoutez le code suivant à votre activité de base afin de mettre à jour le contexte locale sur chaque création d'activité:

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

Si vous utilisez ceci, n'oubliez pas de sauvegarder la langue sur SharedPreferences lorsque vous définissez les paramètres régionaux avec setLocate(locale)

Autres conseils

J'espère que cette aide (à ONRESUME):

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

Comme aucune réponse n'est complet pour la manière de résoudre ce problème, j'ai essayer de donner des instructions pour une solution complète.S'il vous plaît commentaire si quelque chose est manquant ou pourrait faire mieux.

Informations générales

D'abord, il existe des bibliothèques qui veulent résoudre le problème, mais ils semblent tous obsolètes ou manquantes certaines caractéristiques:

De plus je pense que l'écriture d'une bibliothèque ne peut pas être un bon/moyen facile de résoudre ce problème, car il n'y a pas beaucoup à faire, et ce qui doit être fait, c'est plutôt l'évolution actuelle du code de l'aide de quelque chose de complètement découplés.Donc j'ai composé les instructions suivantes qui doit être complète.

Ma solution est basée principalement sur l' https://github.com/gunhansancar/ChangeLanguageExample (comme déjà liés par localhost).C'est le meilleur code que j'ai trouvé pour vous orienter au.Quelques remarques:

  • En tant que de besoin, il fournit des implémentations différentes pour modifier les paramètres régionaux pour Android N (et ci-dessus) et ci-dessous
  • Il utilise une méthode de updateViews() dans chaque Activité, pour mettre à jour manuellement toutes les chaînes après la modification des paramètres régionaux (à l'aide de l'habitude getString(id)) qui n'est pas nécessaire dans l'approche présentée ci-dessous
  • Il prend uniquement en charge les langues et ne pas compléter locales (qui incluent également la région (pays) et de la variante de codes)

Je l'ai changé un peu, le découplage de la partie qui persiste le code choisi (comme on peut avoir envie de le faire séparément, comme indiqué ci-dessous).

Solution

La solution se compose de deux étapes suivantes:

  • Modifier de façon permanente les paramètres régionaux à être utilisé par l'application
  • Faire de l'app, la coutume locale définie, sans redémarrer

Étape 1:Modifier les paramètres régionaux

Utiliser la classe LocaleHelper, basé sur gunhansancar de LocaleHelper:

  • Ajouter un ListPreference dans un PreferenceFragment avec les langues disponibles (doit être maintenue lorsque des langues devrait être ajouté plus tard)
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;
    }
}

Créer un SettingsFragment comme suit:

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

Créer une ressource locales.xml liste de tous les paramètres régionaux avec les traductions de la façon suivanteliste des codes de paramètres régionaux):

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

Dans votre PreferenceScreen vous pouvez utiliser la section suivante pour permettre à l'utilisateur de sélectionner la langue disponible:

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

qui utilise les chaînes de caractères suivantes à partir de 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>

Étape 2:Faire de l'app, la coutume locale

Maintenant, le programme d'installation de chaque Activité à utiliser l'outil de localisation.La façon la plus simple d'y parvenir est d'avoir une classe de base commune pour toutes les activités avec le code suivant (où le code est en attachBaseContext(Context base) et 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();
        }
    }
}

Ce qu'il fait est

  • Remplacer attachBaseContext(Context base) pour utiliser les paramètres régionaux déjà persistante avec LocaleHelper
  • Détecter un changement de la localisation et de recréer de l'Activité de mise à jour de ses cordes

Notes sur cette solution

  • Recréer une Activité n'est pas mise à jour le titre de l'ActionBar (comme indiqué ici: https://github.com/gunhansancar/ChangeLanguageExample/issues/1).

    • Ceci peut être réalisé simplement en ayant un setTitle(R.string.mytitle) dans le onCreate() méthode de chaque activité.
  • Il permet à l'utilisateur choisi les paramètres régionaux système par défaut, ainsi que les paramètres régionaux par défaut de l'application (ce qui peut être nommé, dans ce cas, "anglais").

  • Seuls les codes de langue, pas de région (pays) et de la variante de codes (comme fr-rCA) sont pris en charge jusqu'à présent.À l'appui de plein de paramètres régionaux de spécifications, un analyseur syntaxique similaire à celui de la Android-Langues de la bibliothèque peut être utilisé (prise en charge de la région, mais aucune variante de codes).

    • Si quelqu'un trouve ou qu'elle a écrit un bon analyseur, ajouter un commentaire afin que je puisse l'inclure dans la solution.

J'ai eu un problème avec la définition des paramètres régionaux par programmation avec des appareils qui a Android OS N et supérieur.Pour moi la solution a été écrit ce code dans ma base de l'activité:

(si vous n'avez pas de base de l'activité, alors vous devriez faire ces changements sur l'ensemble de vos activités)

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

notez qu'ici, il ne suffit pas d'appeler

createConfigurationContext(configuration)

vous devez également obtenir le contexte de cette méthode retourne et ce dans le contexte attachBaseContext la méthode.

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

Utilisez simplement cette méthode d'assistance pour forcer les paramètres régionaux spécifiques.

UDPate 22 août 2017. Meilleure utilisation Cette approche . .

Ajouter une classe d'assistance avec la méthode suivante:

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

    }
}

Et de l'appeler dans votre démarrage d'activité, comme MainActivity.java:

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

simple et facile

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

où "fr" est le code de langue et "nous" est le code de pays.

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

Il y a une manière super simple.

dans la base de la fabrique, de l'activité ou du fragment de dérogation Attachsecontext

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

extension

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

Valable pour API16 à API28 Il suffit de placer cette méthode certains où:

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

Insérez ce code dans toutes vos activités en utilisant:

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

ou appelez LocaleUpdaterSources sur des fragments, des adaptateurs, etc. Lorsque vous avez besoin du nouveau contexte.

Crédits: Yaroslav Berezanskyi

mettre ce code dans votre activité

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top