Localisation du moteur
Le texte du moteur destiné aux personnes existe en 17 langues en plus de l'anglais : nl, pl, pt-BR, pt-PT, fi, sv, da, nb, cs, uk, ru, de, fr, es, et, ja, zh-Hans. L'anglais est la source ; en-XA est une pseudo-locale qui accentue, entoure de crochets et complète chaque message, de sorte qu'un test peut voir si le texte est passé dans le catalogue. Le cadre est Project Fluent (fluent-bundle, unic-langid) ; le code est src/i18n/.
Ce qui est localisé et ce qui ne l'est jamais#
| Localisé (une personne le lit) | Jamais localisé (un programme le lit) |
|---|---|
| messages et erreurs de la ligne de commande | clés et valeurs JSON de result.json et report.json |
| la ligne de synthèse de chaque exécution | en-têtes et lignes CSV |
| le texte des graphiques SVG (titres, axes, légendes, légendes de figure) | noms de fichiers |
report.html : titres, tableaux, notes, légendes |
codes d'erreur (E-CLOCK-VERSION) |
| mots de verdict (VALIDATED, MODELLED, PARTIAL) | la matrice de vérification, les définitions d'unités, la provenance |
les descriptions des types de scénario (list_kinds(lang)) |
|
mentions à titre consultatif, avertissements et avis (engine-legal-*) |
les mêmes textes dans le JSON, qui restent en anglais |
report.html de la campagne iq, de la page de comparaison d'études, du classement bench, du rapport de résilience |
summary.html d'un paquet de preuves et le PNG de l'observatoire : tous deux sont hachés dans un manifeste (celui du paquet est aussi signé), ils sont donc construits en anglais quelle que soit la langue |
Les nombres dans le texte destiné aux personnes utilisent le séparateur décimal de la langue (une virgule dans 15 des 18 langues ; un point en en, ja, zh-Hans et en-XA). Les nombres dans les fichiers machine utilisent toujours le point. Un compteur (une variable nommée n, count, n_*, num_* ou *_count) parvient à Fluent comme un nombre, de sorte qu'une traduction peut écrire { $n -> [one] ... [few] ... *[other] ... }.
Choisir la langue#
- Ligne de commande :
--lang <tag>, puisKSHANA_LANG,LC_ALL,LC_MESSAGES,LANG, puis l'anglais.ptest pt-BR ; seulpt-PTest celui du Portugal.zhest le chinois simplifié ; le traditionnel est refusé avec la liste des balises prises en charge. - Bibliothèque :
api::run_toml_lang(toml, lang),run_toml_bilingual,run_toml_human,run_scenario_lang,list_scenario_kinds_json_lang(lang). - Python :
lang=Nonesurrun,run_full,run_typed,validate_toml,error_kind,list_kinds,scenario_kinds;run_human(toml, lang);error_info(toml, lang). - WebAssembly : un
langfinal facultatif surrun_typed,run,chart_svg,summary,table_csv,run_all,error_kind,list_kinds,scenario_kinds;run_human(toml, lang);error_info(toml, lang);register_catalogue(tag, ftl_text). - MCP :
langsurrun_scenarioetlist_scenario_kinds.
Les erreurs et leurs codes#
Chaque message d'erreur a un code stable, l'identifiant du message en majuscules (e-clock-version est E-CLOCK-VERSION), le même dans toutes les langues. Le texte anglais de la ligne de commande est inchangé. Dans une autre langue, la ligne est text [E-CODE] ; avec --verbose, une seconde ligne code: E-CODE suit dans toutes les langues. L'API fournit KshanaError::code() et error_info ({kind, code, message}) ; les erreurs MCP portent {kind, code, message} comme données d'erreur. Fiez-vous au code, jamais au texte.
Comment une exécution fonctionne dans une autre langue (la règle de la double exécution)#
Un fichier machine ne doit pas dépendre de la langue. Une exécution dans une autre langue exécute donc le scénario deux fois : une fois en anglais, dont result.json, report.json et le CSV sont les fichiers machine, et une fois dans la langue de l'utilisateur, pour la synthèse, le graphique et report.html. L'anglais est une seule exécution, octet pour octet ce qu'elle était auparavant.
Mesuré, natif, compilation de release, anglais puis --lang de (secondes) : leo-navmsg-fit-interval-trade 9,2 -> 17,9, cislunar-arc-recovery 7,8 -> 14,1, lunar-station-coverage 7,8 -> 15,0, clock-ensemble 5,8 -> 11,6, leo-navmsg-model-comparison 5,1 -> 10,5, leo-ppp-convergence 2,8 -> 6,2 ; tout autre scénario fourni dure moins de 4 s ; les 173 scénarios fournis au moment de la mesure ont pris 64 s en anglais au total. Le coût est exactement le double pour une autre langue. WebAssembly n'a pas été mesuré (pas de wasm-bindgen ici) ; au facteur navigateur d'environ 4, cela fait une minute pour le type le plus lent.
Une page évite l'attente en affichant tout de suite le résultat anglais puis en appelant run_human(toml, lang) : c'est la seconde exécution seule, elle renvoie {summary, svg}, et le Studio peut afficher « traduction en cours… » jusqu'à son arrivée.
Élément 0,41 : une seule exécution. Rendre les deux à partir d'un enregistrement de (message id, arguments). Cela a été examiné et non réalisé : les résultats t! sont inspectés, mesurés et hachés après leur création (largeurs du texte des graphiques, hachages de provenance sur le texte de sortie), et num() formate au point d'appel, de sorte qu'un enregistrement mettrait des jetons de remplacement dans les fichiers machine et ferait dépendre leurs octets de la relecture. Il faudrait t!/num qui renvoient des jetons, un finaliseur à chaque écrivain et une preuve d'identité des octets pour chaque écrivain.
WebAssembly#
La compilation wasm n'embarque que le catalogue anglais. Les seize autres ajouteraient environ 150 kB en gzip chacun. Une page récupère i18n/<lang>/engine.ftl au choix d'une langue et appelle register_catalogue(tag, text) ; si la récupération ou l'enregistrement échoue, la page reste en anglais. En natif, la ligne de commande et le wheel Python embarquent les 18.
Taille, .wasm non optimisé issu de cargo build --release --target wasm32-unknown-unknown --features wasm --lib (avant wasm-bindgen et wasm-opt), base bc04e98f par rapport à cette branche : 18,71 MB -> 19,88 MB brut, 5,43 MB -> 5,79 MB en gzip, +357 kB en gzip. Le catalogue anglais fait 521 kB brut, dont 153 kB en gzip ; le reste est fluent-bundle et ses dépendances. Cela est accepté tel que mesuré.
Le catalogue#
i18n/<tag>/engine.ftl contient les messages, dont les identifiants ont le préfixe engine-. i18n/en/engine.ftl est la source ; les autres fichiers sont ceux des traducteurs et peuvent manquer de messages (chacun se rabat sur l'anglais message par message). Listes d'accompagnement dans i18n/en/ : engine-counts.txt (messages avec variables de compte, pour les formes plurielles), engine-numbers.txt (nombres transmis comme placeables), engine-fragments.txt (messages qui sont des morceaux d'une phrase assemblée à l'exécution : à fusionner en messages de phrase entière, jamais à multiplier).
Tests#
tests/i18n_catalogue.rs prouve l'anglais : chaque message a un modèle d'origine enregistré et se rend exactement en ce texte ; chaque identifiant est utilisé ; les variables correspondent ; la pseudo-locale rend chaque message. i18n_api.rs, i18n_kinds.rs, i18n_legal.rs couvrent les points d'entrée, les descriptions des types et les textes juridiques. i18n_ratchet.rs échoue si un nouveau littéral de chaîne qu'une personne lirait contourne le catalogue : tolérance par fichier dans tests/fixtures/i18n/allow.json, qui peut baisser et ne monte jamais. scripts/i18n_compare.py exécute des scénarios entiers avec un binaire de référence et le binaire courant et compare chaque fichier de sortie.
Comment déplacer une chaîne dans le catalogue : docs/design/i18n-migration.md.
Dépendances et licences#
Le cadre ajoute fluent-bundle 0,16 (Apache-2.0 OR MIT) et unic-langid 0,9 (MIT OR Apache-2.0), avec leurs crates transitives : fluent-syntax et fluent-langneg (Apache-2.0 OR MIT), intl-memoizer (Apache-2.0 OR MIT), intl_pluralrules (Apache-2.0/MIT), type-map (MIT/Apache-2.0), self_cell (Apache-2.0 OR GPL-2.0-only : l'alternative Apache-2.0 est celle qui est utilisée, ce que deny.toml autorise), tinystr et zerovec (Unicode-3.0), rustc-hash, smallvec, thiserror, displaydoc (MIT OR Apache-2.0). Chacune est permissive selon la liste allow de deny.toml ; thiserror apparaît en deux versions (1 et 2), ce que multiple-versions = "warn" ne fait que signaler. La liste des licences a été lue depuis cargo metadata ; cargo deny check n'est pas installé dans l'environnement de rédaction et s'exécute dans l'intégration continue.