Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

UWP : localisation, savoir dans quelle langue marche l’App

Je vous ai présenté il y a peu le kit de traduction pour applications UWP. C’est magique… Mais comment l’application peut-elle savoir dans quelle langue elle fonctionne ?

Tout automatique !

Avec le kit de traduction (voir l’article UWP Localisation des Apps) tout se fait automatiquement. Je parle du runtime et non de la mise en œuvre qui peut s’avérer un peu lourde, mais typique des procédés de ce type.

C’est l’OS qui décide de la langue à utiliser en fonction des paramètres de l’utilisateur. L’App est lancée et les ressources traduites apparaissent automatiquement dans la bonne langue.

Cela fonctionne à merveille.

Mais parfois l’App a besoin de savoir dans quelle langue elle tourne. J’ai montré comment on peut interroger le système de traduction dans le code, ce qui fait que théoriquement l’App n’a pas besoin de connaitre la langue en cours puisque même par code elle obtient toujours la bonne ressource (texte en général, mais aussi les images par exemple).

Décrocher de l’automatisme

Mais supposons que pour milles raisons qui nous échappent l’App ait tout de même besoin de savoir dans quelle langue elle fonctionne. Imaginons qu’une couleur utilisée dans l’UI par exemple ne soit pas la même selon la langue. Il a plusieurs façon de faire, comme toujours, ici on pourrait mettre dans un champ traduit le nom de la couleur qui serait donc traduit une fois en “rouge”, une autre en “vert”, etc. On obtiendrait bien une couleur différente (et prédéfinie) pour chaque langue.

Mais stocker un nom de couleur oblige à le transformer en Color via un parse. Et que dire s’il ne s’agit pas d’une couleur “nommée” mais d’une couleur uniquement définissable par ses composantes ? Cela commence à compliquer fortement les choses.

Ne serait-il pas plus simple d’avoir une propriété dans l’application qui contienne le nom ou un code pour la langue en cours peu importe ce qu’on en fait ensuite (choisir une couleur comme l’exemple ci-dessus ou n’importe quoi d’autre) ?

Ce qu’on aimerait c’est pouvoir détecter cette langue d’UI, non pas via le thread courant, non pas depuis les réglages de l’OS, mais en fonction de la langue affichée par notre application.

Langue de l’App et non celle de l’utilisateur, nuance

Pourquoi choisir cette source d’information alors qu’on le voit d’autres possibilités existent ?

Parce que votre App ne va certainement pas supporter toutes les variantes de toutes les langues du monde pour commencer. De fait entre le français canadien ou le français “bien d’chez nous” il a peu de chance que vous vous amusiez à faire une traduction, les québécois nos cousins de l’aut’ côté de la grande marre savent lire le français (ils ajoutent l’accent dans leur tête !) . Votre App gèrera le “fr” tout court, pas ses variantes.

Et puis il y a toutes les chances aussi que vous ne gériez pas le hongrois ou le zoulou, aussi belles soient ces langues certainement. Et là votre App ne voyant aucune traduction pour ces langues utilisera la langue “neutre” que vous aurez indiquée en la créant.

C’est pour cela entre autre que je préfère indiquer l’anglais comme neutre et ajouter le français ensuite. Pourquoi ? parce que justement, un gentil zoulou qui utilisa l’App ne disposera pas d’une traduction dans sa langue (et je m’en excuse auprès de tous les zoulous) et que l’App tournera donc dans sa langue par défaut…

Si l’App est conçue avec le français par défaut, ce qui serait logique dans notre pays, hélas c’est dans ce mode qu’elle apparaitra donc à tous les étrangers qui n’ont pas la chance d’avoir une traduction pour leur langue… Ainsi le zoulou ou le hongrois tomberont sur une appli en français…

Certes les français fut longtemps la langue universelle, celle des scientifiques et tout ça. Mais ça c’était avant… Aujourd’hui c’est l’anglais qui tient ce rôle. Et il est donc préférable que la langue par défaut soit l’anglais…

On le voit bien ici, la langue de l’App n’est donc pas forcément celle du thread courant ou celle des réglages de l’OS, mais parfois celle qui est considérée comme “neutre” par votre application.Et si des décisions doivent être prises en fonction de la langue, c’est cette langue là qui est intéressante.

Du coup votre App ne peut pas se reposer sur les infos système pour faire des traitements qui dépendraient de la langue en cours (comme mon exemple de couleur plus haut).

Ce qu’on veut obtenir en réalité c’est la langue dans laquelle fonctionne l’App. Rien d’autre.

Tester la langue de l’App

