Le serveur formulait en français dans une interface réglée en anglais
L'interface a été rendue bilingue et mesurée à cent pour cent. Restait ce que
le serveur dit, et cela se voyait : « This indicator does not grade for the sake
of grading » suivi de « Tour d'astreinte sans trou ». Deux cent une phrases —
refus des routes, accusés, libellés de l'indicateur de préparation, messages de
validation, résumés d'événements du journal.
── Un seul point de traduction pour cent trente-sept messages
Le champ « message » d'une réponse JSON est, par convention de ce serveur, une
phrase adressée au lecteur : un refus qui dit quoi corriger, ou un accusé qui
dit ce qui vient d'être fait. Un crochet de sérialisation le traduit, une fois,
plutôt qu'un appel par route.
Cette convention avait une exception, et je l'ai retirée plutôt que de bâtir un
garde-fou autour d'elle : le lien public de mobilisation renvoyait le texte de
la campagne sous « message ». C'est du contenu écrit par la cellule ; il voyage
désormais sous « texte », comme partout ailleurs dans ce dépôt. Le crochet n'a
donc plus rien à éviter.
Onze messages portent une valeur interpolée — un nom, un délai, un rôle. Ceux-là
se traduisent à la source, avec « req.traduire », la substitution ne pouvant pas
se faire après coup.
── Les nombres, généralisés
Les messages de validation portent leur seuil dans leur texte : « au moins 2
caractères », « au moins 10 caractères ». Une entrée par seuil serait absurde.
La traduction tente la clé exacte, puis la même clé dont les nombres sont
remplacés par « {n} » — « au moins {n} caractères » — et remet les nombres à
leur place. Une entrée couvre tous les seuils.
── Ce qui ne se traduit pas, et ne doit pas
Ce que la cellule a écrit. Une entrée de main courante, un message de salon, un
texte de mobilisation sont des faits datés, versés au journal, relus des mois
plus tard par un assureur ou un juge. Les traduire serait réécrire une preuve.
Seule la formulation du produit se traduit — y compris les résumés que la main
courante dérive du journal à la lecture, qui sont une formulation et non un
fait.
── Une erreur que deux garanties ont vue avant moi
J'avais donné l'identité pour traducteur par défaut : « (fr) => fr ». Elle rend
le texte sans substituer, et « Gravité portée de {de} à {vers} — {motif} »
partait tel quel vers tout appelant sans langue — la suite de vérification, le
dossier de clôture, l'export du journal. EF-1203 et EF-209 sont tombées. Le
défaut est désormais le français, substitution comprise.
── Deux dictionnaires, une convention
Celui du serveur est distinct de celui de l'interface : le navigateur n'a pas à
télécharger les messages du serveur, ni le serveur à embarquer les libellés des
écrans. Même règle de part et d'autre — la clé est le texte français, une clé
absente s'affiche en français.
La langue vient de l'en-tête « accept-language », que le client envoie à chaque
requête. C'est le choix fait dans les préférences qui part, non la langue du
navigateur : quelqu'un dont le système est en anglais peut préférer lire Kastell
en français.
Éprouvé sur l'instance : le même refus rend « Session required. » ou « Session
requise. » selon l'en-tête, « at least 10 characters » conserve son seuil, et
sans en-tête c'est le français. Une garantie neuve compte les phrases du serveur
comme l'autre compte celles de l'interface — 201 sur 201.
Co-Authored-By: Claude (RCA)