J'ai une application multilingue avec l'anglais comme langue principale et l'arabe comme langue secondaire.
J'appelle setLocale()
dans la onCreate()
de chaque Activity
dans mon application:
public static void setLocale(Locale locale){
Locale.setDefault(locale);
Context context = MyApplication.getInstance();
final Resources resources = context.getResources();
final Configuration config = resources.getConfiguration();
config.setLocale(locale);
context.getResources().updateConfiguration(config,
resources.getDisplayMetrics());
}
où locale
est l'un des éléments suivants:
La méthode ci-dessus est appelée avant que super.onCreate(savedInstanceState)
soit appelé.
Comme décrit dans le documentation ,
Android:supportsRtl="true"
dans le manifeste.left
et right
en start
et end
name__.res\values-ar\strings
et des ressources pouvant être extraites dans le dossier res\drawable-ar
(et de la même manière pour d'autres ressources).La configuration ci-dessus fonctionne correctement. Une fois que Locale
a été remplacé par ar-AE
, le texte et les ressources arabes sont correctement affichés dans mes activités.
Toutefois, il existe un problème de ressources et de mise en forme pour tous les appareils Android dotés de la version 8.0 et des versions supérieures.
Sur un appareil avec une version inférieure à 8.0, un écran RTL correctement ressemble à ceci:
Et sur tous les appareils avec 8.0+, le même écran apparaît comme suit:
qui est faux .
Il se trouve que la direction et les ressources s'affichent de manière incorrecte.
Il y a deux problèmes ici:
Locale
correct ne semble pas être mis à jour dans la configuration de l'application.En ce qui concerne la direction, une méthode curieuse appelée setLayoutDirection()
existe que je n'avais pas remarquée auparavant.
J'aimerais savoir en quoi consiste ce problème, pourquoi cela se produit à Oreo et quelle est la solution. S'il vous plaît aider/commenter sur ce.
EDIT:
Selon le rapport Différences d'API , la méthode
updateConfiguration()
était en effet déconseillée dans Android 7.1 (niveau 25 de l'API).
En outre, trouvé tous les messages pertinents à ce sujet. Par ordre d'importance:
1. Android N change de langue par programmation .
2. Android context.getResources.updateConfiguration () obsolète .
3. Comment changer la langue d’application Android O/Oreo/api 26 .
5. Changer de langue par programme (Android N 7.0 - API 24) .
6. Android N - Modifier les paramètres régionaux au moment de l'exécution .
La méthode updateConfiguration()
était obsolète
Maintenant nous devons utiliser createConfigurationContext()
J'ai réussi de cette façon
créer une nouvelle classe
ContextWrapper
import Android.content.Context;
import Android.content.res.Configuration;
import Android.content.res.Resources;
import Android.os.Build;
import Android.os.LocaleList;
import Java.util.Locale;
public class ContextWrapper extends Android.content.ContextWrapper {
public ContextWrapper(Context base) {
super(base);
}
public static ContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new ContextWrapper(context);
}}
créer une nouvelle classe de
BaseActivity
import Android.content.Context;
import Android.support.v7.app.AppCompatActivity;
import Java.util.Locale;
/**
* Created by nilesh on 20/3/18.
*/
public class BaseActivity extends AppCompatActivity {
@Override
protected void attachBaseContext(Context newBase) {
Locale newLocale;
String lang = new PrefManager(newBase).getLanguage();
if (lang.equals("zh_CN")) {
newLocale = new Locale("zh");
} else {
newLocale = new Locale(lang);
}
Context context = ContextWrapper.wrap(newBase, newLocale);
super.attachBaseContext(context);
}
}
Créer une classe
PrefManager
pour stocker les paramètres régionaux
import Android.content.Context;
import Android.content.SharedPreferences;
public class PrefManager {
private SharedPreferences.Editor editor;
private Context mContext;
private SharedPreferences prefs;
private final String LANGUAGE = "language";
private final String PREF = "user_data";
public PrefManager(Context mContext) {
this.mContext = mContext;
}
public String getLanguage() {
this.prefs = this.mContext.getSharedPreferences(PREF, 0);
return this.prefs.getString(LANGUAGE, "en_US");
}
public void setLanguage(String language) {
this.editor = this.mContext.getSharedPreferences(PREF, 0).edit();
this.editor.putString(LANGUAGE, language);
this.editor.apply();
}
}
Maintenant, vous devez étendre votre BaseActivity à toutes vos activités, comme
public class OrdersActivity extends BaseActivity
Maintenant, lorsque vous avez besoin de changer
Locale
, il suffit de mettre à jour la valeur dansPrefManager
et de relancer votre activité.
PrefManager prefManager= new PrefManager(this);
prefManager.setLanguage("zh_CN");
// restart your activity
La méthode Resources#updateConfiguration (Configuration config, DisplayMetrics metrics)
est obsolète dans l'API de niveau 25.
La doc suggère d'utiliser Context#createConfigurationContext (Configuration overrideConfiguration)
Vous pouvez simplement créer une activité de base qui est un parent commun de toutes les activités décrites ci-dessous.
public class BaseActivity
extends AppCompatActivity {
private static final String LANGUAGE_CODE_ENGLISH = "en";
private static final String LANGUAGE_CODE_ARABIC = "ar";
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(CommonUtils.getLanguageAwareContext(newBase));
}
private static Context getLanguageAwareContext(Context context) {
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(new Locale(getLanguageCode));
return context.createConfigurationContext(configuration);
}
// Rewrite this method according to your needs
private static String getLanguageCode() {
return LANGUAGE_CODE_ARABIC;
}
}
getLanguageCode()
devrait retourner le code de langue. Généralement, le code de langue ou toute autre donnée le représentant est stocké dans les préférences.this
ou ActivityName.this
à partir d'activités et getActivity()
à partir de fragments au lieu de getApplicationContext()
.Resources.updateConfiguration est obsolète, utilisez plutôt ceci:
fun setLocale(old: Context, locale: Locale): Context {
val oldConfig = old.resources.configuration
oldConfig.setLocale(locale)
return old.createConfigurationContext(oldConfig)
}
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase?.let { setLocale(it, Locale("ar")) })
}
En java
private Context setLocale(Context old, Locale locale) {
Configuration oldConfig = old.getResources().getConfiguration();
oldConfig.setLocale(locale);
return old.createConfigurationContext(oldConfig);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(setLocale(newBase, new Locale("ar")));
}
Totalement fermé l'application parce que je pense qu'il fait le cache en arrière-plan.
Utilisez le code ci-dessous et voici comment je l'ai réalisé dans mon cas. Vous pouvez également l'essayer:
Intent mStartActivity = new Intent(ctc, SplashActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(ctc, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)ctc.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
public void setLocale(final Context ctx, final String lang) {
AppSettings.getInstance(ctx).save(PrefKeys.language, lang);
final Locale loc = new Locale(lang);
Locale.setDefault(loc);
final Configuration cfg = new Configuration();
cfg.locale = loc;
ctx.getResources().updateConfiguration(cfg, null);
}
Changer en anglais: setLocale(getActivity(), "en";
Changer en arabe: setLocale(getActivity(), "ar");
Après cela, vous devez redémarrer l'application pour obtenir les effets de changement de langue.