Je n’ai pas trouvé de moyen direct de savoir dans quelle langue le système de traduction affiche les ressources, si vous le trouvez n’hésitez pas à le dire ! Il affiche les ressources traduites, ou les neutres, il le fait bien, automatiquement, mais on ne sait pas ce qu’il fait.

Dans la majorité des Apps cela sera parfait. Mais comme pour mon exemple de couleur définie au runtime en fonction de la langue, il peut exister des cas sournois où connaitre la langue de l’App est utile.

L’astuce est simple mais il faut y penser : Il suffit de choisir un objet toujours affiché et de traduire sa propriété Tag.

J’explique : un objet toujours affiché, le mieux c’est de choisir l’objet fenêtre lui-même. On est sûr qu’il est affiché et tout de suite. Mais on peut choisir un User Control (s’il joue le rôle de Shell par exemple).

Traduire sa propriété Tag signifie qu’on va lui ajouter une propriété x:Uid=”machin” et que “machin” va être ajouté aux chaînes à traduire sous la forme “machin.Tag” (voir l’article sur la traduction vous comprendrez mieux j’en suis certain !).

Se raccorder à l’automatisme

Maintenant que cela est fait, le Tag de la fenêtre sera traduit automatiquement… Et on raccroche les wagons à l’automatisme qui nous gênait au départ en l’utilisant pour notre propre compte !

Dans le Main ViewModel il suffira d’aller lire la valeur de ce Tag et de la stocker dans un endroit propre accessible à tous les ViewModels de l’appli.

Les puristes de MVVM auront des convulsions, car accéder à un objet d’UI c’est très mal ! Mais cela dépend comment vous le faites…

De façon directe dans le constructeur du VM principal il suffit de demander à la fenêtre principale son Tag. Franchement cela ne rendra pas votre application horrible pour autant. C’est ponctuel et l’objet d’UI n’est pas à proprement parlé “manipulé”, ses propriétés ne sont pas changées. Et puis que dans une application on puisse avoir connaissance de la classe mère de la fenêtre principale… Ne soyons pas hypocrites c’est une classe sans laquelle votre application ne pourra pas marcher et qui n’est pas remplaçable… Mais les puristes crieront que c’est vraiment pas bien. Chacun fait comme il l’entend et je ne jugerai pas. Tout extrémisme est à mon sens dangereux et toute philosophie qui devient un dogme est un frein à l’intelligence. Mais soit.

En revanche comme je le disais plus haut, cette valeur doit être stockée dans un endroit propre qui puisse être ensuite consulté par tous les VM sans accéder à l’objet fenêtre principal. Ne pas être hypocrite ne doit pas être la porte ouverte à n’importe quoi non plus… C’est le vieux débat “l’éthique vs la morale” qui vient s’inviter dans la technique !

Mais si vous voulez absolument une méthode garantie 100% MVVM agréée par les ministres du culte : dans le code-behind de la fenêtre principale, dans son évènement Loaded (pour que la traduction ait eu le temps d’être renseignée), vous envoyez un message MVVM avec la valeur du Tag. Enregistrez un récepteur pour ce message, par exemple un service répertorié par le conteneur IoC par lequel passeront les VM ou autres qui voudront lire la valeur. Et voilà. C’est hypocrite mais totalement découplé Sourire en plus vous passerez pour un expert de MVVM.

Entre récupération directe ou découplée de la valeur l’important c’est d’obtenir cette dernière, le reste est affaire principalement de budget. Le mieux c’est plus cher. Tout le monde est d’accord sur ce point … tant que ce “tout monde” n’a pas à le financer, car là bizarrement le “mieux” devient alors une notion très discutable sauf s’il est gratuit !

La Version simple

Bien entendu il y a encore plus simple...

Dès lors qu'on s'embarque dans le respect de MVVM avec message, service etc, la solution du Tag traduit ne tient plus la route. Dans ce cas il est préférable d'interroger directement la ressource "machin" qui n'est reliée à aucun élément d'UI et de lire son contenu qui sera donc forcément traduit. Ici pas de violation de MVVM et pas de code artificiel.

La solution du Tag est intéressante uniquement si on n'est pas trop regardant sur MVVM. Dans ce cas lire un Tag ou interroger par code une ressource est parfaitement identique.

A chacun de voir, finalement peu importe la façon de faire la véritable astuce se trouve bien dans la création d'une ressource traduite qu'on peut récupérer ensuite. Tag, interrogation directe de la ressource, tout dépend du support de MVVM et de choix personnels ou liés au projet.

Conclusion

Ce qui est discuté ici est une simple astuce. Mais parfois les petites astuces sont bien utiles et font gagner du temps…

Stay Tuned !

blog comments powered by Disqus