Définir les paramètres Régionaux par programmation
-
13-11-2019 - |
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.
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.
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:
- https://github.com/delight-im/Android-Languages
- Dépassées (voir questions)
- Lors de la sélection d'une langue de l'INTERFACE utilisateur, toujours, il affiche toutes les langues (codé en dur dans la bibliothèque), et pas seulement ceux où il existe des traductions
- https://github.com/akexorcist/Android-LocalizationActivity
- Semble assez sophistiquée et peut utiliser une approche similaire comme indiqué ci-dessous
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'habitudegetString(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 unPreferenceFragment
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 avecLocaleHelper
- 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 leonCreate()
méthode de chaque activité.
- Ceci peut être réalisé simplement en ayant un
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
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"))
}
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();
}