Langues
Le titre et la description de chaque règle, ainsi que le résumé et l’indication de chaque occurrence, sont localisés par une recherche dans un dictionnaire à clés, et non codés en dur pour chaque langue.
Langues actuellement couvertes
| Langue | Fichier | Clés | Non traduites |
|---|---|---|---|
en (anglais) | src/i18n/en.json | 1334 | — (le jeu canonique, utilisé en repli) |
de (allemand) | src/i18n/de.json | 1334 | 0 |
es (espagnol) | src/i18n/es.json | 1334 | 0 |
fr (français) | src/i18n/fr.json | 1334 | 0 |
ja (japonais) | src/i18n/ja.json | 1334 | 0 |
« Non traduites » compte les valeurs identiques au texte anglais, caractère pour caractère, à l’exception des mots qui sont à juste titre les mêmes dans une langue : en français Orientation, Interruptions et Occurrences, en allemand Frame, Frames et Element, en espagnol Selector. Ces mots sont listés comme tels, chacun avec le texte anglais auquel il a été comparé, et comptent comme traduits. Si l’anglais change, l’entrée ne s’applique plus et la chaîne compte comme non traduite jusqu’à ce que quelqu’un la vérifie de nouveau. Le décompte ne voit pas un mot anglais resté dans une phrase par ailleurs traduite ; cela se repère en lisant le texte, et il n’en reste aucun dans les langues ci-dessus. Il ne mesure pas non plus si une traduction est exacte ou emploie les termes d’accessibilité habituels d’une langue ; cela demande une personne qui lit cette langue.
Lire la couverture depuis le paquet
Les mêmes chiffres sont disponibles à l’exécution, à partir des dictionnaires que livre le paquet installé : un outil ou un site de documentation peut donc les afficher sans copie locale du dépôt.
const { getLocaleCoverage } = require('@surea11y/core');getLocaleCoverage();// {// sourceLocale: 'en',// totalKeys: 1334,// locales: [// { locale: 'de', total: 1334, translated: 1334, missing: 0, orphaned: [], percent: 100 },// { locale: 'es', total: 1334, translated: 1334, missing: 0, orphaned: [], percent: 100 },// ...// ]// }
Pour chaque langue, total est le nombre de clés anglaises auquel elle est comparée, translated le nombre de ses valeurs qui diffèrent de l’anglais ou sont listées comme identiques à juste titre, missing le nombre de clés qui lui manquent (elles s’affichent en anglais) et orphaned les clés qu’elle a et que l’anglais n’a pas. total - translated correspond à la colonne « Non traduites » ci-dessus, clés manquantes comprises. Les clés qu’un profil exclut volontairement d’une langue ne sont pas comptées. Le rapport de couverture du dépôt et cette fonction partagent une seule implémentation et concordent donc toujours ; le rapport compte séparément les dictionnaires de core et ceux de chaque profil, cette fonction le dictionnaire fusionné qu’utilise une analyse. C’est un export pris en charge (API_STABILITY.md, points d’extension).
Les fichiers de langue sont du JSON simple : une table plate associant chaque clé à sa chaîne traduite, dans le même ordre de clés que en.json. Ils ne contiennent rien d’autre, donc contribuer une langue revient à modifier du texte sans jamais toucher au code.
Chaque fichier de langue contient toutes les clés de en.json. C’est le rôle de npm run i18n:sync de le garantir : lancez-le après toute modification de en.json et il réécrit chaque fichier de langue non anglais pour l’aligner, en ajoutant les nouvelles clés, en supprimant celles que en.json n’a plus, et sans toucher aux traductions existantes. Une clé qu’il ajoute reçoit le texte anglais comme valeur initiale, ce qui compte comme non traduit jusqu’à ce que quelqu’un le remplace.
Choisir une langue
runDomRulesInPage(url, null, { locale: 'fr' }, null);
La valeur par défaut est 'en' si l’option est omise. Toute chaîne est acceptée ; une locale non reconnue n’est jamais une erreur.
Comment la langue est déterminée
Deux choses se produisent, dans cet ordre. Les confondre est la source de confusion habituelle, c’est pourquoi elles sont décrites séparément.
Étape 1 : choisir un dictionnaire (une fois par analyse)
- Utiliser le dictionnaire qui correspond à votre code de locale.
detrouvede.json. La casse n’a pas d’importance :pt-br,pt-BRetPT-BRtrouvent touspt-BR.json. - Sinon, supprimer tout ce qui suit le premier
-et réessayer.de-DEtrouvede.json;de-ATaussi. - Sinon, utiliser l’anglais.
Vous n’avez donc besoin d’un de-DE.json que si l’allemand d’Autriche et celui d’Allemagne doivent réellement différer. Fournissez de.json et toutes les variantes de l’allemand sont couvertes.
Étape 2 : résoudre chaque chaîne (chaîne par chaîne)
Dans le dictionnaire choisi, chaque chaîne est recherchée individuellement :
- Prendre la valeur de la clé dans le dictionnaire choisi.
- Si cette clé manque, prendre la valeur anglaise.
- Si l’anglais ne l’a pas non plus (ce qui ne devrait pas arriver pour une clé intégrée, mais peut arriver pour une clé écrite à la main), utiliser le texte littéral que porte la règle elle-même.
Le résultat n’est jamais une chaîne vide, un undefined ni une erreur levée. Une traduction inachevée s’affiche dans votre langue là où elle existe, et en anglais partout ailleurs.
Savoir quelle langue vous avez réellement obtenue
Ce repli en douceur a un inconvénient : demandez une langue que le build n’embarque pas et vous recevez un anglais impeccable, sans rien dans les chaînes pour vous le signaler. Chaque résultat indique donc la résolution une fois, en tête :
"engine": {"tag": "a11ycore","schemaVersion": "1.0.0","locale": { "requested": "ko", "resolved": "en", "reason": "unknown-locale" }}
requested est ce que vous avez demandé (après suppression des espaces ; en si vous n’avez rien passé ou une valeur qui n’est pas une chaîne), resolved est le dictionnaire utilisé, et reason prend l’une des valeurs suivantes :
| reason | Signification |
|---|---|
ok | Vous avez obtenu exactement ce que vous avez demandé, et ce dictionnaire contient toutes les clés. |
primary-subtag | Votre code de locale comportait une sous-étiquette sans dictionnaire propre, donc sa langue de base a été utilisée : vous avez demandé de-DE et obtenu de. C’est normal et attendu ; il n’y a rien à corriger. Une simple différence de casse ne relève pas de ce cas : DE renvoie ok. |
dictionary-not-loaded | Le projet fournit cette langue, mais cette copie du moteur ne l’embarque pas et aucun dictionnaire n’a été fourni. En pratique : le bundle navigateur autonome sans son fichier de langue séparé. |
unknown-locale | Le projet ne propose aucune traduction dans cette langue, donc l’anglais a été utilisé. ko et pt-BR tombent tous deux dans ce cas aujourd’hui. |
partial-dictionary | Le dictionnaire a été utilisé mais il lui manque certaines clés, donc ces chaînes-là sont retombées sur l’anglais. |
Considérez cette liste comme ouverte : une version ultérieure peut ajouter une valeur, donc testez celles qui vous intéressent et laissez les autres tomber dans un cas par défaut.
Si vous avez besoin d’une langue précise, requested !== resolved est la condition à vérifier en CI. Notez qu’elle est aussi vraie dans le cas inoffensif primary-subtag ; basez donc plutôt la condition sur reason === 'unknown-locale' || reason === 'dictionary-not-loaded' si une correspondance sur la langue de base vous suffit. Voir le schéma de sortie pour la place de ce champ dans le résultat, et API_STABILITY.md pour ce qui est garanti à son sujet.
Où se trouvent les dictionnaires
Les langues disponibles dépendent de la manière dont vous chargez le moteur.
| Mode de chargement | Ce que vous obtenez |
|---|---|
require('@surea11y/core') | Toutes les langues, intégrées. Rien à configurer. |
| Un binding (Playwright, Cypress, …) | Toutes les langues, intégrées. Rien à configurer. |
surea11y.browser.js | L’anglais. Chargez surea11y.i18n.<locale>.js après lui pour toute autre langue. |
Le bundle est découpé parce qu’il transite par le réseau vers chaque page qui l’utilise, et aucune page n’a besoin de toutes les langues. Garder l’anglais intégré et le reste optionnel tient les autres langues hors du téléchargement, et l’empêche de grossir à mesure que des langues sont ajoutées. Chaque fichier séparé, surea11y.i18n.<locale>.js, a à peu près la taille du texte anglais qu’il remplace (200 à 250 Ko aujourd’hui), et une page ne charge que ceux qu’elle utilise. Rien d’autre ne change : le paquet Node et les bindings ne sont pas concernés.
<script src="surea11y.browser.js"></script><script src="surea11y.i18n.ja.js"></script><script>const result = a11ycore.runa11yCoreInPage(location.href, null, { locale: 'ja' }, null);</script>
Demandez une langue dont vous n’avez pas chargé le fichier et vous obtenez l’anglais, avec engine.locale.reason défini à dictionary-not-loaded, ce qui diffère de unknown-locale, qui signifie que le projet ne propose aucune traduction dans cette langue.
Dans Node, ce même fichier séparé est un module : require('@surea11y/core/i18n/de') renvoie { locale, messages } (locale vaut 'de', messages est la table plate qui associe chaque clé à son texte), sans avoir besoin du bundle.
Les messages d’un pack se trouvent dans ses propres dictionnaires, que le pack liste par langue ; dans une langue pour laquelle le pack n’a pas de dictionnaire, ses messages s’affichent en anglais.
Les dictionnaires de revue
Les étapes qui indiquent à une personne comment trancher un constat indécis (howToCheck, voir le schéma de sortie) se trouvent dans des dictionnaires à part, dans les cinq mêmes langues. Ils sont tenus à l’écart des dictionnaires du moteur pour que les étapes n’entrent jamais dans le bundle ni dans une page : elles sont ajoutées après l’analyse, dans Node, ou par du code qui les importe. Core 1.14.0 et ultérieur.
| Qui les lit | Comment |
|---|---|
runDomRulesInPage, addHowToCheck, howToCheckFor, renderHtmlReport | Depuis le paquet installé, cherchés d’après la langue en minuscules (fr-ca, puis fr), l’anglais en dernier. |
| Du code qui s’exécute dans un navigateur (un spec Cypress) | applyHowToCheck(result, { en, fr }) de @surea11y/core/how-to-check, avec les dictionnaires qu’il importe sous @surea11y/core/review/<locale>. |
a11ycore.openReport(result) dans le bundle navigateur | Récupérés à côté du bundle, ou donnés sous la forme { reviewDictionaries }. |
Une étape qui manque dans une langue s’affiche en anglais, comme un message. Les étapes propres à une règle de pack sont en anglais dans toutes les langues. getLocaleCoverage() ne compte pas ces dictionnaires. Les étapes ne portent pas de clés : pour les afficher dans une autre langue, ajoutez-les de nouveau :
const { addHowToCheck } = require('@surea11y/core');const inFrench = addHowToCheck(result, { locale: 'fr' });
Fournir votre propre dictionnaire
engineOptions.messages accepte { [locale]: { key: value } } et prend le pas sur tout ce qui est intégré ou chargé depuis un fichier séparé. Utile pour remplacer quelques chaînes, ou pour une langue que vous maintenez en privé :
runDomRulesInPage(url, null, {locale: 'de',messages: { de: { img_altPresent_title: 'Eigener Text' } }}, null);
Les clés que vous ne fournissez pas retombent normalement sur les valeurs par défaut, donc un remplacement partiel convient.
Correspondance propre à chaque langue
Cinq règles jugent le texte d’après des expressions connues : elles embarquent donc des listes de mots en plus des messages : link-name-quality (« click here », « こちら »), heading-quality (« Untitled », « 見出し »), form-control-label-quality (« Label », « 入力欄 »), page-title-patterns (« Home », « トップページ ») et media-alternative-transcript-evidence (« transcript », « 文字起こし »). Chaque liste couvre en, de, es, fr et ja. La règle skip-link reconnaît la formulation des liens d’évitement dans ces mêmes cinq langues.
L’anglais est toujours vérifié. La liste de la langue de l’élément, tirée de l’attribut lang le plus proche (celui de l’élément <html> pour un titre de page), s’y ajoute. link-name-quality vérifie les listes de toutes les langues là où aucun lang n’est déclaré dans l’arbre au-dessus du lien, puisque le lien peut être dans n’importe laquelle. Vérifier toutes les listes partout signalerait des mots génériques dans une langue et de vrais noms dans une autre, comme « Suite » ou « Plus » sur une page en anglais. Les mots de transcription font exception : ils sont distinctifs dans toutes les langues et une page peut lier une transcription dans une autre langue, ils sont donc toujours tous vérifiés. Le texte est d’abord normalisé en NFKC, si bien que les formes pleine chasse comme « 見出し2 » correspondent.
page-title-patterns compte aussi chaque caractère chinois, japonais ou coréen pour deux lorsqu’il décide si un titre est trop court, puisque « お問い合わせ » est un titre complet en six caractères.
Où les clés sont utilisées
Plusieurs espaces de noms de clés, tous résolus de la même façon :
- Au niveau de la règle :
meta.i18n.titleKey/meta.i18n.descriptionKeyrésolvent letitle/descriptiond’une règle dans chaque entrée dechecksResults[]. - Rapport HTML : les clés
report_*étiquettent la page que produit@surea11y/core/report: titres, colonnes des tableaux, noms des résultats et des gravités, phrase de synthèse, pagination. Le rapport les lit dans la langue retenue pour l’analyse : un dictionnaire traduit donc aussi le rapport. - Au niveau des composites : le
title/descriptionde chaque agrégation derulesResults[], avec le nom publié du critère de succès dans chaque langue. - Au niveau de l’occurrence :
i18n.summaryKey/i18n.hintKey, aveci18n.paramspour l’interpolation de{{placeholder}}, résolvent lesummary/hintd’une occurrence.i18n.whyKey/i18n.cautionKeyrésolvent de la même façon lewhyet lecautiond’une tendance. Voir le schéma de sortie. - Revue :
<prefix>_review_<CODE>_step<n>,_passet_fail, dans les dictionnaires de revue : lehowToCheckd’une occurrence indécise.
Les clés de la règle, de la règle composite et de l’occurrence figurent dans le résultat à côté du texte déjà résolu, ce qui vous permet de réafficher un résultat enregistré dans une autre langue sans relancer l’analyse.