Android : forcer la langue utilisée par l'application (même sous Oreo)
Il est toujours intéressant de proposer à vos utilisateurs de pouvoir choisir la langue utilisée par l'application. Dans cet article, nous verrons comment réaliser cela dans une application Android (via Xamarin) et comment migrer vers les nouvelles APIs Oreo.
Avant les API 24 (Code N)
Traditionnellement, forcer la langue est quelque chose d'assez simple à mettre en place puisqu'il suffit de mettre à jour la configuration de vos ressources.
On créé d'abord un objet Locale auquel on fournit le code de la lange à utiliser, on assigne cette locale comme valeur par défaut, puis on demande la mise à jour de le configuration des ressources via ce code :
var language = "fr"; // par exemple var locale = new Locale(language); Locale.Default = locale; var config = new Android.Content.Res.Configuration { Locale = locale }; var context = Application.Context; context.Resources .UpdateConfiguration(config, context.Resources.DisplayMetrics);
À partir des APIs 24 (et obligatoirement à partir d'Oreo)
Seulement voilà, à partir de Nougat, de nouvelles APIs remplacent cette manière de faire, qui devient complètement inopérante sous Oreo.
Il convient donc de procéder de cette manière :
- Créer ou obtenir une configuration Android.Content.Res.Configuration,
- À partir d'une instance de Context, créer un "Contexte de configuration",
- Créer un wrapper (la classe ContextWrapper du SDK) autour de ce contexte,
- Utiliser ce wrapper dans vos différentes activités en surchargeant la méthode AttachBaseContext.
L'obtention du wrapper passe donc via ce code :
var config = input.Resources.Configuration; config.Locale = new Locale(language); var wrapper = new ContextWrapper( input.CreateConfigurationContext(config)); input.Resources.Configuration.Locale = new Locale(language); return wrapper;
Et dans vos activités, surchargez AttachBaseContext de cette manière (je passe par un utilitaire de mon cru nommé AndroidLanguageSetterServiceService.WrapContext ici) :
protected override void AttachBaseContext( Android.Content.Context @base) { base.AttachBaseContext( AndroidLanguageSetterServiceService.WrapContext(@base)); }
Ne pas oublier...
Attention, il est important de s'assurer que vous n'utilisez pas la propriété BaseContext de vos activités, sans quoi vous obtiendrez des erreurs difficiles à débugger (on ne trouve rien sur StackOverflow !).
Java.Lang.RuntimeException: Binary XML file line #1: Binary XML file line #1: Error inflating class <unknown> ---> Java.Lang.RuntimeException: Binary XML file line #1: Error inflating class <unknown> ---> Java.Lang.ReflectiveOperationException: Exception of type 'Java.Lang.ReflectiveOperationException' was thrown. ---> Java.Lang.UnsupportedOperationException: Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x7f01017a a=-1} --- End of inner exception stack trace --- --- End of inner exception stack trace --- --- End of inner exception stack trace ---
Pour solutionner ce problème, il suffit d'utiliser la propriété Context de vos activités.
Happy coding !
Commentaires