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...
Le 17/04/2012 11:31, Florian Desbois a écrit :
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...
Je n'ai pas de vraies solutions au problème. Mais l'utilisateur final ne devrait pas voir l'exception : le catch de l'exception est d'afficher un message d'erreur. (UN message, et non le message de l'exception). Le problème étant maintenant de recuperer les bonnes information sur l'erreur de parsing ce qui n'est pas évident. Le problème de mettre ces infos dans l'exception type + info (ImportException (line 12)) est que potentiellement cela induira beaucoup de classes d'exception pour les toutes les erreurs potentielles. En tout cas, c'est sympa de communiquer là dessus ;) -- Éric Chatellier <chatellier@codelutin.com> Tel: 02.40.50.29.28 http://www.codelutin.com
On Tue, 17 Apr 2012 11:31:50 +0200 Florian Desbois <fdesbois@codelutin.com> wrote: ...
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.
Cette solution me parait la mieux, mais je pense qu'elle ne marche pas trop, surtout lorsqu'une librairie/application crée de nouveau thread (ex: isis (oui je sais c pas du web :), mais j'ai pas d'autre exemple, là, maintenant, tout de suite :)) ...
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 ?).
oui tu te trompes, les arguements sont utilisés dans le message, voir meme formaté (date, nombre). ex: LaJolieCle=Vous venez de copier %s fichier(s) et: i18n._("LaJolieCle", 10) ...
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 ?
De plus en plus, je pense que les messages d'exception ne devraient pas être traduit. Ca n'apporte pas grand chose (Exception == Exceptionnel) donc ne devrait jamais arriver. Et si ca arrive l'application devrait l'intercepter pour mettre son propre message. Par contre, la problématique de traduction reste pour d'autres messages/textes, par exemple lorsqu'on écrit des widgets swings. Mais dans ce cas, nous ne sommes pas dans une appli web, avec des utilisateurs qui souhaite l'utiliser dans plusieurs langues. Il reste les taglibs web que l'on pourrait avoir besoin d'écrire. Dans ce cas comment gérer i18n. Peut-être tout simplement en ayant un attribut pour tous les taglibs <w:edit i18n='fr_FR' .../> La valeur de l'attribut pourrait être positionné par une variable dans la JSP. Il reste le cas d'"application" que l'on réutilise dans d'autre (exemple: intégration d'application de forum, utilisation d'extension webmotion, ...). Dans le premier type d'exemple, on ne peut pas y faire grand chose, car on a pas écrit le code. Pour le deuxième type d'exemple si c'est nous qui écrivons le code, il faut peut-être y réfléchir. Si le framework ne nous oblige pas à utiliser son mécanisme
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...
-- Benjamin POUSSIN -------------------- tél: +33 (0) 2 40 50 29 28 email: poussin@codelutin.com http://www.codelutin.com
...
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.
Cette solution me parait la mieux, mais je pense qu'elle ne marche pas trop, surtout lorsqu'une librairie/application crée de nouveau thread (ex: isis (oui je sais c pas du web :), mais j'ai pas d'autre exemple, là, maintenant, tout de suite :))
+0 Il me semblait qu'on avait dit que c'était dangeureux à terme d'être en ThreadLocal (surtout pour du web ?).
...
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 ?).
oui tu te trompes, les arguements sont utilisés dans le message, voir meme formaté (date, nombre).
ex: LaJolieCle=Vous venez de copier %s fichier(s) et: i18n._("LaJolieCle", 10)
...
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 ?
De plus en plus, je pense que les messages d'exception ne devraient pas être traduit. Ca n'apporte pas grand chose (Exception == Exceptionnel) donc ne devrait jamais arriver. Et si ca arrive l'application devrait l'intercepter pour mettre son propre message. +1 on arrive à des systèmes délirants :( Ce n'est pas de la responsabilité pour moi des
Ben il a dit n_ pas _ donc où ça ne sert à rien Flo d'utiliser des paramètre sur cette méthode son unique but étant de marquer des clefs de traductions. libs de traduire les erreurs. Exemple : topia et c'est le bon example vu que tout devrait être en runtime...
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... +1 on doit supprimer ça de Topia dès que possible :)
-- Tony Chemit -------------------- tél: +33 (0) 2 40 50 29 28 email: chemit@codelutin.com http://www.codelutin.com
Le 30/04/2012 00:26, Benjamin POUSSIN a écrit :
On Tue, 17 Apr 2012 11:31:50 +0200 Florian Desbois<fdesbois@codelutin.com> wrote:
...
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.
Cette solution me parait la mieux, mais je pense qu'elle ne marche pas trop
Comme tu dis. Pour moi, c'est la pire solution.
surtout lorsqu'une librairie/application crée de nouveau thread (ex: isis (oui je sais c pas du web :), mais j'ai pas d'autre exemple, là, maintenant, tout de suite :))
C'est le soucis, on ne doit pas faire de supposition sur l'aspect multi-thread de l'appli.
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 ?
De plus en plus, je pense que les messages d'exception ne devraient pas être traduit. Ca n'apporte pas grand chose (Exception == Exceptionnel) donc ne devrait jamais arriver. Et si ca arrive l'application devrait l'intercepter pour mettre son propre message.
Je pense que c'est la bonne façon de faire. Quand tu te prends un IOException dans ton UI, bah le message est pas traduit donc on a pas le choix, c'est à l'UI de gérer.
Ne faudrait-il pas tout laisser en anglais et laisser faire les interfaces ?
Je ne vois pas d'autres façon de faire bien. -- Brendan Le Ny, Code Lutin bleny@codelutin.com (+33) 02 40 50 29 28
Le 02/05/2012 10:34, Brendan Le Ny a écrit :
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 ?
De plus en plus, je pense que les messages d'exception ne devraient pas être traduit. Ca n'apporte pas grand chose (Exception == Exceptionnel) donc ne devrait jamais arriver. Et si ca arrive l'application devrait l'intercepter pour mettre son propre message.
Je pense que c'est la bonne façon de faire. Quand tu te prends un IOException dans ton UI, bah le message est pas traduit donc on a pas le choix, c'est à l'UI de gérer.
Et si tu veux un message qui porte de l'info, tu crées l'exception qui va bien et tu as des getters/setters pour récupérer l'info et la remettre dans ton message d'UI.
Ne faudrait-il pas tout laisser en anglais et laisser faire les interfaces ?
Je ne vois pas d'autres façon de faire bien.
Entièrement d'accord. -- Jean Couteau - Code Lutin - www.codelutin.com 12 Avenue Jules Verne, 44230 Saint-Sébastien-Sur-Loire Tel : 02.40.50.29.28 - Port : 06.68.07.29.29
participants (6)
-
Benjamin POUSSIN -
Brendan Le Ny -
Eric Chatellier -
Florian Desbois -
Jean Couteau -
Tony Chemit