Contexte
======
La plupart des librairies nuiton utilisent i18n pour les messages des
exceptions. Certaines d'entre elles sont intéressantes d'un point de vue
fonctionnelle et les messages pourraient directement être retournés à
l'utilisateur. Par exemple lors d'un import CSV (nuiton-csv), les
messages d'erreurs définissent le numéro de ligne, le type d'erreur, etc...
Problématique
=========
Les messages d'exceptions sont directement traduit avec i18n avec
l'utilisation de la méthode _(). Cependant dans un contexte web, la
locale dynamique modifiée depuis l'interface, ne change pas l'état
d'I18n qui garde sa locale par défaut à l'initialisation. Comment
récupérer alors la clé i18n ou trouver un système permettant de traduire
l'exception en fonction de la locale du contexte web ?
Solution 1 (la plus simple)
================
L'API de la JDK propose une méthode getLocalizedMessage() mais la locale
n'est stipulé nul part. Il faudrait potentiellement la pousser soit via
constructeur (trop intrusif), soit via getter/setter (plus souple, car
la locale peut être mise au moment du catch par exemple).
Ainsi la méthode getLocalizedMessage() renverrais une traduction
localisé (si la locale est mise) en fonction des paramètres de
l'exception. Quelque chose comme :
@Override
public String getLocalizedMessage() {
String result;
if (locale == null) {
result = getMessage();
} else {
result = l_(locale, i18nKey, getMessageArgs());
}
return result;
}
Le paramètre i18nKey pourrait être le message de l'exception en
utilisant n_("i18n.key") au moment de l'instanciation. Les "messageArgs"
dépendent de l'exception. Plus ou moins dynamique suivant les besoins.
Variante:
------------
Quitte à avoir une api avec les getter/setter sur la Locale, autant
ajouter directement une méthode getLocalizedMessage(Locale locale).
=> Cela implique un ajout et une gestion de la locale dans toutes les
exceptions que nous utilisons dans les librairies, ou à minima les plus
pertinentes comme la validation ou l'import/export CSV.
Solution 2 (la moins coûteuse en refactoring)
============================
Avoir une option pour traduire en utilisant un ThreadLocal permettant de
stocker la locale. Ainsi toutes les méthodes _() seront contextualisés
par rapport à ce ThreadLocal.
Solution 3 (l'autre)
===========
Laisser le loisir de traduire le message à l'interface cliente. Dans ce
cas toutes les instanciations d'exception devront utiliser n_() plutôt
que _() pour garder la clé i18n en tant que message. Libre à l'interface
cliente de le traduire ou non. Les traductions des librairies seront
toujours présentes grâce aux bundles.
Variante (plus compliqué):
-----------------------------------
Une autre idée serait de garder la clé i18n mais aussi ses paramètres.
Je me suis toujours demandé l'intérêt d'avoir n_("i18n.key", arg1, arg2)
alors que finalement arg1 et arg2 ne seront jamais gardé ni utilisé (a
moins que je me trompe ?). On pourrait avoir une autre méthode qui
sérialise les paramètres (vu que de toute façon on veut des string).
s_("i18n.key", arg1, arg2) = "i18n.key|toto|18"
qui serait le message de l'exception. Ensuite _() doit être capable
d'interpréter ce parsing avec le séparateur | (ou n'importe quel
caractère qui ferait l'affaire).
=> Les solutions 3 et 4 posent le problème du logging ou des catch
automatique des framework. En effet, la méthode getMessage() sera
généralement appelé sur les stackTrace, mais ici on aura pas de
traduction, à moins encore une fois de surchargé la méthode getMessage()
de toutes les exceptions (pour appeler _() ) et d'ajouter une autre
méthode getOriginalMessage() pour avoir la clé sérialisé.
Conclusion
=======
Cela reste une problématique qui a ses limites. A t-on la réelle
nécessité de devoir traduire tous les messages d'exceptions ? Ne
faudrait-il pas tout laisser en anglais et laisser faire les interfaces ?
De mon point de vue, je ne sais pas encore quelle est la meilleure
solution. Mais je trouve dommage d'avoir toute la gestion i18n de faites
dans les messages d'exceptions alors qu'elle est inutilisable dans un
contexte web...