@surea11y/core 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/CHANGELOG.md +48 -4
  2. package/LICENSE +373 -21
  3. package/README.md +70 -1
  4. package/bin/core.js +240 -11
  5. package/docs/API_STABILITY.md +61 -0
  6. package/docs/BASELINE.md +66 -0
  7. package/docs/BINDING_AUTHORS_GUIDE.md +9 -9
  8. package/docs/CI_INTEGRATIONS.md +103 -0
  9. package/docs/CLI.md +80 -1
  10. package/docs/ENGINE_OPTIONS.md +4 -0
  11. package/docs/INTEGRATION.md +19 -1
  12. package/docs/OUTPUT_SCHEMA.md +2 -2
  13. package/docs/REPORT.md +33 -0
  14. package/docs/RULE_AUTHORING.md +31 -0
  15. package/docs/RULE_CATALOG.md +1 -1
  16. package/docs/SARIF.md +59 -0
  17. package/package.json +15 -4
  18. package/src/baseline.js +0 -0
  19. package/src/catalogs/composites.wcag.js +414 -450
  20. package/src/checks/automatic/area-alt-present.js +59 -25
  21. package/src/checks/automatic/aria-allowed-attr.js +193 -33
  22. package/src/checks/automatic/aria-allowed-role.js +21 -7
  23. package/src/checks/automatic/aria-braille-equivalent.js +32 -10
  24. package/src/checks/automatic/aria-conditional-attr.js +24 -7
  25. package/src/checks/automatic/aria-deprecated-role.js +22 -8
  26. package/src/checks/automatic/aria-hidden-body.js +50 -19
  27. package/src/checks/automatic/aria-hidden-focus.js +408 -53
  28. package/src/checks/automatic/aria-prohibited-attr.js +296 -22
  29. package/src/checks/automatic/aria-prohibited-children.js +125 -29
  30. package/src/checks/automatic/aria-required-attr.js +23 -8
  31. package/src/checks/automatic/aria-required-children.js +37 -14
  32. package/src/checks/automatic/aria-required-parent.js +48 -14
  33. package/src/checks/automatic/aria-role-name-present.js +47 -21
  34. package/src/checks/automatic/aria-roles-valid.js +22 -12
  35. package/src/checks/automatic/aria-valid-attr-value.js +28 -7
  36. package/src/checks/automatic/aria-valid-attr.js +17 -5
  37. package/src/checks/automatic/autocomplete-valid.js +74 -16
  38. package/src/checks/automatic/avoid-inline-spacing.js +20 -6
  39. package/src/checks/automatic/binary-control-name-present.js +60 -50
  40. package/src/checks/automatic/button-name-present.js +48 -18
  41. package/src/checks/automatic/bypass-blocks-present.js +50 -25
  42. package/src/checks/automatic/canvas-text-alternative-present.js +57 -26
  43. package/src/checks/automatic/combobox-name-present.js +38 -45
  44. package/src/checks/automatic/contrast-computable.js +361 -341
  45. package/src/checks/automatic/contrast-enhanced.js +487 -466
  46. package/src/checks/automatic/contrast-minimum.js +486 -465
  47. package/src/checks/automatic/css-orientation-lock.js +39 -9
  48. package/src/checks/automatic/definition-list-children-valid.js +40 -19
  49. package/src/checks/automatic/deprecated-elements-not-used.js +21 -7
  50. package/src/checks/automatic/dialog-name-present.js +37 -75
  51. package/src/checks/automatic/dlitem-parent-valid.js +23 -8
  52. package/src/checks/automatic/duplicate-id-aria.js +24 -6
  53. package/src/checks/automatic/embed-text-alternative-present.js +86 -35
  54. package/src/checks/automatic/form-control-programmatic-label-present.js +79 -196
  55. package/src/checks/automatic/form-control-single-label.js +47 -10
  56. package/src/checks/automatic/html-xml-lang-mismatch.js +43 -19
  57. package/src/checks/automatic/iframe-focusable-content.js +26 -11
  58. package/src/checks/automatic/iframe-name-present.js +31 -9
  59. package/src/checks/automatic/iframe-title-unique.js +29 -8
  60. package/src/checks/automatic/img-alt-present.js +47 -43
  61. package/src/checks/automatic/input-image-alt-present.js +143 -112
  62. package/src/checks/automatic/label-in-name.js +50 -22
  63. package/src/checks/automatic/language-page-present.js +117 -109
  64. package/src/checks/automatic/link-in-text-block.js +59 -19
  65. package/src/checks/automatic/link-name-present.js +45 -14
  66. package/src/checks/automatic/list-children-valid.js +26 -9
  67. package/src/checks/automatic/listbox-name-present.js +39 -19
  68. package/src/checks/automatic/listitem-parent-valid.js +18 -6
  69. package/src/checks/automatic/menuitem-name-present.js +39 -61
  70. package/src/checks/automatic/meta-refresh-no-exceptions.js +37 -8
  71. package/src/checks/automatic/meta-refresh-timing-absent.js +28 -6
  72. package/src/checks/automatic/meta-viewport-zoom-enabled.js +32 -7
  73. package/src/checks/automatic/meter-name-present.js +36 -33
  74. package/src/checks/automatic/nested-interactive-controls-absent.js +31 -10
  75. package/src/checks/automatic/object-text-alternative-present.js +91 -39
  76. package/src/checks/automatic/option-name-present.js +38 -21
  77. package/src/checks/automatic/page-title-present.js +26 -7
  78. package/src/checks/automatic/progressbar-name-present.js +41 -34
  79. package/src/checks/automatic/role-img-alt-present.js +209 -157
  80. package/src/checks/automatic/searchbox-name-present.js +39 -19
  81. package/src/checks/automatic/server-side-image-map-absent.js +23 -8
  82. package/src/checks/automatic/slider-name-present.js +40 -47
  83. package/src/checks/automatic/spinbutton-name-present.js +39 -19
  84. package/src/checks/automatic/summary-name-present.js +37 -17
  85. package/src/checks/automatic/svg-image-text-alternative-present.js +114 -47
  86. package/src/checks/automatic/svg-text-alternative-present.js +246 -226
  87. package/src/checks/automatic/tab-name-present.js +37 -60
  88. package/src/checks/automatic/table-headers-attr-valid.js +24 -8
  89. package/src/checks/automatic/table-th-has-data-cells.js +22 -8
  90. package/src/checks/automatic/target-size-minimum.js +118 -48
  91. package/src/checks/automatic/td-has-header.js +29 -11
  92. package/src/checks/automatic/textbox-name-present.js +39 -19
  93. package/src/checks/automatic/tooltip-name-present.js +37 -18
  94. package/src/checks/automatic/treeitem-name-present.js +38 -21
  95. package/src/checks/automatic/valid-lang.js +20 -6
  96. package/src/checks/automatic/video-poster-text-alternative-present.js +79 -36
  97. package/src/checks/manual/accesskeys-manual.js +14 -5
  98. package/src/checks/manual/area-alt-decorative-manual.js +192 -193
  99. package/src/checks/manual/area-alt-quality-manual.js +182 -141
  100. package/src/checks/manual/aria-checked-state-mismatch-manual.js +34 -11
  101. package/src/checks/manual/aria-text-manual.js +14 -6
  102. package/src/checks/manual/canvas-text-alternative-quality-manual.js +149 -114
  103. package/src/checks/manual/css-hidden-focus.js +196 -165
  104. package/src/checks/manual/embed-text-alternative-quality-manual.js +171 -160
  105. package/src/checks/manual/empty-heading-manual.js +24 -12
  106. package/src/checks/manual/empty-table-header-manual.js +21 -14
  107. package/src/checks/manual/focus-order-semantics-manual.js +45 -10
  108. package/src/checks/manual/form-control-programmatic-label-quality-manual.js +207 -246
  109. package/src/checks/manual/heading-order-manual.js +22 -12
  110. package/src/checks/manual/identical-links-same-purpose-manual.js +34 -12
  111. package/src/checks/manual/image-redundant-alt-manual.js +17 -7
  112. package/src/checks/manual/img-alt-decorative-manual.js +131 -96
  113. package/src/checks/manual/img-alt-quality-manual.js +176 -127
  114. package/src/checks/manual/input-image-alt-decorative-manual.js +125 -92
  115. package/src/checks/manual/input-image-alt-quality-manual.js +125 -92
  116. package/src/checks/manual/label-title-only-manual.js +14 -5
  117. package/src/checks/manual/landmark-banner-is-top-level-manual.js +95 -29
  118. package/src/checks/manual/landmark-contentinfo-is-top-level-manual.js +82 -29
  119. package/src/checks/manual/landmark-main-is-top-level-manual.js +64 -23
  120. package/src/checks/manual/landmark-no-duplicate-banner-manual.js +54 -23
  121. package/src/checks/manual/landmark-no-duplicate-contentinfo-manual.js +54 -23
  122. package/src/checks/manual/landmark-no-duplicate-main-manual.js +17 -8
  123. package/src/checks/manual/landmark-one-main-manual.js +35 -21
  124. package/src/checks/manual/landmark-unique-manual.js +73 -45
  125. package/src/checks/manual/link-name-quality-manual.js +43 -12
  126. package/src/checks/manual/media-transcript-present-manual.js +35 -22
  127. package/src/checks/manual/meta-viewport-large-manual.js +25 -6
  128. package/src/checks/manual/mouse-only-event-handlers-manual.js +38 -11
  129. package/src/checks/manual/no-autoplay-audio-manual.js +20 -6
  130. package/src/checks/manual/object-text-alternative-quality-manual.js +175 -154
  131. package/src/checks/manual/p-as-heading-manual.js +22 -7
  132. package/src/checks/manual/page-has-heading-one-manual.js +40 -23
  133. package/src/checks/manual/page-title-patterns-manual.js +87 -51
  134. package/src/checks/manual/presentation-role-conflict-manual.js +59 -19
  135. package/src/checks/manual/region-manual.js +275 -62
  136. package/src/checks/manual/scope-attr-valid-manual.js +11 -9
  137. package/src/checks/manual/scrollable-region-focusable-manual.js +37 -11
  138. package/src/checks/manual/skip-link-manual.js +35 -12
  139. package/src/checks/manual/svg-text-alternative-quality-manual.js +206 -165
  140. package/src/checks/manual/tabindex-manual.js +11 -9
  141. package/src/checks/manual/table-duplicate-name-manual.js +17 -7
  142. package/src/checks/manual/table-fake-caption-manual.js +24 -7
  143. package/src/checks/manual/video-caption-manual.js +15 -4
  144. package/src/checks/manual-review.js +56 -12
  145. package/src/core/aria-helpers.js +1128 -823
  146. package/src/core/contrast-helpers.js +1217 -1062
  147. package/src/core/dom-helpers.js +4176 -3886
  148. package/src/core/dom-runner.js +720 -596
  149. package/src/core/frame-messaging.js +189 -138
  150. package/src/core/frame-scan.js +94 -82
  151. package/src/core/rollup-composites.js +94 -102
  152. package/src/core/rule-meta.js +71 -35
  153. package/src/core.js +37939 -29121
  154. package/src/i18n/en.js +1194 -887
  155. package/src/i18n/fr.js +1136 -793
  156. package/src/policy/contracts.js +13 -13
  157. package/src/policy/resolvePolicy.js +48 -44
  158. package/src/report.js +502 -0
  159. package/src/sarif.js +175 -0
  160. package/surea11y.browser.js +36042 -0
package/src/i18n/fr.js CHANGED
@@ -1,842 +1,1185 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = {
4
- "img_altPresent_title": "<img> doit avoir un attribut alt",
5
- "img_altPresent_description": "Vérifie que les éléments <img> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.",
6
-
7
- "img_altPresent_summary_fail": "Attribut alt manquant sur <img>.",
8
- "img_altPresent_hint_fail": "Ajoutez un attribut alt (utilisez alt=\"\" uniquement pour les images décoratives).",
9
- "area_altPresent_title": '<area> doit avoir un attribut alt',
10
- "area_altPresent_description":
11
- 'Vérifie que les éléments <area> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.',
12
- "area_altPresent_summary_fail": 'Attribut alt manquant sur <area>.',
13
- "area_altPresent_hint_fail":
14
- 'Ajoutez un attribut alt (utilisez alt="" uniquement pour les zones décoratives).',
15
- "inputImage_altPresent_title": "<input type=\"image\"> doit avoir un attribut alt",
16
- "inputImage_altPresent_description": "Vérifie que les éléments <input type=\"image\"> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.",
17
- "inputImage_altPresent_summary_fail": "Attribut alt manquant sur <input type=\"image\">.",
18
- "inputImage_altPresent_hint_fail": "Ajoutez un attribut alt (utilisez alt=\"\" uniquement lorsqu’un nom accessible séparé est fourni).",
19
- "ariaHidden_programmaticFocus_review_title": "Vérifier le focus programmatique avec aria-hidden",
20
- "ariaHidden_programmaticFocus_review_description": "Signale les éléments aria-hidden considérés comme éligibles uniquement via un focus programmatique (ex. tabindex < 0). Vérifiez l’intention de gestion du focus et l’exposition aux technologies d’assistance.",
21
- "ariaHidden_programmaticFocus_review_summary": "Vérification : un élément aria-hidden est focusable de façon programmatique.",
22
- "ariaHidden_programmaticFocus_review_hint": "Vérifiez que la gestion du focus est intentionnelle et que l’élément doit rester masqué aux technologies d’assistance.",
23
- "canvas_textAltPresent_title": "<canvas> doit fournir une alternative textuelle",
24
- "canvas_textAltPresent_description": "Vérifie que les éléments <canvas> fournissent une alternative textuelle via un contenu de repli ou un nom accessible.",
25
- "canvas_textAltPresent_summary_fail": "Alternative textuelle manquante pour <canvas>.",
26
- "canvas_textAltPresent_hint_fail": "Fournissez un texte de repli dans <canvas> ou un nom accessible (par ex. aria-label/aria-labelledby).",
27
- "svg_textAltPresent_title": "<svg> doit fournir une alternative textuelle",
28
- "svg_textAltPresent_description": "Vérifie que les éléments <svg> en ligne fournissent une alternative textuelle via un élément <title> ou un nom ARIA (un élément <desc> seul ne suffit pas).",
29
- "svg_textAltPresent_summary_fail": "Alternative textuelle manquante pour <svg>.",
30
- "svg_textAltPresent_hint_fail": "Fournissez un élément <title> avec du texte, ou un nom ARIA (aria-label/aria-labelledby) — un élément <desc> seul ne fournit pas de nom accessible.",
31
- "object_textAltPresent_title": "<object> doit fournir une alternative textuelle",
32
- "object_textAltPresent_description": "Vérifie que les éléments <object> fournissent une alternative textuelle via un contenu de repli ou un nom accessible.",
33
- "object_textAltPresent_summary_fail": "Alternative textuelle manquante pour <object>.",
34
- "object_textAltPresent_hint_fail": "Fournissez un contenu de repli pertinent dans <object>, ou ajoutez un nom accessible (aria-label/aria-labelledby).",
35
- "embed_textAltPresent_title": "<embed> doit fournir une alternative textuelle",
36
- "embed_textAltPresent_description": "Vérifie que les éléments <embed> fournissent une alternative textuelle via un nom accessible.",
37
- "embed_textAltPresent_summary_fail": "Alternative textuelle manquante pour <embed>.",
38
- "embed_textAltPresent_hint_fail": "Ajoutez un nom accessible à <embed> (aria-label/aria-labelledby).",
39
- "img_altQuality_title": "<img> : texte alt à vérifier (revue manuelle)",
40
- "img_altQuality_description": "Signale les éléments <img> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.",
41
- "img_altQuality_summary_cantTell": "Vérifiez le texte alt de <img> (exactitude et pertinence).",
42
- "img_altQuality_hint_cantTell": "Assurez-vous que le texte alt exprime le but/l’information de l’image dans son contexte (ni redondant, ni nom de fichier).",
43
- "img_altDecorative_title": "<img> avec alt=\"\" : décoratif à confirmer (revue manuelle)",
44
- "img_altDecorative_description": "Signale les éléments <img> dont l’attribut alt est vide afin de confirmer qu’ils sont purement décoratifs.",
45
- "img_altDecorative_summary_cantTell": "Vérifiez si <img> est décoratif (alt=\"\").",
46
- "img_altDecorative_hint_cantTell": "Confirmez que l’image est purement décorative. Sinon, fournissez un texte alt pertinent.",
47
- "area_altQuality_title": "<area> : texte alt à vérifier (revue manuelle)",
48
- "area_altQuality_description": "Signale les éléments <area> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.",
49
- "area_altQuality_summary_cantTell": "Vérifiez le texte alt de <area> (exactitude et pertinence).",
50
- "area_altQuality_hint_cantTell": "Assurez-vous que le texte alt identifie la destination/l’action de la zone dans son contexte.",
51
- "area_altDecorative_title": "<area> avec alt=\"\" : décoratif à confirmer (revue manuelle)",
52
- "area_altDecorative_description": "Signale les éléments <area> dont l’attribut alt est vide afin de confirmer qu’ils sont décoratifs ou non informatifs.",
53
- "area_altDecorative_summary_cantTell": "Vérifiez si <area> est décoratif (alt=\"\").",
54
- "area_altDecorative_hint_cantTell": "Confirmez que la zone n’a pas de fonction ni d’information. Sinon, fournissez un texte alt pertinent.",
55
- "inputImage_altQuality_title": "<input type=\"image\"> : texte alt à vérifier (revue manuelle)",
56
- "inputImage_altQuality_description": "Signale les éléments <input type=\"image\"> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.",
57
- "inputImage_altQuality_summary_cantTell": "Vérifiez le texte alt de <input type=\"image\"> (exactitude et pertinence).",
58
- "inputImage_altQuality_hint_cantTell": "Assurez-vous que le texte alt décrit l’action du contrôle (ex. « Rechercher », « Envoyer ») dans son contexte.",
59
- "inputImage_altDecorative_title": "<input type=\"image\"> avec alt=\"\" : à vérifier (revue manuelle)",
60
- "inputImage_altDecorative_description": "Signale les éléments <input type=\"image\"> dont l’attribut alt est vide afin de vérifier manuellement (souvent inadapté pour un contrôle fonctionnel).",
61
- "inputImage_altDecorative_summary_cantTell": "Vérifiez <input type=\"image\"> avec alt=\"\".",
62
- "inputImage_altDecorative_hint_cantTell": "Ce contrôle est généralement fonctionnel. Confirmez qu’un nom accessible équivalent existe, sinon fournissez un texte alt pertinent.",
63
- "canvas_textAltQuality_title": "<canvas> : alternative textuelle à vérifier (revue manuelle)",
64
- "canvas_textAltQuality_description": "Signale les éléments <canvas> pour lesquels une alternative textuelle a été détectée, afin de vérifier manuellement son équivalence.",
65
- "canvas_textAltQuality_summary_cantTell": "Vérifiez l’alternative textuelle de <canvas> (équivalence et pertinence).",
66
- "canvas_textAltQuality_hint_cantTell": "Confirmez que le texte de secours ou le nom accessible transmet la même information/fonction que le contenu du canvas.",
67
- "svg_textAltQuality_title": "<svg> : alternative textuelle à vérifier (revue manuelle)",
68
- "svg_textAltQuality_description": "Signale les graphiques <svg> pour lesquels une alternative textuelle a été détectée, afin de vérifier manuellement sa pertinence.",
69
- "svg_textAltQuality_summary_cantTell": "Vérifiez l’alternative textuelle de <svg> (exactitude et pertinence).",
70
- "svg_textAltQuality_hint_cantTell": "Confirmez que <title>/<desc> ou le nom ARIA transmet le sens/le but du graphique dans son contexte.",
71
- "object_textAltQuality_title": "<object> : alternative textuelle à vérifier (revue manuelle)",
72
- "object_textAltQuality_description": "Signale les éléments <object> avec contenu de secours ou nom détecté, afin de vérifier manuellement l’équivalence.",
73
- "object_textAltQuality_summary_cantTell": "Vérifiez l’alternative textuelle de <object> (équivalence et pertinence).",
74
- "object_textAltQuality_hint_cantTell": "Confirmez que le contenu de secours ou le nom ARIA fournit une alternative équivalente au contenu embarqué.",
75
- "embed_textAltQuality_title": "<embed> : alternative textuelle à vérifier (revue manuelle)",
76
- "embed_textAltQuality_description": "Signale les éléments <embed> avec nom détecté, afin de vérifier manuellement sa pertinence.",
77
- "embed_textAltQuality_summary_cantTell": "Vérifiez l’alternative textuelle de <embed> (exactitude et pertinence).",
78
- "embed_textAltQuality_hint_cantTell": "Confirmez que le nom ARIA ou l’attribut title identifie correctement le contenu embarqué dans son contexte.",
79
- "videoPoster_textAltPresent_title": "L’image poster de <video> doit avoir une alternative textuelle",
80
- "videoPoster_textAltPresent_description": "Vérifie que les éléments <video> avec une image poster fournissent une alternative textuelle (nom accessible).",
81
- "videoPoster_textAltPresent_summary_fail": "Alternative textuelle manquante pour l’image poster de <video>.",
82
- "videoPoster_textAltPresent_hint_fail": "Fournissez un nom accessible (par ex. aria-label/aria-labelledby) pour l’image poster.",
83
- "svgImage_textAltPresent_title": "<image> dans un SVG doit avoir une alternative textuelle",
84
- "svgImage_textAltPresent_description": "Vérifie que les éléments SVG <image> fournissent une alternative textuelle via <title>/<desc> ou un nom accessible ARIA.",
85
- "svgImage_textAltPresent_summary_fail": "Alternative textuelle manquante sur <image> (SVG).",
86
- "svgImage_textAltPresent_hint_fail": "Ajoutez un <title> (et éventuellement <desc>) dans <image>, ou fournissez aria-label/aria-labelledby.",
87
- "formControl_programmaticLabelPresent_title":
88
- "Les contrôles de formulaire doivent avoir un libellé programmatique",
89
-
90
- "formControl_programmaticLabelPresent_description":
91
- "Vérifie que les contrôles de formulaire ont un libellé programmatique via <label>, aria-label ou aria-labelledby.",
92
-
93
- "formControl_programmaticLabelPresent_summary_fail":
94
- "Le contrôle de formulaire n’a pas de libellé programmatique.",
95
-
96
- "formControl_programmaticLabelPresent_hint_fail":
97
- "Associez un <label>, ou utilisez aria-label / aria-labelledby (placeholder/title ne sont pas des libellés).",
98
-
99
-
100
- 'formControlAccessibleName_description': 'Échec lorsqu’un contrôle de formulaire applicable n’a pas de nom accessible (ex. label, aria-label, aria-labelledby).',
101
- 'formControlAccessibleName_hint_fail': 'Fournissez un nom accessible via un <label>, aria-label ou aria-labelledby.',
102
- 'formControlAccessibleName_summary_fail': 'Le contrôle de formulaire n’a pas de nom accessible.',
103
- 'formControlAccessibleName_title': 'Les champs de formulaire doivent avoir un nom accessible.',
104
- 'linksTargetBlankNoopener_description': 'Échec lorsqu’un lien avec target="_blank" n’inclut pas rel="noopener" (risque de sécurité via window.opener).',
105
- 'linksTargetBlankNoopener_hint_cantTell': 'Ajoutez rel="noopener" (et éventuellement noreferrer) aux liens avec target="_blank".',
106
- 'linksTargetBlankNoopener_summary_cantTell': 'Lien avec target="_blank" sans rel="noopener".',
107
- 'linksTargetBlankNoopener_title': 'Les liens qui s’ouvrent dans un nouvel onglet doivent utiliser rel="noopener".',
108
- 'manualReview_description': 'Cette règle renvoie toujours cantTell et nécessite une vérification manuelle.',
109
- 'manualReview_hint_cantTell': 'Examinez la page et validez ce point manuellement selon le contexte.',
110
- 'manualReview_summary_cantTell': 'Vérification manuelle requise.',
111
- 'manualReview_title': 'Vérification manuelle requise.',
112
- "rules.img-alt-suspicious.meta.title":
113
- "Texte alternatif suspect nécessitant une vérification",
114
-
115
- "rules.img-alt-suspicious.meta.description":
116
- "Identifie les images dont le texte alternatif correspond à des motifs suspects courants (nom de fichier, URL, texte fictif ou terme générique) et nécessite une vérification manuelle.",
117
-
118
- "rules.img-alt-suspicious.occurrence.cantTell.summary":
119
- "Le texte alternatif de l’image semble suspect (« {{alt}} » ressemble à {{pattern}}) et nécessite une vérification.",
120
-
121
- "rules.img-alt-suspicious.occurrence.cantTell.hint":
122
- "Vérifiez le texte alternatif. Évitez les noms de fichiers, les URL, les textes fictifs ou les termes génériques, et assurez-vous que l’alternative textuelle décrit la fonction ou le contenu de l’image dans son contexte.",
123
- "formControl_programmaticLabelQuality_title":
124
- "Les champs de formulaire ne devraient pas dépendre du placeholder ou du title comme libellé principal",
125
- "formControl_programmaticLabelQuality_description":
126
- "Signale les champs de formulaire dont le nom accessible est principalement dérivé du placeholder ou de l’attribut title. Préférez un <label> ou aria-labelledby.",
127
- "formControl_programmaticLabelQuality_summary_cantTell":
128
- "Le libellé principal du champ provient de {{methodLabel}}.",
129
- "formControl_programmaticLabelQuality_hint_cantTell":
130
- "Préférez un <label> persistant ou aria-labelledby. Évitez d’utiliser placeholder/title comme libellé principal.",
131
- "html_lang_attr_title": 'La langue de la page est déclarée',
132
- "html_lang_attr_description": 'Vérifie que la langue par défaut de la page est déclarée de manière programmatique.',
133
-
134
- "html_lang_attr_missing_absent":
135
- 'La langue par défaut de la page n’est pas déclarée.',
136
- "html_lang_attr_hint_missing_absent":
137
- 'Ajoutez un attribut lang à l’élément <html> (par exemple : <html lang="fr">).',
138
-
139
- "html_lang_attr_missing_empty":
140
- 'La langue par défaut de la page est déclarée mais vide.',
141
-
142
- "html_lang_attr_hint_missing_empty":
143
- 'Renseignez une valeur de langue valide dans l’attribut lang de l’élément <html> (par exemple : <html lang="fr">).',
144
-
145
- "html_lang_attr_invalid":
146
- 'La langue par défaut de la page est déclarée, mais la valeur « {{lang}} » n’est pas une balise de langue valide.',
147
- "html_lang_attr_hint_invalid":
148
- 'Utilisez une balise de langue BCP 47 valide dans <html lang="…"> (par exemple : « fr », « en », « fr-FR »).',
149
-
150
- "mediaTranscriptPresent_title":
151
- "Média temporel : preuve de transcription ou d’alternative textuelle",
152
-
153
- "mediaTranscriptPresent_description":
154
- "Détecte les éléments audio et vidéo pour lesquels la présence d’une transcription ou d’une autre alternative textuelle n’est pas clairement établie dans le contenu de la page. Cette règle est volontairement conservatrice et retourne cantTell lorsque la preuve est absente ou invérifiable.",
155
-
156
- "mediaTranscriptPresent_summary_cantTell_missing":
157
- "Aucune transcription ou autre alternative textuelle pour ce média temporel n’est clairement établie sur la page.",
158
-
159
- "mediaTranscriptPresent_hint_cantTell_missing":
160
- "Fournir une transcription ou une autre alternative textuelle clairement identifiée pour les médias préenregistrés audio seuls ou vidéo seuls, par exemple une section ou un lien « Transcription » visible.",
161
-
162
- "mediaTranscriptPresent_summary_cantTell_unverified":
163
- "Une transcription ou une autre alternative textuelle peut être disponible pour ce média temporel, mais elle n’a pas pu être vérifiée à partir du contenu de la page.",
164
-
165
- "mediaTranscriptPresent_hint_cantTell_unverified":
166
- "Aucune transcription ou autre alternative textuelle pour cet élément {element} n’est clairement établie sur la page.",
167
-
168
- "pageTitlePresent_title": "La page possède un titre non vide",
169
- "pageTitlePresent_description":
170
- "Vérifie que la page contient un élément <title> non vide permettant d’identifier la page.",
171
-
172
- "pageTitlePresent_summary_fail":
173
- "La page ne possède pas de titre non vide.",
174
- "pageTitlePresent_hint_fail":
175
- "Ajouter un élément <title> contenant un texte décrivant le sujet ou l’objectif de la page.",
176
- "pageTitlePatterns_title":
177
- "Motifs de titres de page pouvant indiquer un manque de descriptivité",
178
- "pageTitlePatterns_description":
179
- "Identifie des motifs de titres de page pouvant indiquer un manque de descriptivité, tels que des titres génériques, dupliqués ou excessivement modélisés. Cette règle fournit des signaux de revue et n’entraîne pas d’échec automatique.",
180
-
181
- "pageTitlePatterns_summary_cantTell":
182
- "Le titre de la page peut ne pas être suffisamment descriptif pour identifier le sujet ou l’objectif de la page.",
183
-
184
- "pageTitlePresent_summary_fail_missing":
185
- "La page ne contient pas d’élément <title>.",
186
- "pageTitlePresent_summary_fail_empty":
187
- "La page contient un élément <title> vide.",
188
- "pageTitlePatterns_summary_cantTell_duplicateAcrossPages":
189
- "Plusieurs pages partagent le même titre, ce qui peut rendre plus difficile la distinction entre les pages ({{duplicateGroups}} groupes dupliqués sur {{pagesAnalyzed}} pages). Exemple : « {{exampleTitle}} ».",
190
-
191
- "pageTitlePatterns_summary_cantTell_templatedAcrossPages":
192
- "De nombreux titres de page semblent fortement modélisés, ce qui peut réduire la capacité des titres à distinguer les pages ({{pagesAnalyzed}} pages).",
193
-
194
- "pageTitlePatterns_summary_cantTell_generic":
195
- "Le titre de la page est générique et peut ne pas identifier le sujet ou l’objectif de la page.",
196
-
197
- "pageTitlePatterns_summary_cantTell_veryShort":
198
- "Le titre de la page est très court et peut ne pas identifier le sujet ou l’objectif de la page.",
199
-
200
- "pageTitlePatterns_summary_cantTell_templateLike":
201
- "Le titre de la page semble modélisé et peut ne pas identifier le sujet ou l’objectif de la page.",
202
-
203
- // Un seul conseil pour tous les cas
204
- "pageTitlePatterns_hint_cantTell":
205
- "Vérifier que le titre de la page identifie clairement le sujet ou l’objectif de la page et permet de la distinguer des autres pages.",
4
+ img_altPresent_title: '<img> doit avoir un attribut alt',
5
+ img_altPresent_description:
6
+ 'Vérifie que les éléments <img> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.',
7
+
8
+ img_altPresent_summary_fail: 'Attribut alt manquant sur <img>.',
9
+ img_altPresent_hint_fail:
10
+ 'Ajoutez un attribut alt (utilisez alt="" uniquement pour les images décoratives).',
11
+ area_altPresent_title: '<area> doit avoir un attribut alt',
12
+ area_altPresent_description:
13
+ 'Vérifie que les éléments <area> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.',
14
+ area_altPresent_summary_fail: 'Attribut alt manquant sur <area>.',
15
+ area_altPresent_hint_fail:
16
+ 'Ajoutez un attribut alt (utilisez alt="" uniquement pour les zones décoratives).',
17
+ inputImage_altPresent_title: '<input type="image"> doit avoir un attribut alt',
18
+ inputImage_altPresent_description:
19
+ 'Vérifie que les éléments <input type="image"> fournissent un attribut alt afin de proposer un mécanisme d’alternative textuelle.',
20
+ inputImage_altPresent_summary_fail: 'Attribut alt manquant sur <input type="image">.',
21
+ inputImage_altPresent_hint_fail:
22
+ 'Ajoutez un attribut alt (utilisez alt="" uniquement lorsqu’un nom accessible séparé est fourni).',
23
+ ariaHidden_programmaticFocus_review_title: 'Vérifier le focus programmatique avec aria-hidden',
24
+ ariaHidden_programmaticFocus_review_description:
25
+ 'Signale les éléments aria-hidden considérés comme éligibles uniquement via un focus programmatique (ex. tabindex < 0). Vérifiez l’intention de gestion du focus et l’exposition aux technologies d’assistance.',
26
+ ariaHidden_programmaticFocus_review_summary:
27
+ 'Vérification : un élément aria-hidden est focusable de façon programmatique.',
28
+ ariaHidden_programmaticFocus_review_hint:
29
+ 'Vérifiez que la gestion du focus est intentionnelle et que l’élément doit rester masqué aux technologies d’assistance.',
30
+ canvas_textAltPresent_title: '<canvas> doit fournir une alternative textuelle',
31
+ canvas_textAltPresent_description:
32
+ 'Vérifie que les éléments <canvas> fournissent une alternative textuelle via un contenu de repli ou un nom accessible.',
33
+ canvas_textAltPresent_summary_fail: 'Alternative textuelle manquante pour <canvas>.',
34
+ canvas_textAltPresent_hint_fail:
35
+ 'Fournissez un texte de repli dans <canvas> ou un nom accessible (par ex. aria-label/aria-labelledby).',
36
+ svg_textAltPresent_title: '<svg> doit fournir une alternative textuelle',
37
+ svg_textAltPresent_description:
38
+ 'Vérifie que les éléments <svg> en ligne fournissent une alternative textuelle via un élément <title> ou un nom ARIA (un élément <desc> seul ne suffit pas).',
39
+ svg_textAltPresent_summary_fail: 'Alternative textuelle manquante pour <svg>.',
40
+ svg_textAltPresent_hint_fail:
41
+ 'Fournissez un élément <title> avec du texte, ou un nom ARIA (aria-label/aria-labelledby) — un élément <desc> seul ne fournit pas de nom accessible.',
42
+ object_textAltPresent_title: '<object> doit fournir une alternative textuelle',
43
+ object_textAltPresent_description:
44
+ 'Vérifie que les éléments <object> fournissent une alternative textuelle via un contenu de repli ou un nom accessible.',
45
+ object_textAltPresent_summary_fail: 'Alternative textuelle manquante pour <object>.',
46
+ object_textAltPresent_hint_fail:
47
+ 'Fournissez un contenu de repli pertinent dans <object>, ajoutez un nom accessible (aria-label/aria-labelledby), ou utilisez un attribut title comme solution de repli.',
48
+ embed_textAltPresent_title: '<embed> doit fournir une alternative textuelle',
49
+ embed_textAltPresent_description:
50
+ 'Vérifie que les éléments <embed> fournissent une alternative textuelle via un nom accessible.',
51
+ embed_textAltPresent_summary_fail: 'Alternative textuelle manquante pour <embed>.',
52
+ embed_textAltPresent_hint_fail:
53
+ 'Ajoutez un nom accessible à <embed> (aria-label/aria-labelledby de préférence, ou un attribut title comme solution de repli).',
54
+ img_altQuality_title: '<img> : texte alt à vérifier (revue manuelle)',
55
+ img_altQuality_description:
56
+ 'Signale les éléments <img> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.',
57
+ img_altQuality_summary_cantTell: 'Vérifiez le texte alt de <img> (exactitude et pertinence).',
58
+ img_altQuality_hint_cantTell:
59
+ 'Assurez-vous que le texte alt exprime le but/l’information de l’image dans son contexte (ni redondant, ni nom de fichier).',
60
+ img_altDecorative_title: '<img> avec alt="" : décoratif à confirmer (revue manuelle)',
61
+ img_altDecorative_description:
62
+ 'Signale les éléments <img> dont l’attribut alt est vide afin de confirmer qu’ils sont purement décoratifs.',
63
+ img_altDecorative_summary_cantTell: 'Vérifiez si <img> est décoratif (alt="").',
64
+ img_altDecorative_hint_cantTell:
65
+ 'Confirmez que l’image est purement décorative. Sinon, fournissez un texte alt pertinent.',
66
+ area_altQuality_title: '<area> : texte alt à vérifier (revue manuelle)',
67
+ area_altQuality_description:
68
+ 'Signale les éléments <area> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.',
69
+ area_altQuality_summary_cantTell: 'Vérifiez le texte alt de <area> (exactitude et pertinence).',
70
+ area_altQuality_hint_cantTell:
71
+ 'Assurez-vous que le texte alt identifie la destination/l’action de la zone dans son contexte.',
72
+ area_altDecorative_title: '<area> avec alt="" : décoratif à confirmer (revue manuelle)',
73
+ area_altDecorative_description:
74
+ 'Signale les éléments <area> dont l’attribut alt est vide afin de confirmer qu’ils sont décoratifs ou non informatifs.',
75
+ area_altDecorative_summary_cantTell: 'Vérifiez si <area> est décoratif (alt="").',
76
+ area_altDecorative_hint_cantTell:
77
+ 'Confirmez que la zone n’a pas de fonction ni d’information. Sinon, fournissez un texte alt pertinent.',
78
+ inputImage_altQuality_title: '<input type="image"> : texte alt à vérifier (revue manuelle)',
79
+ inputImage_altQuality_description:
80
+ 'Signale les éléments <input type="image"> dont l’attribut alt n’est pas vide afin de vérifier manuellement sa pertinence.',
81
+ inputImage_altQuality_summary_cantTell:
82
+ 'Vérifiez le texte alt de <input type="image"> (exactitude et pertinence).',
83
+ inputImage_altQuality_hint_cantTell:
84
+ 'Assurez-vous que le texte alt décrit l’action du contrôle (ex. « Rechercher », « Envoyer ») dans son contexte.',
85
+ inputImage_altDecorative_title: '<input type="image"> avec alt="" : à vérifier (revue manuelle)',
86
+ inputImage_altDecorative_description:
87
+ 'Signale les éléments <input type="image"> dont l’attribut alt est vide afin de vérifier manuellement (souvent inadapté pour un contrôle fonctionnel).',
88
+ inputImage_altDecorative_summary_cantTell: 'Vérifiez <input type="image"> avec alt="".',
89
+ inputImage_altDecorative_hint_cantTell:
90
+ 'Ce contrôle est généralement fonctionnel. Confirmez qu’un nom accessible équivalent existe, sinon fournissez un texte alt pertinent.',
91
+ canvas_textAltQuality_title: '<canvas> : alternative textuelle à vérifier (revue manuelle)',
92
+ canvas_textAltQuality_description:
93
+ 'Signale les éléments <canvas> pour lesquels une alternative textuelle a été détectée, afin de vérifier manuellement son équivalence.',
94
+ canvas_textAltQuality_summary_cantTell:
95
+ 'Vérifiez l’alternative textuelle de <canvas> (équivalence et pertinence).',
96
+ canvas_textAltQuality_hint_cantTell:
97
+ 'Confirmez que le texte de secours ou le nom accessible transmet la même information/fonction que le contenu du canvas.',
98
+ svg_textAltQuality_title: '<svg> : alternative textuelle à vérifier (revue manuelle)',
99
+ svg_textAltQuality_description:
100
+ 'Signale les graphiques <svg> pour lesquels une alternative textuelle a été détectée, afin de vérifier manuellement sa pertinence.',
101
+ svg_textAltQuality_summary_cantTell:
102
+ 'Vérifiez l’alternative textuelle de <svg> (exactitude et pertinence).',
103
+ svg_textAltQuality_hint_cantTell:
104
+ 'Confirmez que <title>/<desc> ou le nom ARIA transmet le sens/le but du graphique dans son contexte.',
105
+ object_textAltQuality_title: '<object> : alternative textuelle à vérifier (revue manuelle)',
106
+ object_textAltQuality_description:
107
+ 'Signale les éléments <object> avec contenu de secours ou nom détecté, afin de vérifier manuellement l’équivalence.',
108
+ object_textAltQuality_summary_cantTell:
109
+ 'Vérifiez l’alternative textuelle de <object> (équivalence et pertinence).',
110
+ object_textAltQuality_hint_cantTell:
111
+ 'Confirmez que le contenu de secours ou le nom ARIA fournit une alternative équivalente au contenu embarqué.',
112
+ embed_textAltQuality_title: '<embed> : alternative textuelle à vérifier (revue manuelle)',
113
+ embed_textAltQuality_description:
114
+ 'Signale les éléments <embed> avec nom détecté, afin de vérifier manuellement sa pertinence.',
115
+ embed_textAltQuality_summary_cantTell:
116
+ 'Vérifiez l’alternative textuelle de <embed> (exactitude et pertinence).',
117
+ embed_textAltQuality_hint_cantTell:
118
+ 'Confirmez que le nom ARIA ou l’attribut title identifie correctement le contenu embarqué dans son contexte.',
119
+ videoPoster_textAltPresent_title:
120
+ 'L’image poster de <video> doit avoir une alternative textuelle',
121
+ videoPoster_textAltPresent_description:
122
+ 'Vérifie que les éléments <video> avec une image poster fournissent une alternative textuelle (nom accessible).',
123
+ videoPoster_textAltPresent_summary_fail:
124
+ 'Alternative textuelle manquante pour l’image poster de <video>.',
125
+ videoPoster_textAltPresent_hint_fail:
126
+ 'Fournissez un nom accessible pour l’image poster (aria-label/aria-labelledby de préférence, ou un attribut title comme solution de repli).',
127
+ svgImage_textAltPresent_title: '<image> dans un SVG doit avoir une alternative textuelle',
128
+ svgImage_textAltPresent_description:
129
+ 'Vérifie que les éléments SVG <image> fournissent une alternative textuelle via <title>/<desc> ou un nom accessible ARIA.',
130
+ svgImage_textAltPresent_summary_fail: 'Alternative textuelle manquante sur <image> (SVG).',
131
+ svgImage_textAltPresent_hint_fail:
132
+ 'Ajoutez un <title> (et éventuellement <desc>) dans <image>, ou fournissez aria-label/aria-labelledby.',
133
+ formControl_programmaticLabelPresent_title:
134
+ 'Les contrôles de formulaire doivent avoir un libellé programmatique',
135
+
136
+ formControl_programmaticLabelPresent_description:
137
+ 'Vérifie que les contrôles de formulaire ont un libellé programmatique via <label>, aria-label ou aria-labelledby.',
138
+
139
+ formControl_programmaticLabelPresent_summary_fail:
140
+ 'Le contrôle de formulaire n’a pas de libellé programmatique.',
141
+
142
+ formControl_programmaticLabelPresent_hint_fail:
143
+ 'Associez un <label>, ou utilisez aria-label / aria-labelledby (placeholder/title ne sont pas des libellés).',
144
+
145
+ formControlAccessibleName_description:
146
+ 'Échec lorsqu’un contrôle de formulaire applicable n’a pas de nom accessible (ex. label, aria-label, aria-labelledby).',
147
+ formControlAccessibleName_hint_fail:
148
+ 'Fournissez un nom accessible via un <label>, aria-label ou aria-labelledby.',
149
+ formControlAccessibleName_summary_fail: 'Le contrôle de formulaire n’a pas de nom accessible.',
150
+ formControlAccessibleName_title: 'Les champs de formulaire doivent avoir un nom accessible.',
151
+ linksTargetBlankNoopener_description:
152
+ 'Échec lorsqu’un lien avec target="_blank" n’inclut pas rel="noopener" (risque de sécurité via window.opener).',
153
+ linksTargetBlankNoopener_hint_cantTell:
154
+ 'Ajoutez rel="noopener" (et éventuellement noreferrer) aux liens avec target="_blank".',
155
+ linksTargetBlankNoopener_summary_cantTell: 'Lien avec target="_blank" sans rel="noopener".',
156
+ linksTargetBlankNoopener_title:
157
+ 'Les liens qui s’ouvrent dans un nouvel onglet doivent utiliser rel="noopener".',
158
+ manualReview_description:
159
+ 'Cette règle renvoie toujours cantTell et nécessite une vérification manuelle.',
160
+ manualReview_hint_cantTell:
161
+ 'Examinez la page et validez ce point manuellement selon le contexte.',
162
+ manualReview_summary_cantTell: 'Vérification manuelle requise.',
163
+ manualReview_title: 'Vérification manuelle requise.',
164
+ 'rules.img-alt-suspicious.meta.title': 'Texte alternatif suspect nécessitant une vérification',
165
+
166
+ 'rules.img-alt-suspicious.meta.description':
167
+ 'Identifie les images dont le texte alternatif correspond à des motifs suspects courants (nom de fichier, URL, texte fictif ou terme générique) et nécessite une vérification manuelle.',
168
+
169
+ 'rules.img-alt-suspicious.occurrence.cantTell.summary':
170
+ 'Le texte alternatif de l’image semble suspect (« {{alt}} » ressemble à {{pattern}}) et nécessite une vérification.',
171
+
172
+ 'rules.img-alt-suspicious.occurrence.cantTell.hint':
173
+ 'Vérifiez le texte alternatif. Évitez les noms de fichiers, les URL, les textes fictifs ou les termes génériques, et assurez-vous que l’alternative textuelle décrit la fonction ou le contenu de l’image dans son contexte.',
174
+ formControl_programmaticLabelQuality_title:
175
+ 'Les champs de formulaire ne devraient pas dépendre du placeholder ou du title comme libellé principal',
176
+ formControl_programmaticLabelQuality_description:
177
+ 'Signale les champs de formulaire dont le nom accessible est principalement dérivé du placeholder ou de l’attribut title. Préférez un <label> ou aria-labelledby.',
178
+ formControl_programmaticLabelQuality_summary_cantTell:
179
+ 'Le libellé principal du champ provient de {{methodLabel}}.',
180
+ formControl_programmaticLabelQuality_hint_cantTell:
181
+ 'Préférez un <label> persistant ou aria-labelledby. Évitez d’utiliser placeholder/title comme libellé principal.',
182
+ html_lang_attr_title: 'La langue de la page est déclarée',
183
+ html_lang_attr_description:
184
+ 'Vérifie que la langue par défaut de la page est déclarée de manière programmatique.',
185
+
186
+ html_lang_attr_missing_absent: 'La langue par défaut de la page n’est pas déclarée.',
187
+ html_lang_attr_hint_missing_absent:
188
+ 'Ajoutez un attribut lang à l’élément <html> (par exemple : <html lang="fr">).',
189
+
190
+ html_lang_attr_missing_empty: 'La langue par défaut de la page est déclarée mais vide.',
191
+
192
+ html_lang_attr_hint_missing_empty:
193
+ 'Renseignez une valeur de langue valide dans l’attribut lang de l’élément <html> (par exemple : <html lang="fr">).',
194
+
195
+ html_lang_attr_invalid:
196
+ 'La langue par défaut de la page est déclarée, mais la valeur « {{lang}} » n’est pas une balise de langue valide.',
197
+ html_lang_attr_hint_invalid:
198
+ 'Utilisez une balise de langue BCP 47 valide dans <html lang="…"> (par exemple : « fr », « en », « fr-FR »).',
199
+
200
+ mediaTranscriptPresent_title:
201
+ 'Média temporel : preuve de transcription ou d’alternative textuelle',
202
+
203
+ mediaTranscriptPresent_description:
204
+ 'Détecte les éléments audio et vidéo pour lesquels la présence d’une transcription ou d’une autre alternative textuelle n’est pas clairement établie dans le contenu de la page. Cette règle est volontairement conservatrice et retourne cantTell lorsque la preuve est absente ou invérifiable.',
205
+
206
+ mediaTranscriptPresent_summary_cantTell_missing:
207
+ 'Aucune transcription ou autre alternative textuelle pour ce média temporel n’est clairement établie sur la page.',
208
+
209
+ mediaTranscriptPresent_hint_cantTell_missing:
210
+ 'Fournir une transcription ou une autre alternative textuelle clairement identifiée pour les médias préenregistrés audio seuls ou vidéo seuls, par exemple une section ou un lien « Transcription » visible.',
211
+
212
+ mediaTranscriptPresent_summary_cantTell_unverified:
213
+ 'Une transcription ou une autre alternative textuelle peut être disponible pour ce média temporel, mais elle n’a pas pu être vérifiée à partir du contenu de la page.',
214
+
215
+ mediaTranscriptPresent_hint_cantTell_unverified:
216
+ 'Aucune transcription ou autre alternative textuelle pour cet élément {element} n’est clairement établie sur la page.',
217
+
218
+ pageTitlePresent_title: 'La page possède un titre non vide',
219
+ pageTitlePresent_description:
220
+ 'Vérifie que la page contient un élément <title> non vide permettant d’identifier la page.',
221
+
222
+ pageTitlePresent_summary_fail: 'La page ne possède pas de titre non vide.',
223
+ pageTitlePresent_hint_fail:
224
+ 'Ajouter un élément <title> contenant un texte décrivant le sujet ou l’objectif de la page.',
225
+ pageTitlePatterns_title: 'Motifs de titres de page pouvant indiquer un manque de descriptivité',
226
+ pageTitlePatterns_description:
227
+ 'Identifie des motifs de titres de page pouvant indiquer un manque de descriptivité, tels que des titres génériques, dupliqués ou excessivement modélisés. Cette règle fournit des signaux de revue et n’entraîne pas d’échec automatique.',
228
+
229
+ pageTitlePatterns_summary_cantTell:
230
+ 'Le titre de la page peut ne pas être suffisamment descriptif pour identifier le sujet ou l’objectif de la page.',
231
+
232
+ pageTitlePresent_summary_fail_missing: 'La page ne contient pas d’élément <title>.',
233
+ pageTitlePresent_summary_fail_empty: 'La page contient un élément <title> vide.',
234
+ pageTitlePatterns_summary_cantTell_duplicateAcrossPages:
235
+ 'Plusieurs pages partagent le même titre, ce qui peut rendre plus difficile la distinction entre les pages ({{duplicateGroups}} groupes dupliqués sur {{pagesAnalyzed}} pages). Exemple : « {{exampleTitle}} ».',
236
+
237
+ pageTitlePatterns_summary_cantTell_templatedAcrossPages:
238
+ 'De nombreux titres de page semblent fortement modélisés, ce qui peut réduire la capacité des titres à distinguer les pages ({{pagesAnalyzed}} pages).',
239
+
240
+ pageTitlePatterns_summary_cantTell_generic:
241
+ 'Le titre de la page est générique et peut ne pas identifier le sujet ou l’objectif de la page.',
242
+
243
+ pageTitlePatterns_summary_cantTell_veryShort:
244
+ 'Le titre de la page est très court et peut ne pas identifier le sujet ou l’objectif de la page.',
245
+
246
+ pageTitlePatterns_summary_cantTell_templateLike:
247
+ 'Le titre de la page semble modélisé et peut ne pas identifier le sujet ou l’objectif de la page.',
248
+
249
+ // Un seul conseil pour tous les cas
250
+ pageTitlePatterns_hint_cantTell:
251
+ 'Vérifier que le titre de la page identifie clairement le sujet ou l’objectif de la page et permet de la distinguer des autres pages.',
206
252
 
207
253
  // --- Contraste DOM : calculabilité (porte d’entrée)
208
- "contrastComputable_title": 'Le contraste des couleurs est calculable pour le texte rendu',
209
- "contrastComputable_description":
210
- 'Détermine si suffisamment d’informations sont disponibles pour calculer le contraste WCAG du texte visible (ex. pas de dégradés/images/modes de fusion rendant l’arrière-plan indéterminé).',
211
- "contrastComputable_pass_allComputable":
212
- 'Le contraste est calculable pour tout le texte éligible ({{eligibleTextCount}} nœud(s) de texte).',
254
+ contrastComputable_title: 'Le contraste des couleurs est calculable pour le texte rendu',
255
+ contrastComputable_description:
256
+ 'Détermine si suffisamment d’informations sont disponibles pour calculer le contraste WCAG du texte visible (ex. pas de dégradés/images/modes de fusion rendant l’arrière-plan indéterminé).',
257
+ contrastComputable_pass_allComputable:
258
+ 'Le contraste est calculable pour tout le texte éligible ({{eligibleTextCount}} nœud(s) de texte).',
213
259
 
214
- "contrastComputable_cantTell_generic":
215
- 'Le contraste peut ne pas être calculable ({{reasonCode}}).',
260
+ contrastComputable_cantTell_generic: 'Le contraste peut ne pas être calculable ({{reasonCode}}).',
216
261
 
217
- "contrastComputable_cantTell_bgImageOrGradient":
218
- 'Le contraste n’est pas calculable car l’arrière-plan utilise une image ou un dégradé ({{blockerProperty}}={{blockerValue}}).',
262
+ contrastComputable_cantTell_bgImageOrGradient:
263
+ 'Le contraste n’est pas calculable car l’arrière-plan utilise une image ou un dégradé ({{blockerProperty}}={{blockerValue}}).',
219
264
 
220
- "contrastComputable_cantTell_bgImage":
221
- "Le contraste ne peut pas être calculé car l’arrière-plan utilise une image ({{blockerProperty}}={{blockerValue}}).",
265
+ contrastComputable_cantTell_bgImage:
266
+ 'Le contraste ne peut pas être calculé car l’arrière-plan utilise une image ({{blockerProperty}}={{blockerValue}}).',
222
267
 
223
- "contrastComputable_cantTell_bgGradient":
224
- "Le contraste ne peut pas être calculé car l’arrière-plan utilise un dégradé ({{blockerProperty}}={{blockerValue}}).",
268
+ contrastComputable_cantTell_bgGradient:
269
+ 'Le contraste ne peut pas être calculé car l’arrière-plan utilise un dégradé ({{blockerProperty}}={{blockerValue}}).',
225
270
 
226
- "contrastComputable_cantTell_bgImageAndGradient":
227
- "Le contraste ne peut pas être calculé car l’arrière-plan utilise une image et un dégradé ({{blockerProperty}}={{blockerValue}}).",
271
+ contrastComputable_cantTell_bgImageAndGradient:
272
+ 'Le contraste ne peut pas être calculé car l’arrière-plan utilise une image et un dégradé ({{blockerProperty}}={{blockerValue}}).',
228
273
 
229
- "contrastComputable_cantTell_mixBlendMode":
230
- 'Le contraste n’est pas calculable car mix-blend-mode est utilisé ({{blockerProperty}}={{blockerValue}}).',
274
+ contrastComputable_cantTell_mixBlendMode:
275
+ 'Le contraste n’est pas calculable car mix-blend-mode est utilisé ({{blockerProperty}}={{blockerValue}}).',
231
276
 
232
- "contrastComputable_cantTell_filter":
233
- "Le contraste ne peut pas être calculé car la propriété filter est utilisée ({{blockerProperty}}={{blockerValue}}).",
277
+ contrastComputable_cantTell_filter:
278
+ 'Le contraste ne peut pas être calculé car la propriété filter est utilisée ({{blockerProperty}}={{blockerValue}}).',
234
279
 
235
- "contrastComputable_cantTell_rootNotOpaque":
236
- 'Le contraste n’est pas calculable car l’arrière-plan effectif n’est pas totalement opaque à la racine (alpha={{backgroundAlpha}}).',
280
+ contrastComputable_cantTell_rootNotOpaque:
281
+ 'Le contraste n’est pas calculable car l’arrière-plan effectif n’est pas totalement opaque à la racine (alpha={{backgroundAlpha}}).',
237
282
 
238
- "contrastComputable_cantTell_foregroundUnparsable":
239
- 'Le contraste n’est pas calculable car la couleur de premier plan calculée n’a pas pu être analysée.',
283
+ contrastComputable_cantTell_foregroundUnparsable:
284
+ 'Le contraste n’est pas calculable car la couleur de premier plan calculée n’a pas pu être analysée.',
240
285
 
241
- "contrastComputable_cantTell_engineFailure":
242
- 'La calculabilité du contraste n’a pas pu être déterminée en raison d’une erreur interne du moteur ({{reasonCode}}).',
286
+ contrastComputable_cantTell_engineFailure:
287
+ 'La calculabilité du contraste n’a pas pu être déterminée en raison d’une erreur interne du moteur ({{reasonCode}}).',
243
288
 
244
- "contrastComputable_cantTell_backdropFilter":
245
- "Le contraste ne peut pas être calculé car la propriété backdrop-filter est utilisée ({{blockerProperty}}={{blockerValue}}).",
289
+ contrastComputable_cantTell_backdropFilter:
290
+ 'Le contraste ne peut pas être calculé car la propriété backdrop-filter est utilisée ({{blockerProperty}}={{blockerValue}}).',
246
291
 
247
- "contrastComputable_cantTell_filterOrBackdropFilter":
248
- "Le contraste ne peut pas être calculé car une propriété filter ou backdrop-filter est utilisée ({{blockerProperty}}={{blockerValue}}).",
292
+ contrastComputable_cantTell_filterOrBackdropFilter:
293
+ 'Le contraste ne peut pas être calculé car une propriété filter ou backdrop-filter est utilisée ({{blockerProperty}}={{blockerValue}}).',
249
294
 
250
- // --- Contraste DOM : minimum AA (1.4.3)
251
- "contrastMinimum_title": 'Le texte respecte le contraste minimum (AA)',
252
- "contrastMinimum_description":
253
- 'Vérifie que le texte visible atteint un ratio de contraste d’au moins 4,5:1 (texte normal) ou 3,0:1 (grand texte), lorsque le contraste est calculable à partir du CSS.',
295
+ // --- Contraste DOM : minimum AA (1.4.3)
296
+ contrastMinimum_title: 'Le texte respecte le contraste minimum (AA)',
297
+ contrastMinimum_description:
298
+ 'Vérifie que le texte visible atteint un ratio de contraste d’au moins 4,5:1 (texte normal) ou 3,0:1 (grand texte), lorsque le contraste est calculable à partir du CSS.',
254
299
 
255
- "contrastMinimum_fail_belowThreshold":
256
- "L’élément présente un contraste de couleur insuffisant de {{ratio}}:1 (premier plan : {{foregroundHex}}, arrière-plan : {{backgroundHex}}, taille de police : {{fontSizePx}}px, graisse de police : {{fontWeightLabel}}). Le ratio de contraste attendu est de {{threshold}}:1 ({{#isLargeText}}texte de grande taille{{/isLargeText}}{{^isLargeText}}texte normal{{/isLargeText}}).",
300
+ contrastMinimum_fail_belowThreshold:
301
+ 'L’élément présente un contraste de couleur insuffisant de {{ratio}}:1 (premier plan : {{foregroundHex}}, arrière-plan : {{backgroundHex}}, taille de police : {{fontSizePx}}px, graisse de police : {{fontWeightLabel}}). Le ratio de contraste attendu est de {{threshold}}:1 ({{#isLargeText}}texte de grande taille{{/isLargeText}}{{^isLargeText}}texte normal{{/isLargeText}}).',
257
302
 
258
- "contrastMinimum_pass_allAboveThreshold":
259
- 'Tout le texte calculable respecte le contraste minimum (AA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
303
+ contrastMinimum_pass_allAboveThreshold:
304
+ 'Tout le texte calculable respecte le contraste minimum (AA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
260
305
 
261
- "contrastMinimum_notApplicable_noComputableText":
262
- 'Aucun texte éligible n’avait un contraste calculable (nœuds de texte éligibles : {{eligibleTextCount}}). Voir la règle de calculabilité du contraste pour les détails.',
306
+ contrastMinimum_notApplicable_noComputableText:
307
+ 'Aucun texte éligible n’avait un contraste calculable (nœuds de texte éligibles : {{eligibleTextCount}}). Voir la règle de calculabilité du contraste pour les détails.',
263
308
 
264
- "contrastMinimum_cantTell_engineFailure":
265
- 'Le contraste minimum (AA) n’a pas pu être déterminé en raison d’une erreur interne du moteur ({{reasonCode}}).',
309
+ contrastMinimum_cantTell_engineFailure:
310
+ 'Le contraste minimum (AA) n’a pas pu être déterminé en raison d’une erreur interne du moteur ({{reasonCode}}).',
266
311
 
267
- // --- Contraste DOM : renforcé AAA (1.4.6)
268
- "contrastEnhanced_title": 'Le texte respecte le contraste renforcé (AAA)',
269
- "contrastEnhanced_description":
270
- 'Vérifie que le texte visible atteint un ratio de contraste d’au moins 7,0:1 (texte normal) ou 4,5:1 (grand texte), lorsque le contraste est calculable à partir du CSS.',
312
+ // --- Contraste DOM : renforcé AAA (1.4.6)
313
+ contrastEnhanced_title: 'Le texte respecte le contraste renforcé (AAA)',
314
+ contrastEnhanced_description:
315
+ 'Vérifie que le texte visible atteint un ratio de contraste d’au moins 7,0:1 (texte normal) ou 4,5:1 (grand texte), lorsque le contraste est calculable à partir du CSS.',
271
316
 
272
- // --- 1) Contraste du texte (Minimum) — WCAG 1.4.3 (AA)
273
- "dom_textContrastMinimum_title": "Le texte doit avoir un contraste suffisant (minimum)",
274
- "dom_textContrastMinimum_description": "Vérifie le contraste du texte visible par rapport à son arrière-plan calculé selon WCAG 2.2 SC 1.4.3 (AA), en utilisant les styles rendus (taille/épaisseur) pour déterminer le ratio requis.",
317
+ // --- 1) Contraste du texte (Minimum) — WCAG 1.4.3 (AA)
318
+ dom_textContrastMinimum_title: 'Le texte doit avoir un contraste suffisant (minimum)',
319
+ dom_textContrastMinimum_description:
320
+ 'Vérifie le contraste du texte visible par rapport à son arrière-plan calculé selon WCAG 2.2 SC 1.4.3 (AA), en utilisant les styles rendus (taille/épaisseur) pour déterminer le ratio requis.',
275
321
 
276
- "dom_textContrastMinimum_summary_fail":
277
- "Contraste de texte insuffisant : {{contrastRatio}}:1 (minimum requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.",
278
- "dom_textContrastMinimum_hint_fail":
279
- "Ajustez la couleur du texte ou l’arrière-plan afin d’atteindre au moins {{requiredRatio}}:1 pour cette taille/épaisseur de texte.",
322
+ dom_textContrastMinimum_summary_fail:
323
+ 'Contraste de texte insuffisant : {{contrastRatio}}:1 (minimum requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.',
324
+ dom_textContrastMinimum_hint_fail:
325
+ 'Ajustez la couleur du texte ou l’arrière-plan afin d’atteindre au moins {{requiredRatio}}:1 pour cette taille/épaisseur de texte.',
280
326
 
281
- "dom_textContrastMinimum_summary_pass":
282
- "Contraste de texte conforme : {{contrastRatio}}:1 (minimum requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.",
327
+ dom_textContrastMinimum_summary_pass:
328
+ 'Contraste de texte conforme : {{contrastRatio}}:1 (minimum requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.',
283
329
 
284
- "dom_textContrastMinimum_summary_cantTell":
285
- "Impossible de calculer fiablement le contraste du texte car l’arrière-plan effectif n’est pas déterminable de manière fiable (ex. image, dégradé, vidéo, canvas, transparence ou fusion complexes).",
286
- "dom_textContrastMinimum_hint_cantTell":
287
- "Vérifiez manuellement le contraste lorsque le texte est superposé à des images/dégradés/transparences ; assurez-vous qu’il respecte {{requiredRatio}}:1 selon la taille/épaisseur calculée.",
330
+ dom_textContrastMinimum_summary_cantTell:
331
+ 'Impossible de calculer fiablement le contraste du texte car l’arrière-plan effectif n’est pas déterminable de manière fiable (ex. image, dégradé, vidéo, canvas, transparence ou fusion complexes).',
332
+ dom_textContrastMinimum_hint_cantTell:
333
+ 'Vérifiez manuellement le contraste lorsque le texte est superposé à des images/dégradés/transparences ; assurez-vous qu’il respecte {{requiredRatio}}:1 selon la taille/épaisseur calculée.',
288
334
 
289
- "contrastEnhanced_fail_belowThreshold":
290
- "L’élément présente un contraste de couleur insuffisant renforcé (AAA) de {{ratio}}:1 (premier plan : {{foregroundHex}}, arrière-plan : {{backgroundHex}}, taille de police : {{fontSizePx}}px, graisse de police : {{fontWeightLabel}}). Le ratio de contraste attendu est de {{threshold}}:1 ({{#isLargeText}}texte de grande taille{{/isLargeText}}{{^isLargeText}}texte normal{{/isLargeText}}).",
335
+ contrastEnhanced_fail_belowThreshold:
336
+ 'L’élément présente un contraste de couleur insuffisant renforcé (AAA) de {{ratio}}:1 (premier plan : {{foregroundHex}}, arrière-plan : {{backgroundHex}}, taille de police : {{fontSizePx}}px, graisse de police : {{fontWeightLabel}}). Le ratio de contraste attendu est de {{threshold}}:1 ({{#isLargeText}}texte de grande taille{{/isLargeText}}{{^isLargeText}}texte normal{{/isLargeText}}).',
291
337
 
292
- "contrastEnhanced_pass_allAboveThreshold":
293
- 'Tout le texte calculable respecte le contraste renforcé (AAA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
338
+ contrastEnhanced_pass_allAboveThreshold:
339
+ 'Tout le texte calculable respecte le contraste renforcé (AAA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
294
340
 
295
- "contrastEnhanced_notApplicable_noComputableText":
296
- 'Aucun texte éligible n’avait un contraste calculable (nœuds de texte éligibles : {{eligibleTextCount}}). Voir la règle de calculabilité du contraste pour les détails.',
341
+ contrastEnhanced_notApplicable_noComputableText:
342
+ 'Aucun texte éligible n’avait un contraste calculable (nœuds de texte éligibles : {{eligibleTextCount}}). Voir la règle de calculabilité du contraste pour les détails.',
297
343
 
298
- "contrastEnhanced_cantTell_engineFailure":
299
- 'Le contraste renforcé (AAA) n’a pas pu être déterminé en raison d’une erreur interne du moteur ({{reasonCode}}).',
344
+ contrastEnhanced_cantTell_engineFailure:
345
+ 'Le contraste renforcé (AAA) n’a pas pu être déterminé en raison d’une erreur interne du moteur ({{reasonCode}}).',
300
346
 
301
347
  // --- 2) Contraste du texte (Renforcé) — WCAG 1.4.6 (AAA)
302
- "dom_textContrastEnhanced_title": "Le texte doit avoir un contraste suffisant (renforcé)",
303
- "dom_textContrastEnhanced_description": "Vérifie le contraste du texte visible par rapport à son arrière-plan calculé selon WCAG 2.2 SC 1.4.6 (AAA), en utilisant les styles rendus (taille/épaisseur) pour déterminer le ratio requis.",
348
+ dom_textContrastEnhanced_title: 'Le texte doit avoir un contraste suffisant (renforcé)',
349
+ dom_textContrastEnhanced_description:
350
+ 'Vérifie le contraste du texte visible par rapport à son arrière-plan calculé selon WCAG 2.2 SC 1.4.6 (AAA), en utilisant les styles rendus (taille/épaisseur) pour déterminer le ratio requis.',
304
351
 
305
- "dom_textContrastEnhanced_summary_fail":
306
- "Contraste de texte renforcé insuffisant : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.",
307
- "dom_textContrastEnhanced_hint_fail":
308
- "Ajustez la couleur du texte ou l’arrière-plan afin d’atteindre au moins {{requiredRatio}}:1 pour le niveau renforcé (AAA).",
352
+ dom_textContrastEnhanced_summary_fail:
353
+ 'Contraste de texte renforcé insuffisant : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.',
354
+ dom_textContrastEnhanced_hint_fail:
355
+ 'Ajustez la couleur du texte ou l’arrière-plan afin d’atteindre au moins {{requiredRatio}}:1 pour le niveau renforcé (AAA).',
309
356
 
310
- "dom_textContrastEnhanced_summary_pass":
311
- "Contraste de texte renforcé conforme : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.",
357
+ dom_textContrastEnhanced_summary_pass:
358
+ 'Contraste de texte renforcé conforme : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} sur arrière-plan {{bgColor}}. Police {{fontSizePx}}px, graisse {{fontWeight}}{{#isBold}}, en gras{{/isBold}}{{#isLargeText}} (grand texte){{/isLargeText}}.',
312
359
 
313
- "dom_textContrastEnhanced_summary_cantTell":
314
- "Impossible de calculer fiablement le contraste renforcé car l’arrière-plan effectif n’est pas déterminable de manière fiable (ex. image, dégradé, vidéo, canvas, transparence ou fusion complexes).",
315
- "dom_textContrastEnhanced_hint_cantTell":
316
- "Vérifiez manuellement le contraste renforcé (AAA) lorsque le texte est superposé à des images/dégradés/transparences ; assurez-vous qu’il respecte {{requiredRatio}}:1 selon la taille/épaisseur calculée.",
360
+ dom_textContrastEnhanced_summary_cantTell:
361
+ 'Impossible de calculer fiablement le contraste renforcé car l’arrière-plan effectif n’est pas déterminable de manière fiable (ex. image, dégradé, vidéo, canvas, transparence ou fusion complexes).',
362
+ dom_textContrastEnhanced_hint_cantTell:
363
+ 'Vérifiez manuellement le contraste renforcé (AAA) lorsque le texte est superposé à des images/dégradés/transparences ; assurez-vous qu’il respecte {{requiredRatio}}:1 selon la taille/épaisseur calculée.',
317
364
 
318
365
  // --- 3) Contraste non-textuel — WCAG 1.4.11 (AA)
319
- "dom_nonTextContrast_title": "Les composants d’interface et les graphiques doivent avoir un contraste suffisant",
320
- "dom_nonTextContrast_description": "Vérifie le contraste des informations visuelles non textuelles (contours de composants, états, et objets graphiques porteurs d’information) selon WCAG 2.2 SC 1.4.11 (AA).",
366
+ dom_nonTextContrast_title:
367
+ 'Les composants d’interface et les graphiques doivent avoir un contraste suffisant',
368
+ dom_nonTextContrast_description:
369
+ 'Vérifie le contraste des informations visuelles non textuelles (contours de composants, états, et objets graphiques porteurs d’information) selon WCAG 2.2 SC 1.4.11 (AA).',
370
+
371
+ dom_nonTextContrast_summary_fail:
372
+ 'Contraste non-textuel insuffisant : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} par rapport à {{bgColor}}. Composant : {{componentKind}}{{#componentState}} (état : {{componentState}}){{/componentState}}.',
373
+ dom_nonTextContrast_hint_fail:
374
+ 'Ajustez les couleurs du composant/graphique afin d’atteindre au moins {{requiredRatio}}:1 pour le contour perceptible ou l’information visuelle essentielle.',
375
+
376
+ dom_nonTextContrast_summary_pass:
377
+ 'Contraste non-textuel conforme : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} par rapport à {{bgColor}}. Composant : {{componentKind}}{{#componentState}} (état : {{componentState}}){{/componentState}}.',
378
+
379
+ dom_nonTextContrast_summary_cantTell:
380
+ 'Impossible de calculer fiablement le contraste non-textuel car l’arrière-plan effectif ou les pixels peints ne sont pas déterminables (ex. image/dégradé/vidéo/canvas, transparence ou fusion complexes).',
381
+ dom_nonTextContrast_hint_cantTell:
382
+ 'Vérifiez manuellement le contraste du composant/graphique par rapport aux couleurs adjacentes ; assurez-vous qu’il respecte {{requiredRatio}}:1 pour l’information visuelle non textuelle essentielle.',
383
+ contrastEnhanced_pass_allTextMeetsThreshold:
384
+ 'Tout le texte calculable respecte le contraste renforcé (AAA).',
385
+ contrastMinimum_pass_allTextMeetsThreshold:
386
+ 'Tout le texte calculable respecte le contraste minimum (AA).',
387
+ contrastComputable_cantTell_notComputable:
388
+ 'Le contraste ne peut pas être calculé pour ce texte ({{reasonCode}}).',
389
+
390
+ roleImg_textAlternativePresent_title:
391
+ 'Les éléments avec role="img" doivent avoir une alternative textuelle accessible',
392
+
393
+ roleImg_textAlternativePresent_description:
394
+ 'Vérifie que les éléments ayant le rôle "img" fournissent une alternative textuelle accessible via aria-label ou aria-labelledby.',
321
395
 
322
- "dom_nonTextContrast_summary_fail":
323
- "Contraste non-textuel insuffisant : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} par rapport à {{bgColor}}. Composant : {{componentKind}}{{#componentState}} (état : {{componentState}}){{/componentState}}.",
324
- "dom_nonTextContrast_hint_fail":
325
- "Ajustez les couleurs du composant/graphique afin d’atteindre au moins {{requiredRatio}}:1 pour le contour perceptible ou l’information visuelle essentielle.",
396
+ // Résumé d’échec & aide
397
+ roleImg_textAlternativePresent_summary_fail:
398
+ 'L’élément avec le rôle "img" ne possède pas d’alternative textuelle accessible.',
326
399
 
327
- "dom_nonTextContrast_summary_pass":
328
- "Contraste non-textuel conforme : {{contrastRatio}}:1 (requis {{requiredRatio}}:1). Premier plan {{fgColor}} par rapport à {{bgColor}}. Composant : {{componentKind}}{{#componentState}} (état : {{componentState}}){{/componentState}}.",
400
+ roleImg_textAlternativePresent_hint_fail:
401
+ 'Fournissez une alternative textuelle à l’aide de aria-label ou de aria-labelledby pointant vers un texte non vide.',
329
402
 
330
- "dom_nonTextContrast_summary_cantTell":
331
- "Impossible de calculer fiablement le contraste non-textuel car l’arrière-plan effectif ou les pixels peints ne sont pas déterminables (ex. image/dégradé/vidéo/canvas, transparence ou fusion complexes).",
332
- "dom_nonTextContrast_hint_cantTell":
333
- "Vérifiez manuellement le contraste du composant/graphique par rapport aux couleurs adjacentes ; assurez-vous qu’il respecte {{requiredRatio}}:1 pour l’information visuelle non textuelle essentielle.",
334
- "contrastEnhanced_pass_allTextMeetsThreshold": "Tout le texte calculable respecte le contraste renforcé (AAA).",
335
- "contrastMinimum_pass_allTextMeetsThreshold": "Tout le texte calculable respecte le contraste minimum (AA).",
336
- "contrastComputable_cantTell_notComputable":
337
- "Le contraste ne peut pas être calculé pour ce texte ({{reasonCode}}).",
403
+ // --- Taille de la cible (minimum) — WCAG 2.5.8 (AA)
404
+ targetSizeMinimum_title: 'Les cibles activables au pointeur respectent la taille minimale (AA)',
405
+ targetSizeMinimum_description:
406
+ 'Vérifie que les cibles activables au pointeur ont une zone cliquable effective d’au moins 24×24 pixels CSS, ou respectent une exception autorisée (par ex. un espacement suffisant).',
407
+ targetSizeMinimum_summary_fail:
408
+ 'La cible est plus petite que 24×24 px CSS et est trop proche d’une autre cible.',
409
+ targetSizeMinimum_hint_fail:
410
+ 'Augmentez la taille de la cible à au moins 24×24 px CSS, ou ajoutez un espacement suffisant par rapport aux cibles voisines.',
411
+ targetSizeMinimum_summary_cantTell_ambiguousSpacing:
412
+ 'La cible est peut-être trop petite et trop proche d’une autre cible, mais le chevauchement est proche du seuil de détection et n’a pas pu être mesuré avec certitude.',
413
+ targetSizeMinimum_hint_cantTell_ambiguousSpacing:
414
+ 'Vérifiez manuellement l’espacement effectif entre cette cible et sa voisine ; augmentez la taille de la cible ou l’espacement si le chevauchement est réel.',
415
+ targetSizeMinimum_summary_cantTell_plausiblyEssential:
416
+ 'La cible est trop petite et trop proche d’une autre cible, mais pourrait être exemptée en tant qu’élément essentiel d’une zone graphique ou d’une image cliquable.',
417
+ targetSizeMinimum_hint_cantTell_plausiblyEssential:
418
+ 'Vérifiez si la taille de cette cible est réellement essentielle à sa fonction (par ex. partie d’un SVG/canvas/plan d’image) ; sinon, augmentez la taille de la cible ou l’espacement.',
419
+ targetSizeMinimum_notApplicable_noTargets:
420
+ 'Aucune cible activable par pointeur n’était éligible à l’évaluation.',
421
+ targetSizeMinimum_pass_allOk:
422
+ 'Toutes les cibles activables par pointeur respectent la taille minimale ou une exception autorisée.',
423
+
424
+ // --- aria-hidden-focus
425
+ ariaHidden_focus_title: 'Les éléments aria-hidden ne doivent pas être focalisables',
426
+ ariaHidden_focus_description:
427
+ 'Vérifie que les éléments avec aria-hidden="true" ne sont pas focalisables et ne contiennent pas d’éléments focalisables.',
428
+
429
+ ariaHidden_focus_summary_fail_desc:
430
+ 'L’élément aria-hidden {{element}} contient {{focusableCount}} élément(s) focalisable(s).',
431
+ ariaHidden_focus_summary_fail_self:
432
+ 'L’élément aria-hidden {{element}} est focalisable ({{focusableCount}} élément(s) focalisable(s)).',
433
+ ariaHidden_focus_summary_fail_self_and_desc:
434
+ 'L’élément aria-hidden {{element}} est focalisable et contient {{descendantFocusableCount}} descendant(s) focalisable(s) ({{focusableCount}} élément(s) focalisable(s) au total).',
435
+
436
+ ariaHidden_focus_hint_fail:
437
+ 'Supprimez la focalisation des descendants ou retirez aria-hidden ; assurez la cohérence entre l’ordre de focus et l’arbre d’accessibilité.',
438
+ ariaHidden_focus_summary_cantTell_redirect:
439
+ 'L’élément aria-hidden {{element}} reçoit le focus mais le focus est immédiatement déplacé vers un autre élément. Vérifiez le comportement de sentinelle/piège de focus.',
440
+ ariaHidden_focus_hint_cantTell_redirect:
441
+ 'Vérifiez qu’il s’agit d’un transfert intentionnel de sentinelle/piège de focus et que les utilisateurs clavier ne restent jamais sur une cible de focus masquée.',
442
+
443
+ // --- css-hidden-focus
444
+ cssHidden_focus_title: 'Les éléments focalisables ne doivent pas être masqués visuellement',
445
+ cssHidden_focus_description:
446
+ 'Vérifie que les éléments focalisables au clavier ne sont pas masqués visuellement par des techniques CSS pouvant les laisser dans l’ordre de tabulation.',
447
+
448
+ cssHidden_focus_summary_cantTell:
449
+ 'L’élément focalisable {{element}} est masqué visuellement ({{visibilityHints}}).',
450
+ cssHidden_focus_hint_cantTell:
451
+ 'Rendez l’élément visible lorsqu’il peut recevoir le focus clavier, ou retirez-le de l’ordre de tabulation tant qu’il n’est pas visible.',
452
+
453
+ linkNamePresent_title: 'Les liens ont un nom accessible',
454
+ linkNamePresent_description: 'Vérifie que les liens exposent un nom accessible non vide.',
455
+ linkNamePresent_summary_fail: 'Ce lien n’a pas de nom accessible.',
456
+ linkNamePresent_hint_fail:
457
+ 'Fournissez un texte de lien ou un mécanisme de nom accessible (par exemple aria-label) afin que les technologies d’assistance puissent identifier le lien.',
458
+ buttonNamePresent_title: 'Les boutons ont un nom accessible',
459
+ buttonNamePresent_description: 'Vérifie que les boutons exposent un nom accessible non vide.',
460
+ buttonNamePresent_summary_fail: 'Ce bouton n’a pas de nom accessible.',
461
+ buttonNamePresent_hint_fail:
462
+ 'Fournissez un texte visible pour le bouton ou un mécanisme de nom accessible (par exemple aria-label) afin que les technologies d’assistance puissent identifier le bouton.',
463
+ binaryControlNamePresent_title: 'Les contrôles binaires ont un nom accessible',
464
+ binaryControlNamePresent_description:
465
+ 'Vérifie que les cases à cocher, les boutons radio et les interrupteurs exposent un nom accessible non vide.',
466
+ binaryControlNamePresent_summary_fail: 'Ce contrôle n’a pas de nom accessible.',
467
+ binaryControlNamePresent_hint_fail:
468
+ 'Fournissez un libellé, aria-label, aria-labelledby ou un autre mécanisme de nom accessible afin que les technologies d’assistance puissent identifier le contrôle.',
469
+ comboboxNamePresent_title: 'Les listes déroulantes (combobox) ont un nom accessible',
470
+ comboboxNamePresent_description:
471
+ 'Vérifie que les éléments avec role="combobox" exposent un nom accessible non vide.',
472
+ comboboxNamePresent_summary_fail: 'Cette combobox n’a pas de nom accessible.',
473
+ comboboxNamePresent_hint_fail:
474
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de cet élément.',
475
+ dialogNamePresent_title: 'Les dialogues ont un nom accessible',
476
+ dialogNamePresent_description:
477
+ 'Vérifie que les éléments avec role="dialog" ou role="alertdialog" exposent un nom accessible non vide.',
478
+ dialogNamePresent_summary_fail: 'Ce dialogue n’a pas de nom accessible.',
479
+ dialogNamePresent_hint_fail:
480
+ 'Fournissez aria-labelledby (préféré) ou aria-label afin que les technologies d’assistance puissent annoncer le dialogue.',
481
+ menuitemNamePresent_title: 'Les éléments de menu ont un nom accessible',
482
+ menuitemNamePresent_description:
483
+ 'Vérifie que les éléments de menu (role="menuitem*", y compris les variantes case à cocher/radio) exposent un nom accessible non vide.',
484
+ menuitemNamePresent_summary_fail: 'Cet élément de menu n’a pas de nom accessible.',
485
+ menuitemNamePresent_hint_fail:
486
+ 'Fournissez un texte visible qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
487
+ tabNamePresent_title: 'Les onglets ont un nom accessible',
488
+ tabNamePresent_description:
489
+ 'Vérifie que les éléments avec role="tab" exposent un nom accessible non vide.',
490
+ tabNamePresent_summary_fail: 'Cet onglet n’a pas de nom accessible.',
491
+ tabNamePresent_hint_fail:
492
+ 'Fournissez un texte d’onglet qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
493
+ sliderNamePresent_title: 'Les curseurs ont un nom accessible',
494
+ sliderNamePresent_description:
495
+ 'Vérifie que les curseurs (input[type="range"] et role="slider") exposent un nom accessible non vide.',
496
+ sliderNamePresent_summary_fail: 'Ce curseur n’a pas de nom accessible.',
497
+ sliderNamePresent_hint_fail:
498
+ 'Fournissez un libellé, aria-label ou aria-labelledby afin que les technologies d’assistance puissent identifier le curseur.',
499
+ textboxNamePresent_title: 'Les champs de texte ont un nom accessible',
500
+ textboxNamePresent_description:
501
+ 'Vérifie que les éléments avec role="textbox" exposent un nom accessible non vide.',
502
+ textboxNamePresent_summary_fail: 'Ce champ de texte n’a pas de nom accessible.',
503
+ textboxNamePresent_hint_fail:
504
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de ce champ de texte.',
505
+ searchboxNamePresent_title: 'Les champs de recherche ont un nom accessible',
506
+ searchboxNamePresent_description:
507
+ 'Vérifie que les éléments avec role="searchbox" exposent un nom accessible non vide.',
508
+ searchboxNamePresent_summary_fail: 'Ce champ de recherche n’a pas de nom accessible.',
509
+ searchboxNamePresent_hint_fail:
510
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de ce champ de recherche.',
511
+ spinbuttonNamePresent_title: 'Les sélecteurs numériques (spinbutton) ont un nom accessible',
512
+ spinbuttonNamePresent_description:
513
+ 'Vérifie que les éléments avec role="spinbutton" exposent un nom accessible non vide.',
514
+ spinbuttonNamePresent_summary_fail: 'Ce spinbutton n’a pas de nom accessible.',
515
+ spinbuttonNamePresent_hint_fail:
516
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de ce spinbutton.',
517
+ listboxNamePresent_title: 'Les listes (listbox) ont un nom accessible',
518
+ listboxNamePresent_description:
519
+ 'Vérifie que les éléments avec role="listbox" exposent un nom accessible non vide.',
520
+ listboxNamePresent_summary_fail: 'Cette listbox n’a pas de nom accessible.',
521
+ listboxNamePresent_hint_fail:
522
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de cette listbox.',
523
+ optionNamePresent_title: 'Les options ont un nom accessible',
524
+ optionNamePresent_description:
525
+ 'Vérifie que les éléments avec role="option" exposent un nom accessible non vide.',
526
+ optionNamePresent_summary_fail: 'Cette option n’a pas de nom accessible.',
527
+ optionNamePresent_hint_fail:
528
+ 'Fournissez un texte d’option qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
529
+ treeitemNamePresent_title: 'Les éléments d’arborescence ont un nom accessible',
530
+ treeitemNamePresent_description:
531
+ 'Vérifie que les éléments avec role="treeitem" exposent un nom accessible non vide.',
532
+ treeitemNamePresent_summary_fail: 'Cet élément d’arborescence n’a pas de nom accessible.',
533
+ treeitemNamePresent_hint_fail:
534
+ 'Fournissez un texte d’élément d’arborescence qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
535
+ ariaRoleNamePresent_title: 'Les rôles ARIA de type widget/conteneur ont un nom accessible',
536
+ ariaRoleNamePresent_description:
537
+ 'Vérifie que certains rôles ARIA de type widget/conteneur exposent un nom accessible non vide.',
538
+ ariaRoleNamePresent_summary_fail: 'Cet élément n’a pas de nom accessible.',
539
+ ariaRoleNamePresent_hint_fail:
540
+ 'Fournissez aria-label ou aria-labelledby (préféré), ou un attribut title non vide.',
338
541
 
339
- "roleImg_textAlternativePresent_title":
340
- 'Les éléments avec role="img" doivent avoir une alternative textuelle accessible',
542
+ /* =========================
543
+ * Résumé des règles composites
544
+ * ========================= */
545
+ composite_rollup_summary:
546
+ 'Résultat de la règle composite : {{reasonCode}} ({{testCount}} contrôles)',
341
547
 
342
- "roleImg_textAlternativePresent_description":
343
- 'Vérifie que les éléments ayant le rôle "img" fournissent une alternative textuelle accessible via aria-label ou aria-labelledby.',
548
+ /* =========================
549
+ * WCAG 1.1.1 – Contenu non textuel
550
+ * ========================= */
551
+ 'catalog.rules.wcag_111_non_text_content.title': 'Contenu non textuel : alternatives textuelles',
552
+ 'catalog.rules.wcag_111_non_text_content.description':
553
+ 'Regroupe les contrôles garantissant que le contenu non textuel dispose d’une alternative textuelle appropriée.',
344
554
 
345
- // Résumé d’échec & aide
346
- "roleImg_textAlternativePresent_summary_fail":
347
- 'L’élément avec le rôle "img" ne possède pas d’alternative textuelle accessible.',
555
+ /* =========================
556
+ * WCAG 1.2.1 – Audio seul / Vidéo seule
557
+ * ========================= */
558
+ 'catalog.rules.wcag_121_prerecorded_transcript.title':
559
+ 'Audio seul et vidéo seule (préenregistrés) : transcription',
560
+ 'catalog.rules.wcag_121_prerecorded_transcript.description':
561
+ 'Regroupe les contrôles vérifiant la disponibilité d’une transcription pour les médias audio seuls ou vidéo seuls préenregistrés.',
348
562
 
349
- "roleImg_textAlternativePresent_hint_fail":
350
- 'Fournissez une alternative textuelle à l’aide de aria-label ou de aria-labelledby pointant vers un texte non vide.',
563
+ /* =========================
564
+ * WCAG 1.4.3 – Contraste (minimum)
565
+ * ========================= */
566
+ 'catalog.rules.wcag_143_contrast_minimum.title': 'Contraste : minimum',
567
+ 'catalog.rules.wcag_143_contrast_minimum.description':
568
+ 'Regroupe les contrôles relatifs au contraste minimal du texte.',
351
569
 
352
- // --- Taille de la cible (minimum) — WCAG 2.5.8 (AA)
353
- "targetSizeMinimum_title": "Les cibles activables au pointeur respectent la taille minimale (AA)",
354
- "targetSizeMinimum_description": "Vérifie que les cibles activables au pointeur ont une zone cliquable effective d’au moins 24×24 pixels CSS, ou respectent une exception autorisée (par ex. un espacement suffisant).",
355
- "targetSizeMinimum_summary_fail": "La cible est plus petite que 24×24 px CSS et est trop proche d’une autre cible.",
356
- "targetSizeMinimum_hint_fail": "Augmentez la taille de la cible à au moins 24×24 px CSS, ou ajoutez un espacement suffisant par rapport aux cibles voisines.",
357
- "targetSizeMinimum_notApplicable_noTargets": "Aucune cible activable par pointeur n’était éligible à l’évaluation.",
358
- "targetSizeMinimum_pass_allOk": "Toutes les cibles activables par pointeur respectent la taille minimale ou une exception autorisée.",
359
-
360
- // --- aria-hidden-focus
361
- "ariaHidden_focus_title": "Les éléments aria-hidden ne doivent pas être focalisables",
362
- "ariaHidden_focus_description":
363
- "Vérifie que les éléments avec aria-hidden=\"true\" ne sont pas focalisables et ne contiennent pas d’éléments focalisables.",
364
-
365
- "ariaHidden_focus_summary_fail_desc":
366
- "L’élément aria-hidden {{element}} contient {{focusableCount}} élément(s) focalisable(s).",
367
- "ariaHidden_focus_summary_fail_self":
368
- "L’élément aria-hidden {{element}} est focalisable ({{focusableCount}} élément(s) focalisable(s)).",
369
- "ariaHidden_focus_summary_fail_self_and_desc":
370
- "L’élément aria-hidden {{element}} est focalisable et contient {{descendantFocusableCount}} descendant(s) focalisable(s) ({{focusableCount}} élément(s) focalisable(s) au total).",
371
-
372
- "ariaHidden_focus_hint_fail":
373
- "Supprimez la focalisation des descendants ou retirez aria-hidden ; assurez la cohérence entre l’ordre de focus et l’arbre d’accessibilité.",
374
-
375
- // --- css-hidden-focus
376
- "cssHidden_focus_title": "Les éléments focalisables ne doivent pas être masqués visuellement",
377
- "cssHidden_focus_description":
378
- "Vérifie que les éléments focalisables au clavier ne sont pas masqués visuellement par des techniques CSS pouvant les laisser dans l’ordre de tabulation.",
379
-
380
- "cssHidden_focus_summary_cantTell":
381
- "L’élément focalisable {{element}} est masqué visuellement ({{visibilityHints}}).",
382
- "cssHidden_focus_hint_cantTell":
383
- "Rendez l’élément visible lorsqu’il peut recevoir le focus clavier, ou retirez-le de l’ordre de tabulation tant qu’il n’est pas visible.",
384
-
385
- "linkNamePresent_title": "Les liens ont un nom accessible",
386
- "linkNamePresent_description": "Vérifie que les liens exposent un nom accessible non vide.",
387
- "linkNamePresent_summary_fail": "Ce lien n’a pas de nom accessible.",
388
- "linkNamePresent_hint_fail": "Fournissez un texte de lien ou un mécanisme de nom accessible (par exemple aria-label) afin que les technologies d’assistance puissent identifier le lien.",
389
- "buttonNamePresent_title": "Les boutons ont un nom accessible",
390
- "buttonNamePresent_description": "Vérifie que les boutons exposent un nom accessible non vide.",
391
- "buttonNamePresent_summary_fail": "Ce bouton n’a pas de nom accessible.",
392
- "buttonNamePresent_hint_fail": "Fournissez un texte visible pour le bouton ou un mécanisme de nom accessible (par exemple aria-label) afin que les technologies d’assistance puissent identifier le bouton.",
393
- "binaryControlNamePresent_title": "Les contrôles binaires ont un nom accessible",
394
- "binaryControlNamePresent_description": "Vérifie que les cases à cocher, les boutons radio et les interrupteurs exposent un nom accessible non vide.",
395
- "binaryControlNamePresent_summary_fail": "Ce contrôle n’a pas de nom accessible.",
396
- "binaryControlNamePresent_hint_fail": "Fournissez un libellé, aria-label, aria-labelledby ou un autre mécanisme de nom accessible afin que les technologies d’assistance puissent identifier le contrôle.",
397
- "comboboxNamePresent_title": "Les listes déroulantes (combobox) ont un nom accessible",
398
- "comboboxNamePresent_description": "Vérifie que les éléments avec role=\"combobox\" exposent un nom accessible non vide.",
399
- "comboboxNamePresent_summary_fail": "Cette combobox n’a pas de nom accessible.",
400
- "comboboxNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou assurez-vous que l’élément a un texte visible qui n’est pas masqué aux technologies d’assistance.",
401
- "dialogNamePresent_title": "Les dialogues ont un nom accessible",
402
- "dialogNamePresent_description": "Vérifie que les éléments avec role=\"dialog\" ou role=\"alertdialog\" exposent un nom accessible non vide.",
403
- "dialogNamePresent_summary_fail": "Ce dialogue n’a pas de nom accessible.",
404
- "dialogNamePresent_hint_fail": "Fournissez aria-labelledby (préféré) ou aria-label afin que les technologies d’assistance puissent annoncer le dialogue.",
405
- "menuitemNamePresent_title": "Les éléments de menu ont un nom accessible",
406
- "menuitemNamePresent_description": "Vérifie que les éléments de menu (role=\"menuitem*\", y compris les variantes case à cocher/radio) exposent un nom accessible non vide.",
407
- "menuitemNamePresent_summary_fail": "Cet élément de menu n’a pas de nom accessible.",
408
- "menuitemNamePresent_hint_fail": "Fournissez un texte visible qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
409
- "tabNamePresent_title": "Les onglets ont un nom accessible",
410
- "tabNamePresent_description": "Vérifie que les éléments avec role=\"tab\" exposent un nom accessible non vide.",
411
- "tabNamePresent_summary_fail": "Cet onglet n’a pas de nom accessible.",
412
- "tabNamePresent_hint_fail": "Fournissez un texte d’onglet qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
413
- "sliderNamePresent_title": "Les curseurs ont un nom accessible",
414
- "sliderNamePresent_description": "Vérifie que les curseurs (input[type=\"range\"] et role=\"slider\") exposent un nom accessible non vide.",
415
- "sliderNamePresent_summary_fail": "Ce curseur n’a pas de nom accessible.",
416
- "sliderNamePresent_hint_fail": "Fournissez un libellé, aria-label ou aria-labelledby afin que les technologies d’assistance puissent identifier le curseur.",
417
- "textboxNamePresent_title": "Les champs de texte ont un nom accessible",
418
- "textboxNamePresent_description": "Vérifie que les éléments avec role=\"textbox\" exposent un nom accessible non vide.",
419
- "textboxNamePresent_summary_fail": "Ce champ de texte n’a pas de nom accessible.",
420
- "textboxNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou assurez-vous que le champ de texte a un texte visible qui n’est pas masqué aux technologies d’assistance.",
421
- "searchboxNamePresent_title": "Les champs de recherche ont un nom accessible",
422
- "searchboxNamePresent_description": "Vérifie que les éléments avec role=\"searchbox\" exposent un nom accessible non vide.",
423
- "searchboxNamePresent_summary_fail": "Ce champ de recherche n’a pas de nom accessible.",
424
- "searchboxNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou assurez-vous que le champ de recherche a un texte visible qui n’est pas masqué aux technologies d’assistance.",
425
- "spinbuttonNamePresent_title": "Les sélecteurs numériques (spinbutton) ont un nom accessible",
426
- "spinbuttonNamePresent_description": "Vérifie que les éléments avec role=\"spinbutton\" exposent un nom accessible non vide.",
427
- "spinbuttonNamePresent_summary_fail": "Ce spinbutton n’a pas de nom accessible.",
428
- "spinbuttonNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou assurez-vous que le spinbutton a un texte visible qui n’est pas masqué aux technologies d’assistance.",
429
- "listboxNamePresent_title": "Les listes (listbox) ont un nom accessible",
430
- "listboxNamePresent_description": "Vérifie que les éléments avec role=\"listbox\" exposent un nom accessible non vide.",
431
- "listboxNamePresent_summary_fail": "Cette listbox n’a pas de nom accessible.",
432
- "listboxNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou assurez-vous que la listbox a un texte visible qui n’est pas masqué aux technologies d’assistance.",
433
- "optionNamePresent_title": "Les options ont un nom accessible",
434
- "optionNamePresent_description": "Vérifie que les éléments avec role=\"option\" exposent un nom accessible non vide.",
435
- "optionNamePresent_summary_fail": "Cette option n’a pas de nom accessible.",
436
- "optionNamePresent_hint_fail": "Fournissez un texte d’option qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
437
- "treeitemNamePresent_title": "Les éléments d’arborescence ont un nom accessible",
438
- "treeitemNamePresent_description": "Vérifie que les éléments avec role=\"treeitem\" exposent un nom accessible non vide.",
439
- "treeitemNamePresent_summary_fail": "Cet élément d’arborescence n’a pas de nom accessible.",
440
- "treeitemNamePresent_hint_fail": "Fournissez un texte d’élément d’arborescence qui n’est pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
441
- "ariaRoleNamePresent_title": "Les rôles ARIA de type widget/conteneur ont un nom accessible",
442
- "ariaRoleNamePresent_description": "Vérifie que certains rôles ARIA de type widget/conteneur exposent un nom accessible non vide.",
443
- "ariaRoleNamePresent_summary_fail": "Cet élément n’a pas de nom accessible.",
444
- "ariaRoleNamePresent_hint_fail": "Fournissez aria-label ou aria-labelledby (préféré), ou un attribut title non vide.",
570
+ /* =========================
571
+ * WCAG 1.4.6 – Contraste (renforcé)
572
+ * ========================= */
573
+ 'catalog.rules.wcag_146_contrast_enhanced.title': 'Contraste : renforcé',
574
+ 'catalog.rules.wcag_146_contrast_enhanced.description':
575
+ 'Regroupe les contrôles relatifs au contraste renforcé du texte.',
445
576
 
446
577
  /* =========================
447
- * Résumé des règles composites
578
+ * WCAG 2.4.2 – Page titrée
579
+ * ========================= */
580
+ 'catalog.rules.wcag_242_page_titled.title': 'Page titrée',
581
+ 'catalog.rules.wcag_242_page_titled.description':
582
+ 'Regroupe les contrôles garantissant que les documents possèdent un titre de page pertinent.',
583
+
584
+ /* =========================
585
+ * WCAG 2.4.7 – Focus visible
586
+ * ========================= */
587
+ 'catalog.rules.wcag_247_focus_visible.title': 'Focus visible',
588
+ 'catalog.rules.wcag_247_focus_visible.description':
589
+ 'Regroupe les contrôles garantissant que le focus clavier n’est pas masqué et reste perceptible.',
590
+
591
+ /* =========================
592
+ * WCAG 2.5.8 – Taille de la cible (minimum)
593
+ * ========================= */
594
+ 'catalog.rules.wcag_258_target_size_minimum.title': 'Taille de la cible : minimum',
595
+ 'catalog.rules.wcag_258_target_size_minimum.description':
596
+ 'Regroupe les contrôles garantissant que les cibles de pointage respectent les dimensions minimales requises.',
597
+
598
+ /* =========================
599
+ * WCAG 3.1.1 – Langue de la page
600
+ * ========================= */
601
+ 'catalog.rules.wcag_311_language_of_page.title': 'Langue de la page',
602
+ 'catalog.rules.wcag_311_language_of_page.description':
603
+ 'Regroupe les contrôles garantissant que la langue de la page est spécifiée.',
604
+
605
+ /* =========================
606
+ * WCAG 4.1.2 – Nom, rôle, valeur
448
607
  * ========================= */
449
- "composite_rollup_summary":
450
- "Résultat de la règle composite : {{reasonCode}} ({{testCount}} contrôles)",
451
-
452
- /* =========================
453
- * WCAG 1.1.1 – Contenu non textuel
454
- * ========================= */
455
- "catalog.rules.wcag_111_non_text_content.title":
456
- "Contenu non textuel : alternatives textuelles",
457
- "catalog.rules.wcag_111_non_text_content.description":
458
- "Regroupe les contrôles garantissant que le contenu non textuel dispose d’une alternative textuelle appropriée.",
459
-
460
- /* =========================
461
- * WCAG 1.2.1 – Audio seul / Vidéo seule
462
- * ========================= */
463
- "catalog.rules.wcag_121_prerecorded_transcript.title":
464
- "Audio seul et vidéo seule (préenregistrés) : transcription",
465
- "catalog.rules.wcag_121_prerecorded_transcript.description":
466
- "Regroupe les contrôles vérifiant la disponibilité d’une transcription pour les médias audio seuls ou vidéo seuls préenregistrés.",
467
-
468
- /* =========================
469
- * WCAG 1.4.3 – Contraste (minimum)
470
- * ========================= */
471
- "catalog.rules.wcag_143_contrast_minimum.title":
472
- "Contraste : minimum",
473
- "catalog.rules.wcag_143_contrast_minimum.description":
474
- "Regroupe les contrôles relatifs au contraste minimal du texte.",
475
-
476
- /* =========================
477
- * WCAG 1.4.6 – Contraste (renforcé)
478
- * ========================= */
479
- "catalog.rules.wcag_146_contrast_enhanced.title":
480
- "Contraste : renforcé",
481
- "catalog.rules.wcag_146_contrast_enhanced.description":
482
- "Regroupe les contrôles relatifs au contraste renforcé du texte.",
483
-
484
- /* =========================
485
- * WCAG 2.4.2 – Page titrée
486
- * ========================= */
487
- "catalog.rules.wcag_242_page_titled.title":
488
- "Page titrée",
489
- "catalog.rules.wcag_242_page_titled.description":
490
- "Regroupe les contrôles garantissant que les documents possèdent un titre de page pertinent.",
491
-
492
- /* =========================
493
- * WCAG 2.4.7 – Focus visible
494
- * ========================= */
495
- "catalog.rules.wcag_247_focus_visible.title":
496
- "Focus visible",
497
- "catalog.rules.wcag_247_focus_visible.description":
498
- "Regroupe les contrôles garantissant que le focus clavier n’est pas masqué et reste perceptible.",
499
-
500
- /* =========================
501
- * WCAG 2.5.8 – Taille de la cible (minimum)
502
- * ========================= */
503
- "catalog.rules.wcag_258_target_size_minimum.title":
504
- "Taille de la cible : minimum",
505
- "catalog.rules.wcag_258_target_size_minimum.description":
506
- "Regroupe les contrôles garantissant que les cibles de pointage respectent les dimensions minimales requises.",
507
-
508
- /* =========================
509
- * WCAG 3.1.1 – Langue de la page
510
- * ========================= */
511
- "catalog.rules.wcag_311_language_of_page.title":
512
- "Langue de la page",
513
- "catalog.rules.wcag_311_language_of_page.description":
514
- "Regroupe les contrôles garantissant que la langue de la page est spécifiée.",
515
-
516
- /* =========================
517
- * WCAG 4.1.2 – Nom, rôle, valeur
518
- * ========================= */
519
- "catalog.rules.wcag_412_name.title":
520
- "Nom, rôle, valeur : nom accessible",
521
- "catalog.rules.wcag_412_name.description":
522
- "Regroupe les contrôles garantissant que les éléments interactifs courants exposent un nom accessible non vide.",
523
- "labelInName_title": "Intitulé dans le nom : le nom accessible contient le texte visible",
524
- "labelInName_description": "Vérifie que lorsqu’un composant possède un libellé textuel visible, le nom accessible contient ce libellé visible (WCAG 2.5.3).",
525
- "labelInName_summary_fail": "{{element}} : le libellé visible « {{visibleLabel}} » (source : {{labelSource}}) n’est pas inclus dans le nom accessible (source : {{nameMechanism}}).",
526
- "labelInName_hint_fail": "Modifiez aria-label ou aria-labelledby (ou le texte du libellé visible) afin que le nom accessible inclue le libellé visible.",
527
- "ariaRolesValid_title": "L’attribut role doit être un rôle ARIA valide et non abstrait",
528
- "ariaRolesValid_description": "Vérifie qu’un attribut role=\"\" explicite correspond à un rôle WAI-ARIA réel et non abstrait.",
529
- "ariaRolesValid_summary_invalid": "role=\"{{role}}\" n’est pas un rôle ARIA reconnu.",
530
- "ariaRolesValid_hint_invalid": "Utilisez un rôle ARIA valide, ou retirez l’attribut role si aucun ne s’applique.",
531
- "ariaRolesValid_summary_abstract": "role=\"{{role}}\" est un rôle ARIA abstrait, qui ne doit pas être utilisé directement.",
532
- "ariaRolesValid_hint_abstract": "Remplacez ce rôle abstrait par un rôle concret adapté au composant/à la structure.",
533
- "ariaDeprecatedRole_title": "L’attribut role ne doit pas utiliser un rôle ARIA obsolète ou interdit aux auteurs",
534
- "ariaDeprecatedRole_description": "Vérifie qu’un attribut role=\"\" explicite n’utilise pas un rôle rendu obsolète par la spécification WAI-ARIA, ni un rôle réservé à un usage interne à l’agent utilisateur (ex. role=\"generic\").",
535
- "ariaDeprecatedRole_summary_fail": "Cet élément utilise role=\"{{role}}\", que les auteurs ne doivent pas déclarer explicitement.",
536
- "ariaDeprecatedRole_hint_fail": "{{guidance}}",
537
- "ariaValidAttr_title": "Les attributs aria-* doivent être des attributs ARIA réels et définis",
538
- "ariaValidAttr_description": "Vérifie que chaque nom d’attribut aria-* présent dans le DOM est un attribut réel défini par la spécification WAI-ARIA.",
539
- "ariaValidAttr_summary_fail": "{{attr}} n’est pas un attribut ARIA reconnu.",
540
- "ariaValidAttr_hint_fail": "Corrigez le nom de l’attribut (vérifiez les fautes de frappe), ou retirez-le s’il n’est pas nécessaire.",
541
- "ariaValidAttrValue_title": "Les valeurs des attributs aria-* doivent correspondre à leur type déclaré",
542
- "ariaValidAttrValue_description": "Vérifie que chaque attribut aria-* reconnu a une valeur conforme à son type déclaré par WAI-ARIA (booléen, tri-état, jeton, entier, nombre ou référence d’ID).",
543
- "ariaValidAttrValue_summary_fail": "{{attr}}=\"{{value}}\" n’est pas une valeur valide pour cet attribut.",
544
- "ariaValidAttrValue_hint_fail": "Utilisez une valeur correspondant au type attendu de l’attribut (consultez la spécification WAI-ARIA pour cet attribut).",
545
- "ariaAllowedAttr_title": "Les attributs aria-* doivent être autorisés pour le rôle de l’élément",
546
- "ariaAllowedAttr_description": "Vérifie que chaque attribut aria-* reconnu présent sur un élément ayant un rôle explicite est soit globalement pris en charge, soit pris en charge par ce rôle.",
547
- "ariaAllowedAttr_summary_fail": "{{attr}} n’est pas autorisé sur role=\"{{role}}\".",
548
- "ariaAllowedAttr_hint_fail": "Retirez cet attribut, ou utilisez un rôle qui le prend en charge.",
549
- "ariaProhibitedAttr_title": "Les attributs de nommage ARIA ne doivent pas être utilisés sur des rôles qui les interdisent",
550
- "ariaProhibitedAttr_description": "Vérifie que aria-label/aria-labelledby ne sont pas présents sur des rôles WAI-ARIA dont la spécification interdit explicitement le nommage ARIA (ex. generic, emphasis, strong, paragraph).",
551
- "ariaProhibitedAttr_summary_fail": "{{attr}} est interdit sur role=\"{{role}}\".",
552
- "ariaProhibitedAttr_hint_fail": "Retirez cet attribut ; ce rôle ne doit pas porter de nom accessible.",
553
- "ariaRequiredAttr_title": "Les rôles avec un état/une propriété ARIA requis doivent le porter",
554
- "ariaRequiredAttr_description": "Vérifie que les éléments ayant un rôle explicite portent chaque état/propriété aria-* requis, non ambigu et indépendant du contexte, pour ce rôle (ex. role=\"checkbox\" doit avoir aria-checked).",
555
- "ariaRequiredAttr_summary_fail": "{{attr}} est requis pour role=\"{{role}}\", mais est absent.",
556
- "ariaRequiredAttr_hint_fail": "Ajoutez cet attribut avec une valeur valide pour ce rôle.",
557
- "ariaAllowedRole_title": "Le rôle explicite doit être autorisé pour son élément hôte",
558
- "ariaAllowedRole_description": "Vérifie qu’un attribut role=\"\" explicite fait partie des rôles que la spécification ARIA-in-HTML autorise pour l’élément hôte (ex. role=\"tab\" n’est pas autorisé sur <nav>).",
559
- "ariaAllowedRole_summary_fail": "role=\"{{role}}\" n’est pas autorisé sur <{{element}}>.",
560
- "ariaAllowedRole_hint_fail": "Utilisez un rôle autorisé pour cet élément, ou changez l’élément hôte.",
561
- "ariaRequiredChildren_title": "Les rôles conteneurs doivent posséder au moins un rôle enfant requis",
562
- "ariaRequiredChildren_description": "Vérifie que les rôles conteneurs disposant d’une entrée documentée « éléments possédés requis » (list, listbox, menu, radiogroup, table, grid, tablist, tree, row, ...) contiennent au moins un descendant, ou un élément référencé par aria-owns, ayant un rôle possédé acceptable.",
563
- "ariaRequiredChildren_summary_fail": "role=\"{{role}}\" ne possède aucun enfant ayant l’un des rôles requis : {{requiredRoles}}.",
564
- "ariaRequiredChildren_hint_fail": "Ajoutez un descendant (ou un élément référencé par aria-owns) ayant l’un des rôles possédés requis.",
565
- "ariaProhibitedChildren_title": "Les rôles conteneurs ne doivent pas posséder d’enfant ayant un rôle interdit",
566
- "ariaProhibitedChildren_description": "Vérifie que chaque enfant possédé (dans l’arbre d’accessibilité) d’un rôle conteneur (list, listbox, menu, menubar, radiogroup, rowgroup, table, grid, treegrid, tablist, tree, row) a l’un des rôles possédés autorisés par ce rôle.",
567
- "ariaProhibitedChildren_summary_fail": "Cet élément a le rôle role=\"{{childRole}}\", qui n’est pas un rôle enfant possédé autorisé par le conteneur englobant role=\"{{containerRole}}\".",
568
- "ariaProhibitedChildren_hint_fail": "Retirez ou modifiez ce rôle afin qu’il corresponde à l’un des rôles possédés autorisés du conteneur ({{allowedRoles}}), ou déplacez cet élément hors du conteneur {{containerRole}}.",
569
- "ariaProhibitedChildren_summary_fail_roleless": "Cet élément n’a pas de rôle explicite mais porte {{attr}}, ce qui en fait un véritable nœud de l’arbre d’accessibilité qui n’est pas un enfant possédé autorisé du conteneur englobant role=\"{{containerRole}}\".",
570
- "ariaProhibitedChildren_hint_fail_roleless": "Retirez {{attr}} (ou la relation de possession avec le conteneur role=\"{{containerRole}}\"), ou attribuez à cet élément role=\"presentation\"/\"none\" s’il n’est pas censé constituer son propre nœud dans l’arbre d’accessibilité.",
571
- "ariaRequiredParent_title": "Les rôles exigeant un rôle de contexte spécifique doivent se trouver dans ce contexte",
572
- "ariaRequiredParent_description": "Vérifie que les rôles disposant d’une entrée documentée « rôle de contexte requis » (listitem, option, tab, treeitem, row, cell, ...) ont un ancêtre, ou un propriétaire aria-owns, ayant un rôle de contexte acceptable.",
573
- "ariaRequiredParent_summary_fail": "role=\"{{role}}\" exige un rôle de contexte parmi : {{requiredRoles}}, qui n’a pas été trouvé.",
574
- "ariaRequiredParent_hint_fail": "Placez cet élément à l’intérieur d’un élément ayant un rôle de contexte acceptable (ou référencez-le depuis celui-ci via aria-owns).",
575
- "deprecatedElements_title": "Les éléments obsolètes non interruptibles (<blink>, <marquee>) ne doivent pas être utilisés",
576
- "deprecatedElements_description": "Vérifie que les éléments HTML obsolètes et non standards dont le contenu clignotant/défilant ne peut pas être mis en pause, arrêté ou masqué par l’utilisateur (<blink>, <marquee>) ne sont pas présents.",
577
- "deprecatedElements_summary_fail": "Le contenu de <{{element}}> ne peut pas être mis en pause, arrêté ou masqué par l’utilisateur.",
578
- "deprecatedElements_hint_fail": "Retirez cet élément ; utilisez à la place un contenu statique, ou une animation dotée d’un contrôle de pause/arrêt accessible à l’utilisateur.",
579
- "iframeNamePresent_title": "Les cadres ont un nom accessible",
580
- "iframeNamePresent_description": "Vérifie que les éléments <iframe>/<frame> exposent un nom accessible non vide via aria-label, aria-labelledby, ou l’attribut title.",
581
- "iframeNamePresent_summary_fail": "Ce <{{element}}> n’a pas de nom accessible.",
582
- "iframeNamePresent_hint_fail": "Ajoutez un attribut title (ou aria-label/aria-labelledby) décrivant le contenu ou l’objet du cadre.",
583
- "iframeTitleUnique_title": "Les titres de cadres doivent être uniques",
584
- "iframeTitleUnique_description": "Vérifie qu’aucun <iframe>/<frame> dans le périmètre analysé ne partage la même valeur d’attribut title qu’un autre.",
585
- "iframeTitleUnique_summary_fail": "Le titre « {{title}} » de ce <{{element}}> n’est pas unique parmi les cadres de cette page.",
586
- "iframeTitleUnique_hint_fail": "Donnez à chaque cadre un titre distinct décrivant son contenu ou son objet spécifique.",
587
- "iframeFocusableContent_title": "Les cadres avec tabindex=\"-1\" ne doivent pas contenir de contenu focalisable",
588
- "iframeFocusableContent_description": "Vérifie que les éléments <iframe>/<frame> de même origine avec tabindex=\"-1\" ne contiennent pas de contenu focalisable, car les navigateurs ne propagent pas cette restriction au document intégré du cadre.",
589
- "iframeFocusableContent_summary_fail": "Ce <{{element}}> a tabindex=\"-1\" mais son contenu contient des éléments focalisables, qui restent accessibles au clavier.",
590
- "iframeFocusableContent_hint_fail": "Retirez le contenu focalisable du cadre, ou retirez tabindex=\"-1\" si le cadre est censé être accessible.",
591
- "tableHeadersAttrValid_title": "L’attribut headers d’une cellule de tableau doit référencer des cellules d’en-tête valides",
592
- "tableHeadersAttrValid_description": "Vérifie que chaque id de l’attribut headers d’un <td>/<th> correspond à un élément <th> du même tableau (ni absent, ni un élément autre que th, ni lui-même).",
593
- "tableHeadersAttrValid_summary_fail": "L’attribut headers de ce <{{element}}> référence des cellules d’en-tête invalides : {{invalidIds}}.",
594
- "tableHeadersAttrValid_hint_fail": "Mettez à jour l’attribut headers afin que chaque id désigne un élément <th> du même tableau.",
595
- "tableThHasDataCells_title": "Les éléments <th> doivent décrire au moins une cellule de données",
596
- "tableThHasDataCells_description": "Vérifie qu’un tableau contenant des éléments <th> contient aussi au moins une cellule de données <td> que ces en-têtes décrivent.",
597
- "tableThHasDataCells_summary_fail": "Ce tableau a des cellules d’en-tête mais aucune cellule de données à décrire.",
598
- "tableThHasDataCells_hint_fail": "Ajoutez des cellules de données (<td>) au tableau, ou retirez les cellules d’en-tête si le tableau n’a pas de données.",
599
- "ariaHiddenBody_title": "Le <body> du document ne doit pas être aria-hidden",
600
- "ariaHiddenBody_description": "Vérifie que <body> n’a pas aria-hidden=\"true\", ce qui retirerait toute la page de l’arbre d’accessibilité.",
601
- "ariaHiddenBody_summary_fail": "Le corps du document a aria-hidden=\"true\", ce qui masque toute la page aux technologies d’assistance.",
602
- "ariaHiddenBody_hint_fail": "Retirez aria-hidden de <body>. Masquez des éléments spécifiques à la place, si c’était l’intention.",
603
- "listChildrenValid_title": "Les listes ne doivent contenir directement que des éléments de liste",
604
- "listChildrenValid_description": "Vérifie que les éléments <ul>/<ol> n’ont comme enfants directs que <li>, <script> ou <template>.",
605
- "listChildrenValid_summary_fail": "Ce <{{element}}> contient un enfant direct qui n’est pas un élément de liste : {{invalidChildren}}.",
606
- "listChildrenValid_hint_fail": "N’utilisez que <li> (ou <script>/<template>) comme enfants directs de <ul>/<ol> ; déplacez tout autre balisage à l’intérieur d’un <li>.",
607
- "listitemParentValid_title": "Les éléments de liste doivent se trouver à l’intérieur d’un conteneur de liste",
608
- "listitemParentValid_description": "Vérifie que les éléments <li> sont contenus par <ul>, <ol>, ou un élément ayant role=\"list\".",
609
- "listitemParentValid_summary_fail": "Le parent de cet élément de liste (<{{parentElement}}>) n’est pas un conteneur de liste.",
610
- "listitemParentValid_hint_fail": "Placez ce <li> à l’intérieur d’un <ul>/<ol>, ou donnez à son parent role=\"list\".",
611
- "definitionListChildrenValid_title": "Les listes de définitions doivent être structurées correctement",
612
- "definitionListChildrenValid_description": "Vérifie que les éléments <dl> ne contiennent directement que des groupes <dt>/<dd> (éventuellement enveloppés dans un seul <div>), <script>, <template>, ou <style>.",
613
- "definitionListChildrenValid_summary_fail_invalidChild": "Cette liste de définitions contient un enfant direct ou enveloppé qui ne fait pas partie d’un groupe dt/dd : {{invalidChildren}}.",
614
- "definitionListChildrenValid_hint_fail_invalidChild": "N’utilisez que <dt>/<dd> (éventuellement enveloppés dans un seul <div>), <script>, <template>, ou <style> à l’intérieur de <dl>.",
615
- "definitionListChildrenValid_summary_fail_noDtDd": "Cette liste de définitions n’a aucun groupe terme/définition <dt>/<dd>.",
616
- "definitionListChildrenValid_hint_fail_noDtDd": "Ajoutez au moins une paire <dt>/<dd> à l’intérieur de ce <dl>.",
617
- "dlitemParentValid_title": "Les éléments d’une liste de définitions doivent se trouver à l’intérieur d’une liste de définitions",
618
- "dlitemParentValid_description": "Vérifie que les éléments <dt>/<dd> sont contenus par un <dl>, directement ou via un <div> englobant.",
619
- "dlitemParentValid_summary_fail": "Le parent (<{{parentElement}}>) de ce <{{element}}> n’est pas une liste de définitions.",
620
- "dlitemParentValid_hint_fail": "Placez ce <dt>/<dd> à l’intérieur d’un <dl>, directement ou enveloppé dans un seul <div>.",
621
- "duplicateIdAria_title": "Les ID référencés par ARIA doivent être uniques",
622
- "duplicateIdAria_description": "Vérifie que toute valeur id référencée par un attribut de référence d’ID ARIA (aria-labelledby, aria-describedby, aria-owns, aria-controls, aria-activedescendant, aria-flowto, aria-errormessage, aria-details) est unique dans le document.",
623
- "duplicateIdAria_summary_fail": "L’id « {{id}} » est référencé par un attribut ARIA mais est utilisé par {{duplicateCount}} éléments.",
624
- "duplicateIdAria_hint_fail": "Rendez uniques dans le document les id référencés par des attributs ARIA.",
625
- "summaryNamePresent_title": "Les éléments summary ont un nom accessible",
626
- "summaryNamePresent_description": "Vérifie que les éléments <summary> exposent un nom accessible non vide.",
627
- "summaryNamePresent_summary_fail": "Ce summary n’a pas de nom accessible.",
628
- "summaryNamePresent_hint_fail": "Fournissez un texte de summary qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
629
- "metaViewportZoomEnabled_title": "La balise meta viewport ne doit pas désactiver le zoom",
630
- "metaViewportZoomEnabled_description": "Vérifie que <meta name=\"viewport\"> ne définit pas user-scalable=no ni maximum-scale en dessous de 2 (200 %).",
631
- "metaViewportZoomEnabled_summary_fail": "Cette balise meta viewport restreint la capacité de l’utilisateur à zoomer ({{reasons}}).",
632
- "metaViewportZoomEnabled_hint_fail": "Retirez user-scalable=no et tout maximum-scale inférieur à 2 du contenu de la balise meta viewport.",
633
- "metaRefreshTimingAbsent_title": "La page ne doit pas utiliser un rafraîchissement meta minuté",
634
- "metaRefreshTimingAbsent_description": "Vérifie que <meta http-equiv=\"refresh\"> n’impose pas un délai positif de 20 heures ou moins.",
635
- "metaRefreshTimingAbsent_summary_fail": "Cette page se rafraîchit automatiquement après {{delay}} secondes.",
636
- "metaRefreshTimingAbsent_hint_fail": "Retirez le rafraîchissement meta minuté, ou proposez un moyen pour les utilisateurs de le désactiver, de le prolonger ou de le mettre en pause avant qu’il ne se déclenche.",
637
- "meterNamePresent_title": "Les éléments meter ont un nom accessible",
638
- "meterNamePresent_description": "Vérifie que les éléments avec role=\"meter\" exposent un nom accessible non vide.",
639
- "meterNamePresent_summary_fail": "Ce meter n’a pas de nom accessible.",
640
- "meterNamePresent_hint_fail": "Fournissez un texte pour le meter qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
641
- "progressbarNamePresent_title": "Les barres de progression ont un nom accessible",
642
- "progressbarNamePresent_description": "Vérifie que les éléments avec role=\"progressbar\" exposent un nom accessible non vide.",
643
- "progressbarNamePresent_summary_fail": "Cette barre de progression n’a pas de nom accessible.",
644
- "progressbarNamePresent_hint_fail": "Fournissez un texte pour la barre de progression qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
645
- "tooltipNamePresent_title": "Les infobulles ont un nom accessible",
646
- "tooltipNamePresent_description": "Vérifie que les éléments avec role=\"tooltip\" exposent un nom accessible non vide.",
647
- "tooltipNamePresent_summary_fail": "Cette infobulle n’a pas de nom accessible.",
648
- "tooltipNamePresent_hint_fail": "Fournissez un texte pour l’infobulle qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.",
649
- "serverSideImageMapAbsent_title": "Les images ne doivent pas utiliser une carte d’image côté serveur",
650
- "serverSideImageMapAbsent_description": "Vérifie que les éléments <img> ne portent pas l’attribut ismap (les cartes d’image côté serveur n’ont pas d’équivalent utilisable au clavier).",
651
- "serverSideImageMapAbsent_summary_fail": "Cette image utilise une carte d’image côté serveur, qui n’a pas d’équivalent utilisable au clavier.",
652
- "serverSideImageMapAbsent_hint_fail": "Remplacez la carte d’image côté serveur (ismap) par une carte d’image côté client (<map>/<area>) ou par des liens/boutons accessibles distincts.",
653
- "formControlSingleLabel_title": "Les contrôles de formulaire ne doivent pas avoir plusieurs étiquettes",
654
- "formControlSingleLabel_description": "Vérifie qu’un contrôle de formulaire est associé à au plus un <label> (par imbrication ou par label[for]).",
655
- "formControlSingleLabel_summary_fail": "Ce <{{element}}> est associé à {{labelCount}} étiquettes.",
656
- "formControlSingleLabel_hint_fail": "Conservez une seule <label> par contrôle de formulaire (soit en l’enveloppant, soit en la référençant via for/id).",
657
- "nestedInteractiveControlsAbsent_title": "Les contrôles interactifs ne doivent pas être imbriqués",
658
- "nestedInteractiveControlsAbsent_description": "Vérifie qu’un contrôle interactif (lien, bouton, contrôle de formulaire, ou rôle de widget ARIA) ne contient pas un autre contrôle interactif.",
659
- "nestedInteractiveControlsAbsent_summary_fail": "Ce <{{element}}> contient un ou plusieurs contrôles interactifs imbriqués : {{nestedElements}}.",
660
- "nestedInteractiveControlsAbsent_hint_fail": "Déplacez le(s) contrôle(s) interactif(s) imbriqué(s) hors de cet élément ; les contrôles interactifs imbriqués ne sont pas utilisables de façon fiable via les technologies d’assistance.",
661
- "bypassBlocksPresent_title": "La page doit proposer un moyen de contourner les blocs répétés",
662
- "bypassBlocksPresent_description": "Vérifie que la page dispose d’au moins un mécanisme reconnu de contournement des blocs répétés (WCAG 2.4.1) : un point de repère main, un lien d’ancrage fonctionnel vers la même page, ou un titre.",
663
- "bypassBlocksPresent_summary_fail": "Cette page n’a aucun moyen reconnu de contourner les blocs de contenu répétés.",
664
- "bypassBlocksPresent_hint_fail": "Ajoutez un point de repère main (<main> ou role=\"main\"), un lien « aller au contenu » fonctionnel, ou des éléments de titre que les technologies d’assistance peuvent utiliser pour passer le contenu répété.",
665
- "landmarkBannerIsTopLevel_title": "Le point de repère banner doit être de premier niveau",
666
- "landmarkBannerIsTopLevel_description": "Vérifie que le point de repère banner (role=\"banner\" ou un <header> non imbriqué) n’est pas imbriqué dans un autre point de repère.",
667
- "landmarkBannerIsTopLevel_summary_cantTell": "Ce point de repère banner est imbriqué dans un autre point de repère.",
668
- "landmarkBannerIsTopLevel_hint_cantTell": "Déplacez le point de repère banner (header/role=\"banner\") afin qu’il ne soit contenu par aucun autre point de repère ; un banner doit être une région de premier niveau de la page.",
669
- "landmarkContentinfoIsTopLevel_title": "Le point de repère contentinfo doit être de premier niveau",
670
- "landmarkContentinfoIsTopLevel_description": "Vérifie que le point de repère contentinfo (role=\"contentinfo\" ou un <footer> non imbriqué) n’est pas imbriqué dans un autre point de repère.",
671
- "landmarkContentinfoIsTopLevel_summary_cantTell": "Ce point de repère contentinfo est imbriqué dans un autre point de repère.",
672
- "landmarkContentinfoIsTopLevel_hint_cantTell": "Déplacez le point de repère contentinfo (footer/role=\"contentinfo\") afin qu’il ne soit contenu par aucun autre point de repère ; contentinfo doit être une région de premier niveau de la page.",
673
- "landmarkMainIsTopLevel_title": "Le point de repère main doit être de premier niveau",
674
- "landmarkMainIsTopLevel_description": "Vérifie que le point de repère main (role=\"main\" ou <main>) n’est pas imbriqué dans un autre point de repère.",
675
- "landmarkMainIsTopLevel_summary_cantTell": "Ce point de repère main est imbriqué dans un autre point de repère.",
676
- "landmarkMainIsTopLevel_hint_cantTell": "Déplacez le point de repère main (<main>/role=\"main\") afin qu’il ne soit contenu par aucun autre point de repère ; main doit être une région de premier niveau de la page.",
677
- "landmarkNoDuplicateBanner_title": "La page ne doit pas avoir plus d’un point de repère banner",
678
- "landmarkNoDuplicateBanner_description": "Vérifie qu’au plus un point de repère banner (role=\"banner\" ou un <header> non imbriqué) existe sur la page.",
679
- "landmarkNoDuplicateBanner_summary_cantTell": "Cette page a plus d’un point de repère banner.",
680
- "landmarkNoDuplicateBanner_hint_cantTell": "Ne conservez qu’un seul point de repère banner (header/role=\"banner\") par page.",
681
- "landmarkNoDuplicateContentinfo_title": "La page ne doit pas avoir plus d’un point de repère contentinfo",
682
- "landmarkNoDuplicateContentinfo_description": "Vérifie qu’au plus un point de repère contentinfo (role=\"contentinfo\" ou un <footer> non imbriqué) existe sur la page.",
683
- "landmarkNoDuplicateContentinfo_summary_cantTell": "Cette page a plus d’un point de repère contentinfo.",
684
- "landmarkNoDuplicateContentinfo_hint_cantTell": "Ne conservez qu’un seul point de repère contentinfo (footer/role=\"contentinfo\") par page.",
685
- "landmarkNoDuplicateMain_title": "La page ne doit pas avoir plus d’un point de repère main",
686
- "landmarkNoDuplicateMain_description": "Vérifie qu’au plus un point de repère main (role=\"main\" ou <main>) existe sur la page.",
687
- "landmarkNoDuplicateMain_summary_cantTell": "Cette page a plus d’un point de repère main.",
688
- "landmarkNoDuplicateMain_hint_cantTell": "Ne conservez qu’un seul point de repère main (<main>/role=\"main\") par page.",
689
- "landmarkOneMain_title": "La page devrait avoir un point de repère main",
690
- "landmarkOneMain_description": "Vérifie que la page a au moins un point de repère main (role=\"main\" ou <main>).",
691
- "landmarkOneMain_summary_cantTell_missing": "Cette page n’a aucun point de repère main.",
692
- "landmarkOneMain_hint_cantTell_missing": "Ajoutez un point de repère main (<main> ou role=\"main\") autour du contenu principal de la page.",
693
- "landmarkUnique_title": "Les points de repère partageant le même rôle doivent avoir des noms uniques",
694
- "landmarkUnique_description": "Vérifie que lorsque deux points de repère ou plus partagent le même rôle, chacun a un nom accessible distinct.",
695
- "landmarkUnique_summary_cantTell_duplicateName": "Ce point de repère {{role}} partage son nom accessible avec un autre point de repère {{role}}.",
696
- "landmarkUnique_summary_cantTell_bothUnnamed": "Ce point de repère {{role}} n’a pas de nom accessible, et plus d’un point de repère {{role}} sans nom existe sur cette page.",
697
- "landmarkUnique_hint_cantTell": "Donnez à chaque point de repère {{role}} un nom distinct via aria-label ou aria-labelledby.",
698
- "emptyHeading_title": "Les titres ne doivent pas être vides",
699
- "emptyHeading_description": "Vérifie que les éléments de titre (<h1>-<h6> ou role=\"heading\") ont un nom accessible non vide.",
700
- "emptyHeading_summary_cantTell": "Ce titre n’a pas de nom accessible.",
701
- "emptyHeading_hint_cantTell": "Ajoutez du contenu textuel (ou aria-label/aria-labelledby) à ce titre, ou retirez-le s’il n’est pas nécessaire.",
702
- "headingOrder_title": "Les niveaux de titre ne doivent pas sauter un niveau",
703
- "headingOrder_description": "Vérifie que les niveaux de titre n’augmentent que d’un niveau à la fois, dans l’ordre du document.",
704
- "headingOrder_summary_cantTell": "Ce titre passe du niveau {{fromLevel}} au niveau {{toLevel}}, en sautant un niveau.",
705
- "headingOrder_hint_cantTell": "Utilisez des niveaux de titre consécutifs (ne sautez pas de niveau en descendant dans la hiérarchie) afin que le plan du document reste prévisible.",
706
- "pageHasHeadingOne_title": "La page devrait avoir un titre de niveau un",
707
- "pageHasHeadingOne_description": "Vérifie que la page a au moins un titre de niveau un (<h1> ou role=\"heading\" avec aria-level=\"1\").",
708
- "pageHasHeadingOne_summary_cantTell": "Cette page n’a aucun titre de niveau un.",
709
- "pageHasHeadingOne_hint_cantTell": "Ajoutez un titre de niveau un (<h1> ou role=\"heading\" aria-level=\"1\") identifiant le contenu principal de la page.",
710
- "accesskeys_title": "Les valeurs accesskey doivent être uniques",
711
- "accesskeys_description": "Vérifie qu’aucun élément de la page ne partage la même valeur d’attribut accesskey qu’un autre.",
712
- "accesskeys_summary_cantTell": "L’accesskey de cet élément est partagée avec un autre élément de la page.",
713
- "accesskeys_hint_cantTell": "Rendez chaque valeur accesskey unique sur l’ensemble de la page.",
714
- "scopeAttrValid_title": "L’attribut scope doit avoir une valeur valide",
715
- "scopeAttrValid_description": "Vérifie que scope=\"...\" vaut row, col, rowgroup, ou colgroup.",
716
- "scopeAttrValid_summary_cantTell": "Cette valeur d’attribut scope n’est pas reconnue.",
717
- "scopeAttrValid_hint_cantTell": "Utilisez row, col, rowgroup, ou colgroup pour l’attribut scope.",
718
- "tabindex_title": "tabindex ne devrait pas être supérieur à 0",
719
- "tabindex_description": "Vérifie que les valeurs de tabindex sont égales à 0 ou négatives, jamais un nombre positif.",
720
- "tabindex_summary_cantTell": "Cet élément a un tabindex positif, ce qui modifie l’ordre naturel de tabulation.",
721
- "tabindex_hint_cantTell": "Utilisez tabindex=\"0\" (ou une valeur négative pour le retirer de l’ordre de tabulation) plutôt qu’un nombre positif ; corrigez l’ordre dans le DOM si un ordre de tabulation différent est nécessaire.",
722
- "emptyTableHeader_title": "Les cellules d’en-tête de tableau ne doivent pas être vides",
723
- "emptyTableHeader_description": "Vérifie que les éléments <th> ont un contenu textuel visible — un en-tête nommé uniquement via aria-label/aria-labelledby est aussi signalé, car la prise en charge réelle par les lecteurs d’écran/navigateurs est incohérente.",
724
- "emptyTableHeader_summary_cantTell": "Cette cellule d’en-tête de tableau n’a pas de nom accessible.",
725
- "emptyTableHeader_hint_cantTell": "Ajoutez du contenu textuel (ou aria-label/aria-labelledby) à cette cellule d’en-tête, ou retirez-la si elle n’est pas nécessaire.",
726
- "emptyTableHeader_summary_cantTell_ariaOnly": "Cette cellule d’en-tête de tableau n’a pas de texte visible — son seul nom accessible provient de aria-label/aria-labelledby, que des combinaisons réelles de lecteur d’écran/navigateur (ex. NVDA+Firefox, iOS VoiceOver+Safari) sont connues pour ignorer sur les éléments <th>.",
727
- "emptyTableHeader_hint_cantTell_ariaOnly": "Ajoutez du contenu textuel visible à cette cellule d’en-tête (en plus de, ou à la place de, aria-label/aria-labelledby) — le texte visible est le seul mécanisme de nommage confirmé comme fonctionnel sur les lecteurs d’écran testés.",
728
- "labelTitleOnly_title": "Les contrôles de formulaire ne devraient pas utiliser title comme seule étiquette",
729
- "labelTitleOnly_description": "Vérifie qu’un contrôle de formulaire ayant un attribut title possède aussi une véritable étiquette (élément label, aria-label, ou aria-labelledby).",
730
- "labelTitleOnly_summary_cantTell": "Ce contrôle de formulaire repose sur l’attribut title comme seule étiquette.",
731
- "labelTitleOnly_hint_cantTell": "Ajoutez une <label> visible (ou aria-label/aria-labelledby) en plus de, ou à la place de, l’attribut title.",
732
- "imageRedundantAlt_title": "Le texte alt d’une image ne doit pas dupliquer le texte visible adjacent",
733
- "imageRedundantAlt_description": "Vérifie que le texte alt d’un <img> n’est pas identique à un autre texte visible déjà présent dans son élément parent immédiat.",
734
- "imageRedundantAlt_summary_cantTell": "Le texte alt de cette image duplique un autre texte visible juste à côté.",
735
- "imageRedundantAlt_hint_cantTell": "Videz le texte alt (alt=\"\") si l’image est purement décorative à côté du texte, ou supprimez la duplication redondante.",
736
- "tableDuplicateName_title": "La légende d’un tableau ne doit pas dupliquer son attribut summary",
737
- "tableDuplicateName_description": "Vérifie que le texte de la <caption> d’un <table> n’est pas identique à son attribut summary (obsolète).",
738
- "tableDuplicateName_summary_cantTell": "La légende de ce tableau duplique son attribut summary.",
739
- "tableDuplicateName_hint_cantTell": "Retirez l’attribut summary redondant, ou faites en sorte qu’il apporte une information différente de la légende.",
740
- "metaViewportLarge_title": "La balise meta viewport devrait permettre un zoom jusqu’à 500 %",
741
- "metaViewportLarge_description": "Vérifie que <meta name=\"viewport\"> ne définit pas user-scalable=no ni maximum-scale en dessous de 5 (500 %).",
742
- "metaViewportLarge_summary_cantTell": "Cette balise meta viewport restreint le zoom en dessous de l’objectif de bonne pratique de 500 %.",
743
- "metaViewportLarge_hint_cantTell": "Retirez user-scalable=no et augmentez maximum-scale à au moins 5 (500 %) si possible.",
744
- "presentationRoleConflict_title": "Un rôle de présentation ne doit pas entrer en conflit avec un attribut ARIA global ou la focalisabilité",
745
- "presentationRoleConflict_description": "Vérifie que role=\"presentation\"/\"none\" (y compris le rôle presentation implicite d’un <img alt=\"\">) n’est pas combiné avec un attribut ARIA global (aria-label, aria-hidden, aria-describedby, ...) ou avec la focalisabilité (tabindex/native).",
746
- "presentationRoleConflict_summary_cantTell": "Cet élément role=\"{{role}}\" a aussi une condition conflictuelle ({{attrs}}), qui restaure son rôle implicite et annule l’intention présentationnelle.",
747
- "presentationRoleConflict_hint_cantTell": "Retirez le(s) attribut(s) de nommage conflictuel(s) et/ou la focalisabilité (tabindex/native) si l’élément doit rester présentationnel, ou retirez role=\"presentation\"/\"none\" s’il doit être exposé aux technologies d’assistance.",
748
- "region_title": "Le contenu de la page devrait se trouver à l’intérieur d’un point de repère",
749
- "region_description": "Vérifie que les enfants directs de <body> ayant un contenu textuel visible sont contenus dans un point de repère.",
750
- "region_summary_cantTell": "Ce contenu n’est contenu dans aucun point de repère.",
751
- "region_hint_cantTell": "Déplacez ce contenu à l’intérieur d’un point de repère (main, nav, aside, une section nommée, etc.).",
752
- "skipLink_title": "Un lien d’évitement doit avoir une cible qui se résout et qui est utilisable",
753
- "skipLink_description": "Vérifie que le fragment href d’un lien « aller au... » se résout vers un élément réel et actuellement utilisable du document.",
754
- "skipLink_summary_cantTell": "La cible de ce lien d’évitement n’existe pas.",
755
- "skipLink_hint_cantTell": "Faites pointer le href du lien d’évitement vers un id qui existe dans le document, ou ajoutez l’élément cible manquant.",
756
- "skipLink_summary_unusableTarget_cantTell": "Ce lien d’évitement pointe vers une cible qui existe mais qui n’est pas actuellement utilisable.",
757
- "skipLink_hint_unusableTarget_cantTell": "Faites pointer ce lien d’évitement vers une cible exposée et utilisable comme destination de navigation.",
758
- "autocompleteValid_title": "L’attribut autocomplete doit être une valeur d’auto-remplissage valide",
759
- "autocompleteValid_description": "Vérifie qu’un attribut autocomplete non vide vaut « on »/« off » ou une liste de jetons d’auto-remplissage bien formée.",
760
- "autocompleteValid_summary_fail": "Cette valeur d’attribut autocomplete n’est pas une valeur d’auto-remplissage valide.",
761
- "autocompleteValid_hint_fail": "Utilisez « on »/« off », ou une liste de jetons d’auto-remplissage valide (ex. « shipping street-address », « cc-number »).",
762
- "htmlXmlLangMismatch_title": "lang et xml:lang ne doivent pas se contredire",
763
- "htmlXmlLangMismatch_description": "Vérifie que les attributs lang et xml:lang de l’élément <html> déclarent la même langue principale, lorsque les deux sont présents.",
764
- "htmlXmlLangMismatch_summary_fail": "Les attributs lang (« {{lang}} ») et xml:lang (« {{xmlLang}} ») déclarent des langues différentes.",
765
- "htmlXmlLangMismatch_hint_fail": "Faites en sorte que lang et xml:lang déclarent la même langue principale, ou retirez l’attribut obsolète xml:lang.",
766
- "avoidInlineSpacing_title": "Un style en ligne ne doit pas forcer l’espacement du texte avec !important",
767
- "avoidInlineSpacing_description": "Vérifie qu’un style en ligne ne définit pas line-height, letter-spacing, ou word-spacing avec !important, ce qui bloque les surcharges d’espacement de texte par l’utilisateur.",
768
- "avoidInlineSpacing_summary_fail": "Le style en ligne de cet élément force {{properties}} avec !important, bloquant les surcharges d’espacement de texte par l’utilisateur.",
769
- "avoidInlineSpacing_hint_fail": "Retirez !important de line-height/letter-spacing/word-spacing dans les styles en ligne afin que les utilisateurs puissent surcharger l’espacement du texte.",
770
- "metaRefreshNoExceptions_title": "La page ne doit utiliser aucun rafraîchissement meta (AAA)",
771
- "metaRefreshNoExceptions_description": "Vérifie que <meta http-equiv=\"refresh\"> n’est présent en aucun cas, quel que soit le délai — la variante plus stricte, de niveau AAA, de la vérification de niveau A qui ne porte que sur les délais positifs.",
772
- "metaRefreshNoExceptions_summary_fail": "Cette page utilise un rafraîchissement meta, un changement de contexte automatique non initié par l’utilisateur.",
773
- "metaRefreshNoExceptions_hint_fail": "Retirez le rafraîchissement meta ; déclenchez la redirection/le rafraîchissement uniquement en réponse à une action de l’utilisateur.",
774
- "validLang_title": "L’attribut lang d’un élément doit être syntaxiquement valide",
775
- "validLang_description": "Vérifie que tout élément (autre que la racine <html>) ayant un attribut lang non vide utilise une étiquette de langue syntaxiquement valide.",
776
- "validLang_summary_fail": "Cette valeur d’attribut lang (« {{value}} ») n’est pas une étiquette de langue syntaxiquement valide.",
777
- "validLang_hint_fail": "Utilisez une étiquette de langue BCP47 valide (ex. « fr », « es-MX »).",
778
- "linkInTextBlock_title": "Les liens dans des blocs de texte doivent être distinguables du texte environnant sans se fier uniquement à la couleur",
779
- "linkInTextBlock_description": "Vérifie qu’un lien à l’intérieur d’un bloc de texte est visuellement distinguable du texte environnant par un soulignement, une différence de graisse/style de police, ou un contraste de couleur suffisant (>= 3:1) — pas seulement par la couleur.",
780
- "linkInTextBlock_summary_fail": "Ce lien dans un bloc de texte se distingue du texte environnant uniquement par la couleur.",
781
- "linkInTextBlock_hint_fail": "Ajoutez un soulignement, une différence de graisse/style de police, ou augmentez le contraste de couleur entre le lien et le texte environnant à au moins 3:1.",
782
- "noAutoplayAudio_title": "Un audio en lecture automatique devrait proposer un mécanisme de pause/arrêt ou de contrôle du volume",
783
- "noAutoplayAudio_description": "Signale les éléments <audio>/<video> qui se lancent automatiquement sans être coupés et sans attribut controls natif, pour une revue manuelle par rapport à l’exemption de 3 secondes de la WCAG 1.4.2.",
784
- "noAutoplayAudio_summary_cantTell": "Cet élément lit un audio automatiquement sans mécanisme natif de pause/arrêt ou de contrôle du volume.",
785
- "noAutoplayAudio_hint_cantTell": "Si ce clip dure plus de 3 secondes, ajoutez un attribut controls (ou un mécanisme personnalisé équivalent) afin que les utilisateurs puissent le mettre en pause/l’arrêter ou contrôler son volume indépendamment du volume du système.",
786
- "videoCaption_title": "Une vidéo préenregistrée devrait proposer une piste de sous-titres",
787
- "videoCaption_description": "Signale les éléments <video> sans enfant <track kind=\"captions\"|\"subtitles\">, pour une revue manuelle visant à déterminer si la vidéo a une piste audio nécessitant des sous-titres.",
788
- "videoCaption_summary_cantTell": "Cette vidéo n’a aucune piste de sous-titres (captions ou subtitles).",
789
- "videoCaption_hint_cantTell": "Si cette vidéo a une piste audio porteuse d’information, ajoutez un <track kind=\"captions\" src=\"...\"> avec le contenu sous-titré.",
790
- "scrollableRegionFocusable_title": "Les régions défilantes sans contenu focalisable devraient être focalisables au clavier",
791
- "scrollableRegionFocusable_description": "Signale les éléments dont le CSS déclare overflow:auto/scroll, qui ne contiennent aucun descendant focalisable, et qui ne sont pas eux-mêmes focalisables au clavier, pour une revue manuelle visant à déterminer si leur contenu déborde réellement et nécessite un accès au défilement au clavier.",
792
- "scrollableRegionFocusable_summary_cantTell": "Cet élément déclare overflow:auto/scroll, n’a aucun descendant focalisable, et n’est pas lui-même focalisable au clavier.",
793
- "scrollableRegionFocusable_hint_cantTell": "Si le contenu de cette région déborde réellement, ajoutez tabindex=\"0\" (et une étiquette adaptée) afin que les utilisateurs du clavier puissent la focaliser et faire défiler avec les flèches.",
794
- "identicalLinksSamePurpose_title": "Les liens partageant le même nom accessible devraient mener à la même destination",
795
- "identicalLinksSamePurpose_description": "Signale les groupes de liens qui partagent le même nom accessible mais mènent à plus d’une destination distincte, pour une revue manuelle visant à déterminer s’ils servent le même objectif.",
796
- "identicalLinksSamePurpose_summary_cantTell": "Ce lien partage un nom accessible avec d’autres liens de la page qui mènent à une destination différente.",
797
- "identicalLinksSamePurpose_hint_cantTell": "Assurez-vous que les liens ayant le même texte servent le même objectif, ou rendez le texte du lien suffisamment distinct pour décrire chaque destination.",
798
- "ariaBrailleEquivalent_title": "aria-braillelabel/aria-brailleroledescription doivent avoir un équivalent non braille",
799
- "ariaBrailleEquivalent_description": "Vérifie que les éléments utilisant aria-braillelabel ont aussi un nom accessible ordinaire, et que ceux utilisant aria-brailleroledescription ont aussi aria-roledescription.",
800
- "ariaBrailleEquivalent_summary_fail": "Cet élément a {{attr}} mais pas {{requires}}, son équivalent non braille.",
801
- "ariaBrailleEquivalent_hint_fail": "{{attr}} est un complément spécifique au braille, pas un remplacement — fournissez aussi {{requires}}.",
802
- "ariaConditionalAttr_title": "aria-errormessage exige que aria-invalid soit défini à une valeur autre que false",
803
- "ariaConditionalAttr_description": "Vérifie que les éléments ayant aria-errormessage ont aussi aria-invalid défini à « true », « grammar », ou « spelling » — sinon le message d’erreur est retiré de l’arbre d’accessibilité.",
804
- "ariaConditionalAttr_summary_fail": "Cet élément a aria-errormessage mais aria-invalid est absent ou « false », donc le message d’erreur n’est pas exposé.",
805
- "ariaConditionalAttr_hint_fail": "Définissez aria-invalid à « true » (ou « grammar »/« spelling ») chaque fois que aria-errormessage doit être exposé aux technologies d’assistance.",
806
- "ariaCheckedStateMismatch_title": "L’aria-checked d’une case à cocher/d’un bouton radio natif devrait correspondre à son état réel",
807
- "ariaCheckedStateMismatch_description": "Signale un <input type=\"checkbox\">/<input type=\"radio\"> natif dont la valeur explicite d’aria-checked ne correspond pas à son état réel (coché/indéterminé), pour une revue manuelle.",
808
- "ariaCheckedStateMismatch_summary_cantTell": "La valeur d’aria-checked de cet élément ne correspond pas à son état réel (coché/indéterminé).",
809
- "ariaCheckedStateMismatch_hint_cantTell": "Définissez aria-checked pour qu’il corresponde à l’état réel de l’élément, ou retirez-le — une case à cocher/un bouton radio natif expose déjà cet état sans lui.",
810
- "cssOrientationLock_title": "Le CSS ne doit pas verrouiller la page à une seule orientation",
811
- "cssOrientationLock_description": "Vérifie qu’aucune règle @media (orientation: portrait|landscape) ne définit un transform: rotate(...) sur la page, une technique connue pour contourner l’orientation de l’appareil.",
812
- "cssOrientationLock_summary_fail": "Une media query « {{mediaText}} » fait pivoter « {{selectorText}} », verrouillant la page à une seule orientation.",
813
- "cssOrientationLock_hint_fail": "Retirez la transformation rotate() de la media query d’orientation ; laissez la page répondre naturellement à l’orientation de l’appareil au lieu de forcer une rotation visuelle.",
814
- "ariaText_title": "Les éléments role=\"text\" ne devraient avoir aucun descendant focalisable",
815
- "ariaText_description": "Vérifie que les éléments ayant role=\"text\" ne contiennent aucun descendant focalisable (lien, bouton, contrôle de formulaire, tabindex, iframe, ou contenteditable).",
816
- "ariaText_summary_cantTell": "Cet élément role=\"text\" contient un descendant focalisable.",
817
- "ariaText_hint_cantTell": "Retirez role=\"text\" (ou retirez le descendant focalisable) — une région de « texte brut » ne devrait pas contenir de contenu focalisable.",
818
- "focusOrderSemantics_title": "Les éléments ajoutés à l’ordre de tabulation devraient avoir une sémantique interactive",
819
- "focusOrderSemantics_description": "Signale les éléments ayant tabindex >= 0 dont le rôle explicite est un rôle structurel/documentaire non interactif (ex. heading, list, region, presentation), pour une revue manuelle.",
820
- "focusOrderSemantics_summary_cantTell": "Cet élément est dans l’ordre de tabulation (tabindex=\"{{tabindex}}\") mais a un rôle non interactif (« {{role}} »).",
821
- "focusOrderSemantics_hint_cantTell": "Retirez tabindex si cet élément n’est pas censé être interactif, ou utilisez un rôle interactif correspondant à son comportement réel.",
822
- "pAsHeading_title": "Un <p> stylé pour ressembler à un titre devrait probablement être un véritable titre",
823
- "pAsHeading_description": "Signale les éléments <p> courts dont tout le texte est en gras et affiché à >= 18px, pour une revue manuelle visant à déterminer si un véritable élément de titre devrait être utilisé à la place.",
824
- "pAsHeading_summary_cantTell": "Ce paragraphe est entièrement en gras et affiché à une taille évoquant un titre.",
825
- "pAsHeading_hint_cantTell": "Si ce texte introduit une nouvelle section, utilisez un véritable élément de titre (<h1>-<h6> ou role=\"heading\") plutôt que de styler un paragraphe pour qu’il y ressemble.",
826
- "tableFakeCaption_title": "La première ligne d’un tableau ne devrait pas tenir lieu de véritable <caption>",
827
- "tableFakeCaption_description": "Signale les tableaux sans <caption> dont la première ligne a une seule cellule non vide alors que les autres lignes ont plusieurs cellules, pour une revue manuelle visant à déterminer si cette cellule fait office de légende factice.",
828
- "tableFakeCaption_summary_cantTell": "Ce tableau n’a pas de <caption>, mais sa première ligne est une cellule unique placée au-dessus de lignes à plusieurs cellules — elle fait peut-être office de légende factice.",
829
- "tableFakeCaption_hint_cantTell": "Si cette cellule est censée décrire le tableau, utilisez un véritable élément <caption> plutôt qu’une cellule isolée en première ligne.",
830
- "tdHasHeader_title": "Les cellules de données des grands tableaux doivent avoir un en-tête associé",
831
- "tdHasHeader_description": "Vérifie que chaque <td> d’un tableau grand et simple (sans colspan/rowspan) a un en-tête associé — via un attribut headers, un <th> de colonne implicite au-dessus, ou un <th> de ligne implicite à sa gauche.",
832
- "tdHasHeader_summary_fail": "Cette cellule de données n’a pas d’en-tête associé (pas d’attribut headers, pas de <th> de colonne au-dessus, pas de <th> de ligne à gauche).",
833
- "tdHasHeader_hint_fail": "Ajoutez un attribut headers référençant le(s) id du/des <th> pertinent(s), ou restructurez le tableau afin que cette cellule ait un en-tête de ligne/colonne implicite.",
834
- "mouseOnlyEventHandlers_title": "Les gestionnaires d’événements en ligne réservés au pointeur devraient avoir un équivalent accessible au clavier",
835
- "mouseOnlyEventHandlers_description": "Signale les éléments ayant un gestionnaire d’événement en ligne réservé au pointeur (onmouseover, onmouseout, onmousedown, onmouseup, ondblclick, onmousemove, onmouseenter, onmouseleave) sans équivalent accessible au clavier (onkeydown/onkeyup/onkeypress/onfocus/onblur), pour une revue manuelle.",
836
- "mouseOnlyEventHandlers_summary_cantTell": "Cet élément a {{attrs}} mais aucun gestionnaire équivalent accessible au clavier.",
837
- "mouseOnlyEventHandlers_hint_cantTell": "Ajoutez onkeydown/onkeyup/onkeypress (ou onfocus/onblur pour un comportement déclenché au survol) afin que cette fonctionnalité soit aussi accessible au clavier.",
838
- "linkNameQuality_title": "Le texte des liens devrait être descriptif, pas générique",
839
- "linkNameQuality_description": "Signale les liens dont le nom accessible complet est une formule connue comme non descriptive (ex. « cliquez ici », « en savoir plus », « plus »), pour une revue manuelle visant à déterminer si l’objet du lien est clair sans contexte supplémentaire.",
840
- "linkNameQuality_summary_cantTell": "Le nom accessible de ce lien (« {{name}} ») est une formule générique et non descriptive.",
841
- "linkNameQuality_hint_cantTell": "Faites en sorte que le texte du lien lui-même décrive sa destination/son objet (ex. « Télécharger le guide tarifaire 2026 » plutôt que « Télécharger »), ou confirmez que le contexte environnant rend déjà l’objet clair.",
842
- }
608
+ 'catalog.rules.wcag_412_name.title': 'Nom, rôle, valeur : nom accessible',
609
+ 'catalog.rules.wcag_412_name.description':
610
+ 'Regroupe les contrôles garantissant que les éléments interactifs courants exposent un nom accessible non vide.',
611
+ labelInName_title: 'Intitulé dans le nom : le nom accessible contient le texte visible',
612
+ labelInName_description:
613
+ 'Vérifie que lorsqu’un composant possède un libellé textuel visible, le nom accessible contient ce libellé visible (WCAG 2.5.3).',
614
+ labelInName_summary_fail:
615
+ '{{element}} : le libellé visible « {{visibleLabel}} » (source : {{labelSource}}) n’est pas inclus dans le nom accessible (source : {{nameMechanism}}).',
616
+ labelInName_hint_fail:
617
+ 'Modifiez aria-label ou aria-labelledby (ou le texte du libellé visible) afin que le nom accessible inclue le libellé visible.',
618
+ ariaRolesValid_title: 'L’attribut role doit être un rôle ARIA valide et non abstrait',
619
+ ariaRolesValid_description:
620
+ 'Vérifie qu’un attribut role="" explicite correspond à un rôle WAI-ARIA réel et non abstrait.',
621
+ ariaRolesValid_summary_invalid: 'role="{{role}}" n’est pas un rôle ARIA reconnu.',
622
+ ariaRolesValid_hint_invalid:
623
+ 'Utilisez un rôle ARIA valide, ou retirez l’attribut role si aucun ne s’applique.',
624
+ ariaRolesValid_summary_abstract:
625
+ 'role="{{role}}" est un rôle ARIA abstrait, qui ne doit pas être utilisé directement.',
626
+ ariaRolesValid_hint_abstract:
627
+ 'Remplacez ce rôle abstrait par un rôle concret adapté au composant/à la structure.',
628
+ ariaDeprecatedRole_title:
629
+ 'L’attribut role ne doit pas utiliser un rôle ARIA obsolète ou interdit aux auteurs',
630
+ ariaDeprecatedRole_description:
631
+ 'Vérifie qu’un attribut role="" explicite n’utilise pas un rôle rendu obsolète par la spécification WAI-ARIA, ni un rôle réservé à un usage interne à l’agent utilisateur (ex. role="generic").',
632
+ ariaDeprecatedRole_summary_fail:
633
+ 'Cet élément utilise role="{{role}}", que les auteurs ne doivent pas déclarer explicitement.',
634
+ ariaDeprecatedRole_hint_fail: '{{guidance}}',
635
+ ariaValidAttr_title: 'Les attributs aria-* doivent être des attributs ARIA réels et définis',
636
+ ariaValidAttr_description:
637
+ 'Vérifie que chaque nom d’attribut aria-* présent dans le DOM est un attribut réel défini par la spécification WAI-ARIA.',
638
+ ariaValidAttr_summary_fail: '{{attr}} n’est pas un attribut ARIA reconnu.',
639
+ ariaValidAttr_hint_fail:
640
+ 'Corrigez le nom de l’attribut (vérifiez les fautes de frappe), ou retirez-le s’il n’est pas nécessaire.',
641
+ ariaValidAttrValue_title:
642
+ 'Les valeurs des attributs aria-* doivent correspondre à leur type déclaré',
643
+ ariaValidAttrValue_description:
644
+ 'Vérifie que chaque attribut aria-* reconnu a une valeur conforme à son type déclaré par WAI-ARIA (booléen, tri-état, jeton, entier, nombre ou référence d’ID).',
645
+ ariaValidAttrValue_summary_fail:
646
+ '{{attr}}="{{value}}" n’est pas une valeur valide pour cet attribut.',
647
+ ariaValidAttrValue_hint_fail:
648
+ 'Utilisez une valeur correspondant au type attendu de l’attribut (consultez la spécification WAI-ARIA pour cet attribut).',
649
+ ariaAllowedAttr_title: 'Les attributs aria-* doivent être autorisés pour le rôle de l’élément',
650
+ ariaAllowedAttr_description:
651
+ 'Vérifie que chaque attribut aria-* reconnu présent sur un élément ayant un rôle explicite est soit globalement pris en charge, soit pris en charge par ce rôle.',
652
+ ariaAllowedAttr_summary_fail: '{{attr}} n’est pas autorisé sur role="{{role}}".',
653
+ ariaAllowedAttr_hint_fail: 'Retirez cet attribut, ou utilisez un rôle qui le prend en charge.',
654
+ ariaProhibitedAttr_title:
655
+ 'Les attributs de nommage ARIA ne doivent pas être utilisés sur des rôles qui les interdisent',
656
+ ariaProhibitedAttr_description:
657
+ 'Vérifie que aria-label/aria-labelledby ne sont pas présents sur des rôles WAI-ARIA dont la spécification interdit explicitement le nommage ARIA (ex. generic, emphasis, strong, paragraph).',
658
+ ariaProhibitedAttr_summary_fail: '{{attr}} est interdit sur role="{{role}}".',
659
+ ariaProhibitedAttr_hint_fail:
660
+ 'Retirez cet attribut ; ce rôle ne doit pas porter de nom accessible.',
661
+ ariaProhibitedAttr_summary_fail_roleless:
662
+ "Cet élément {{element}} n'a aucun rôle ni autre source de nom accessible, donc {{attr}} n'est pas exposé de façon fiable aux technologies d'assistance.",
663
+ ariaProhibitedAttr_hint_fail_roleless:
664
+ 'Donnez à cet élément un rôle prenant en charge un nom accessible (par ex. role="img"/"button"), ou retirez cet attribut s\'il ne sert à rien sans rôle.',
665
+ ariaProhibitedAttr_summary_cantTell_roleless:
666
+ "Cet élément {{element}} n'a aucun rôle, donc {{attr}} pourrait ne pas être exposé comme nom accessible par les technologies d'assistance — mais le contenu de l'élément en fournit déjà un.",
667
+ ariaProhibitedAttr_hint_cantTell_roleless:
668
+ 'Vérifiez si le contenu textuel existant sert déjà de libellé à cet élément ; si oui, l\'attribut de nommage est redondant, sinon donnez à l\'élément un rôle prenant en charge le nommage (par ex. role="img").',
669
+ ariaRequiredAttr_title: 'Les rôles avec un état/une propriété ARIA requis doivent le porter',
670
+ ariaRequiredAttr_description:
671
+ 'Vérifie que les éléments ayant un rôle explicite portent chaque état/propriété aria-* requis, non ambigu et indépendant du contexte, pour ce rôle (ex. role="checkbox" doit avoir aria-checked).',
672
+ ariaRequiredAttr_summary_fail: '{{attr}} est requis pour role="{{role}}", mais est absent.',
673
+ ariaRequiredAttr_hint_fail: 'Ajoutez cet attribut avec une valeur valide pour ce rôle.',
674
+ ariaAllowedRole_title: 'Le rôle explicite doit être autorisé pour son élément hôte',
675
+ ariaAllowedRole_description:
676
+ 'Vérifie qu’un attribut role="" explicite fait partie des rôles que la spécification ARIA-in-HTML autorise pour l’élément hôte (ex. role="tab" n’est pas autorisé sur <nav>).',
677
+ ariaAllowedRole_summary_fail: 'role="{{role}}" n’est pas autorisé sur <{{element}}>.',
678
+ ariaAllowedRole_hint_fail:
679
+ 'Utilisez un rôle autorisé pour cet élément, ou changez l’élément hôte.',
680
+ ariaRequiredChildren_title:
681
+ 'Les rôles conteneurs doivent posséder au moins un rôle enfant requis',
682
+ ariaRequiredChildren_description:
683
+ 'Vérifie que les rôles conteneurs disposant d’une entrée documentée « éléments possédés requis » (list, listbox, menu, radiogroup, table, grid, tablist, tree, row, ...) contiennent au moins un descendant, ou un élément référencé par aria-owns, ayant un rôle possédé acceptable.',
684
+ ariaRequiredChildren_summary_fail:
685
+ 'role="{{role}}" ne possède aucun enfant ayant l’un des rôles requis : {{requiredRoles}}.',
686
+ ariaRequiredChildren_hint_fail:
687
+ 'Ajoutez un descendant (ou un élément référencé par aria-owns) ayant l’un des rôles possédés requis.',
688
+ ariaProhibitedChildren_title:
689
+ 'Les rôles conteneurs ne doivent pas posséder d’enfant ayant un rôle interdit',
690
+ ariaProhibitedChildren_description:
691
+ 'Vérifie que chaque enfant possédé (dans l’arbre d’accessibilité) d’un rôle conteneur (list, listbox, menu, menubar, radiogroup, rowgroup, table, grid, treegrid, tablist, tree, row) a l’un des rôles possédés autorisés par ce rôle.',
692
+ ariaProhibitedChildren_summary_fail:
693
+ 'Cet élément a le rôle role="{{childRole}}", qui n’est pas un rôle enfant possédé autorisé par le conteneur englobant role="{{containerRole}}".',
694
+ ariaProhibitedChildren_hint_fail:
695
+ 'Retirez ou modifiez ce rôle afin qu’il corresponde à l’un des rôles possédés autorisés du conteneur ({{allowedRoles}}), ou déplacez cet élément hors du conteneur {{containerRole}}.',
696
+ ariaProhibitedChildren_summary_fail_roleless:
697
+ 'Cet élément n’a pas de rôle explicite mais porte {{attr}}, ce qui en fait un véritable nœud de l’arbre d’accessibilité qui n’est pas un enfant possédé autorisé du conteneur englobant role="{{containerRole}}".',
698
+ ariaProhibitedChildren_hint_fail_roleless:
699
+ 'Retirez {{attr}} (ou la relation de possession avec le conteneur role="{{containerRole}}"), ou attribuez à cet élément role="presentation"/"none" s’il n’est pas censé constituer son propre nœud dans l’arbre d’accessibilité.',
700
+ ariaProhibitedChildren_summary_fail_native_focusable:
701
+ 'Cet élément n’a pas de rôle explicite mais est nativement focalisable, ce qui en fait un véritable nœud de l’arbre d’accessibilité qui n’est pas un enfant possédé autorisé du conteneur englobant role="{{containerRole}}".',
702
+ ariaProhibitedChildren_hint_fail_native_focusable:
703
+ 'Attribuez à cet élément role="presentation"/"none", retirez sa focalisabilité native (par ex. supprimez l’attribut href/tabindex à l’origine), ou déplacez-le hors du conteneur {{containerRole}}.',
704
+ ariaRequiredParent_title:
705
+ 'Les rôles exigeant un rôle de contexte spécifique doivent se trouver dans ce contexte',
706
+ ariaRequiredParent_description:
707
+ 'Vérifie que les rôles disposant d’une entrée documentée « rôle de contexte requis » (listitem, option, tab, treeitem, row, cell, ...) ont un ancêtre, ou un propriétaire aria-owns, ayant un rôle de contexte acceptable.',
708
+ ariaRequiredParent_summary_fail:
709
+ 'role="{{role}}" exige un rôle de contexte parmi : {{requiredRoles}}, qui n’a pas été trouvé.',
710
+ ariaRequiredParent_hint_fail:
711
+ 'Placez cet élément à l’intérieur d’un élément ayant un rôle de contexte acceptable (ou référencez-le depuis celui-ci via aria-owns).',
712
+ deprecatedElements_title:
713
+ 'Les éléments obsolètes non interruptibles (<blink>, <marquee>) ne doivent pas être utilisés',
714
+ deprecatedElements_description:
715
+ 'Vérifie que les éléments HTML obsolètes et non standards dont le contenu clignotant/défilant ne peut pas être mis en pause, arrêté ou masqué par l’utilisateur (<blink>, <marquee>) ne sont pas présents.',
716
+ deprecatedElements_summary_fail:
717
+ 'Le contenu de <{{element}}> ne peut pas être mis en pause, arrêté ou masqué par l’utilisateur.',
718
+ deprecatedElements_hint_fail:
719
+ 'Retirez cet élément ; utilisez à la place un contenu statique, ou une animation dotée d’un contrôle de pause/arrêt accessible à l’utilisateur.',
720
+ iframeNamePresent_title: 'Les cadres ont un nom accessible',
721
+ iframeNamePresent_description:
722
+ 'Vérifie que les éléments <iframe>/<frame> exposent un nom accessible non vide via aria-label, aria-labelledby, ou l’attribut title.',
723
+ iframeNamePresent_summary_fail: 'Ce <{{element}}> n’a pas de nom accessible.',
724
+ iframeNamePresent_hint_fail:
725
+ 'Ajoutez un attribut title (ou aria-label/aria-labelledby) décrivant le contenu ou l’objet du cadre.',
726
+ iframeTitleUnique_title: 'Les titres de cadres doivent être uniques',
727
+ iframeTitleUnique_description:
728
+ 'Vérifie qu’aucun <iframe>/<frame> dans le périmètre analysé ne partage la même valeur d’attribut title qu’un autre.',
729
+ iframeTitleUnique_summary_fail:
730
+ 'Le titre « {{title}} » de ce <{{element}}> n’est pas unique parmi les cadres de cette page.',
731
+ iframeTitleUnique_hint_fail:
732
+ 'Donnez à chaque cadre un titre distinct décrivant son contenu ou son objet spécifique.',
733
+ iframeFocusableContent_title:
734
+ 'Les cadres avec tabindex="-1" ne doivent pas contenir de contenu focalisable',
735
+ iframeFocusableContent_description:
736
+ 'Vérifie que les éléments <iframe>/<frame> de même origine avec tabindex="-1" ne contiennent pas de contenu focalisable, car les navigateurs ne propagent pas cette restriction au document intégré du cadre.',
737
+ iframeFocusableContent_summary_fail:
738
+ 'Ce <{{element}}> a tabindex="-1" mais son contenu contient des éléments focalisables, qui restent accessibles au clavier.',
739
+ iframeFocusableContent_hint_fail:
740
+ 'Retirez le contenu focalisable du cadre, ou retirez tabindex="-1" si le cadre est censé être accessible.',
741
+ tableHeadersAttrValid_title:
742
+ 'L’attribut headers d’une cellule de tableau doit référencer des cellules d’en-tête valides',
743
+ tableHeadersAttrValid_description:
744
+ 'Vérifie que chaque id de l’attribut headers d’un <td>/<th> correspond à un élément <th> du même tableau (ni absent, ni un élément autre que th, ni lui-même).',
745
+ tableHeadersAttrValid_summary_fail:
746
+ 'L’attribut headers de ce <{{element}}> référence des cellules d’en-tête invalides : {{invalidIds}}.',
747
+ tableHeadersAttrValid_hint_fail:
748
+ 'Mettez à jour l’attribut headers afin que chaque id désigne un élément <th> du même tableau.',
749
+ tableThHasDataCells_title: 'Les éléments <th> doivent décrire au moins une cellule de données',
750
+ tableThHasDataCells_description:
751
+ 'Vérifie qu’un tableau contenant des éléments <th> contient aussi au moins une cellule de données <td> que ces en-têtes décrivent.',
752
+ tableThHasDataCells_summary_fail:
753
+ 'Ce tableau a des cellules d’en-tête mais aucune cellule de données à décrire.',
754
+ tableThHasDataCells_hint_fail:
755
+ 'Ajoutez des cellules de données (<td>) au tableau, ou retirez les cellules d’en-tête si le tableau n’a pas de données.',
756
+ ariaHiddenBody_title: 'Le <body> du document ne doit pas être aria-hidden',
757
+ ariaHiddenBody_description:
758
+ 'Vérifie que <body> n’a pas aria-hidden="true", ce qui retirerait toute la page de l’arbre d’accessibilité.',
759
+ ariaHiddenBody_summary_fail:
760
+ 'Le corps du document a aria-hidden="true", ce qui masque toute la page aux technologies d’assistance.',
761
+ ariaHiddenBody_hint_fail:
762
+ 'Retirez aria-hidden de <body>. Masquez des éléments spécifiques à la place, si c’était l’intention.',
763
+ listChildrenValid_title: 'Les listes ne doivent contenir directement que des éléments de liste',
764
+ listChildrenValid_description:
765
+ 'Vérifie que les éléments <ul>/<ol> n’ont comme enfants directs que <li>, <script> ou <template>.',
766
+ listChildrenValid_summary_fail:
767
+ 'Ce <{{element}}> contient un enfant direct qui n’est pas un élément de liste : {{invalidChildren}}.',
768
+ listChildrenValid_hint_fail:
769
+ 'N’utilisez que <li> (ou <script>/<template>) comme enfants directs de <ul>/<ol> ; déplacez tout autre balisage à l’intérieur d’un <li>.',
770
+ listitemParentValid_title:
771
+ 'Les éléments de liste doivent se trouver à l’intérieur d’un conteneur de liste',
772
+ listitemParentValid_description:
773
+ 'Vérifie que les éléments <li> sont contenus par <ul>, <ol>, ou un élément ayant role="list".',
774
+ listitemParentValid_summary_fail:
775
+ 'Le parent de cet élément de liste (<{{parentElement}}>) n’est pas un conteneur de liste.',
776
+ listitemParentValid_hint_fail:
777
+ 'Placez ce <li> à l’intérieur d’un <ul>/<ol>, ou donnez à son parent role="list".',
778
+ definitionListChildrenValid_title:
779
+ 'Les listes de définitions doivent être structurées correctement',
780
+ definitionListChildrenValid_description:
781
+ 'Vérifie que les éléments <dl> ne contiennent directement que des groupes <dt>/<dd> (éventuellement enveloppés dans un seul <div>), <script>, <template>, ou <style>.',
782
+ definitionListChildrenValid_summary_fail_invalidChild:
783
+ 'Cette liste de définitions contient un enfant direct ou enveloppé qui ne fait pas partie d’un groupe dt/dd : {{invalidChildren}}.',
784
+ definitionListChildrenValid_hint_fail_invalidChild:
785
+ 'N’utilisez que <dt>/<dd> (éventuellement enveloppés dans un seul <div>), <script>, <template>, ou <style> à l’intérieur de <dl>.',
786
+ definitionListChildrenValid_summary_fail_noDtDd:
787
+ 'Cette liste de définitions n’a aucun groupe terme/définition <dt>/<dd>.',
788
+ definitionListChildrenValid_hint_fail_noDtDd:
789
+ 'Ajoutez au moins une paire <dt>/<dd> à l’intérieur de ce <dl>.',
790
+ dlitemParentValid_title:
791
+ 'Les éléments d’une liste de définitions doivent se trouver à l’intérieur d’une liste de définitions',
792
+ dlitemParentValid_description:
793
+ 'Vérifie que les éléments <dt>/<dd> sont contenus par un <dl>, directement ou via un <div> englobant.',
794
+ dlitemParentValid_summary_fail:
795
+ 'Le parent (<{{parentElement}}>) de ce <{{element}}> n’est pas une liste de définitions.',
796
+ dlitemParentValid_hint_fail:
797
+ 'Placez ce <dt>/<dd> à l’intérieur d’un <dl>, directement ou enveloppé dans un seul <div>.',
798
+ duplicateIdAria_title: 'Les ID référencés par ARIA doivent être uniques',
799
+ duplicateIdAria_description:
800
+ 'Vérifie que toute valeur id référencée par un attribut de référence d’ID ARIA (aria-labelledby, aria-describedby, aria-owns, aria-controls, aria-activedescendant, aria-flowto, aria-errormessage, aria-details) est unique dans le document.',
801
+ duplicateIdAria_summary_fail:
802
+ 'L’id « {{id}} » est référencé par un attribut ARIA mais est utilisé par {{duplicateCount}} éléments.',
803
+ duplicateIdAria_hint_fail:
804
+ 'Rendez uniques dans le document les id référencés par des attributs ARIA.',
805
+ summaryNamePresent_title: 'Les éléments summary ont un nom accessible',
806
+ summaryNamePresent_description:
807
+ 'Vérifie que les éléments <summary> exposent un nom accessible non vide.',
808
+ summaryNamePresent_summary_fail: 'Ce summary n’a pas de nom accessible.',
809
+ summaryNamePresent_hint_fail:
810
+ 'Fournissez un texte de summary qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
811
+ metaViewportZoomEnabled_title: 'La balise meta viewport ne doit pas désactiver le zoom',
812
+ metaViewportZoomEnabled_description:
813
+ 'Vérifie que <meta name="viewport"> ne définit pas user-scalable=no ni maximum-scale en dessous de 2 (200 %).',
814
+ metaViewportZoomEnabled_summary_fail:
815
+ 'Cette balise meta viewport restreint la capacité de l’utilisateur à zoomer ({{reasons}}).',
816
+ metaViewportZoomEnabled_hint_fail:
817
+ 'Retirez user-scalable=no et tout maximum-scale inférieur à 2 du contenu de la balise meta viewport.',
818
+ metaRefreshTimingAbsent_title: 'La page ne doit pas utiliser un rafraîchissement meta minuté',
819
+ metaRefreshTimingAbsent_description:
820
+ 'Vérifie que <meta http-equiv="refresh"> n’impose pas un délai positif de 20 heures ou moins.',
821
+ metaRefreshTimingAbsent_summary_fail:
822
+ 'Cette page se rafraîchit automatiquement après {{delay}} secondes.',
823
+ metaRefreshTimingAbsent_hint_fail:
824
+ 'Retirez le rafraîchissement meta minuté, ou proposez un moyen pour les utilisateurs de le désactiver, de le prolonger ou de le mettre en pause avant qu’il ne se déclenche.',
825
+ meterNamePresent_title: 'Les éléments meter ont un nom accessible',
826
+ meterNamePresent_description:
827
+ 'Vérifie que les éléments avec role="meter" exposent un nom accessible non vide.',
828
+ meterNamePresent_summary_fail: 'Ce meter n’a pas de nom accessible.',
829
+ meterNamePresent_hint_fail:
830
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de ce meter.',
831
+ progressbarNamePresent_title: 'Les barres de progression ont un nom accessible',
832
+ progressbarNamePresent_description:
833
+ 'Vérifie que les éléments avec role="progressbar" exposent un nom accessible non vide.',
834
+ progressbarNamePresent_summary_fail: 'Cette barre de progression n’a pas de nom accessible.',
835
+ progressbarNamePresent_hint_fail:
836
+ 'Fournissez aria-label, aria-labelledby ou un attribut title — le contenu textuel visible n’est pas exposé comme nom accessible de cette barre de progression.',
837
+ tooltipNamePresent_title: 'Les infobulles ont un nom accessible',
838
+ tooltipNamePresent_description:
839
+ 'Vérifie que les éléments avec role="tooltip" exposent un nom accessible non vide.',
840
+ tooltipNamePresent_summary_fail: 'Cette infobulle n’a pas de nom accessible.',
841
+ tooltipNamePresent_hint_fail:
842
+ 'Fournissez un texte pour l’infobulle qui ne soit pas masqué aux technologies d’assistance, ou fournissez aria-label ou aria-labelledby.',
843
+ serverSideImageMapAbsent_title:
844
+ 'Les images ne doivent pas utiliser une carte d’image côté serveur',
845
+ serverSideImageMapAbsent_description:
846
+ 'Vérifie que les éléments <img> ne portent pas l’attribut ismap (les cartes d’image côté serveur n’ont pas d’équivalent utilisable au clavier).',
847
+ serverSideImageMapAbsent_summary_fail:
848
+ 'Cette image utilise une carte d’image côté serveur, qui n’a pas d’équivalent utilisable au clavier.',
849
+ serverSideImageMapAbsent_hint_fail:
850
+ 'Remplacez la carte d’image côté serveur (ismap) par une carte d’image côté client (<map>/<area>) ou par des liens/boutons accessibles distincts.',
851
+ formControlSingleLabel_title:
852
+ 'Les contrôles de formulaire ne doivent pas avoir plusieurs étiquettes',
853
+ formControlSingleLabel_description:
854
+ 'Vérifie qu’un contrôle de formulaire est associé à au plus un <label> (par imbrication ou par label[for]).',
855
+ formControlSingleLabel_summary_fail: 'Ce <{{element}}> est associé à {{labelCount}} étiquettes.',
856
+ formControlSingleLabel_hint_fail:
857
+ 'Conservez une seule <label> par contrôle de formulaire (soit en l’enveloppant, soit en la référençant via for/id).',
858
+ nestedInteractiveControlsAbsent_title: 'Les contrôles interactifs ne doivent pas être imbriqués',
859
+ nestedInteractiveControlsAbsent_description:
860
+ 'Vérifie qu’un contrôle interactif (lien, bouton, contrôle de formulaire, ou rôle de widget ARIA) ne contient pas un autre contrôle interactif.',
861
+ nestedInteractiveControlsAbsent_summary_fail:
862
+ 'Ce <{{element}}> contient un ou plusieurs contrôles interactifs imbriqués : {{nestedElements}}.',
863
+ nestedInteractiveControlsAbsent_hint_fail:
864
+ 'Déplacez le(s) contrôle(s) interactif(s) imbriqué(s) hors de cet élément ; les contrôles interactifs imbriqués ne sont pas utilisables de façon fiable via les technologies d’assistance.',
865
+ bypassBlocksPresent_title: 'La page doit proposer un moyen de contourner les blocs répétés',
866
+ bypassBlocksPresent_description:
867
+ 'Vérifie que la page dispose d’au moins un mécanisme reconnu de contournement des blocs répétés (WCAG 2.4.1) : un point de repère main, un lien d’ancrage fonctionnel vers la même page, ou un titre.',
868
+ bypassBlocksPresent_summary_fail:
869
+ 'Cette page n’a aucun moyen reconnu de contourner les blocs de contenu répétés.',
870
+ bypassBlocksPresent_hint_fail:
871
+ 'Ajoutez un point de repère main (<main> ou role="main"), un lien « aller au contenu » fonctionnel, ou des éléments de titre que les technologies d’assistance peuvent utiliser pour passer le contenu répété.',
872
+ landmarkBannerIsTopLevel_title: 'Le point de repère banner doit être de premier niveau',
873
+ landmarkBannerIsTopLevel_description:
874
+ 'Vérifie que le point de repère banner (role="banner" ou un <header> non imbriqué) n’est pas imbriqué dans un autre point de repère.',
875
+ landmarkBannerIsTopLevel_summary_cantTell:
876
+ 'Ce point de repère banner est imbriqué dans un autre point de repère.',
877
+ landmarkBannerIsTopLevel_hint_cantTell:
878
+ 'Déplacez le point de repère banner (header/role="banner") afin qu’il ne soit contenu par aucun autre point de repère ; un banner doit être une région de premier niveau de la page.',
879
+ landmarkContentinfoIsTopLevel_title: 'Le point de repère contentinfo doit être de premier niveau',
880
+ landmarkContentinfoIsTopLevel_description:
881
+ 'Vérifie que le point de repère contentinfo (role="contentinfo" ou un <footer> non imbriqué) n’est pas imbriqué dans un autre point de repère.',
882
+ landmarkContentinfoIsTopLevel_summary_cantTell:
883
+ 'Ce point de repère contentinfo est imbriqué dans un autre point de repère.',
884
+ landmarkContentinfoIsTopLevel_hint_cantTell:
885
+ 'Déplacez le point de repère contentinfo (footer/role="contentinfo") afin qu’il ne soit contenu par aucun autre point de repère ; contentinfo doit être une région de premier niveau de la page.',
886
+ landmarkMainIsTopLevel_title: 'Le point de repère main doit être de premier niveau',
887
+ landmarkMainIsTopLevel_description:
888
+ 'Vérifie que le point de repère main (role="main" ou <main>) n’est pas imbriqué dans un autre point de repère.',
889
+ landmarkMainIsTopLevel_summary_cantTell:
890
+ 'Ce point de repère main est imbriqué dans un autre point de repère.',
891
+ landmarkMainIsTopLevel_hint_cantTell:
892
+ 'Déplacez le point de repère main (<main>/role="main") afin qu’il ne soit contenu par aucun autre point de repère ; main doit être une région de premier niveau de la page.',
893
+ landmarkNoDuplicateBanner_title: 'La page ne doit pas avoir plus d’un point de repère banner',
894
+ landmarkNoDuplicateBanner_description:
895
+ 'Vérifie qu’au plus un point de repère banner (role="banner" ou un <header> non imbriqué) existe sur la page.',
896
+ landmarkNoDuplicateBanner_summary_cantTell: 'Cette page a plus d’un point de repère banner.',
897
+ landmarkNoDuplicateBanner_hint_cantTell:
898
+ 'Ne conservez qu’un seul point de repère banner (header/role="banner") par page.',
899
+ landmarkNoDuplicateContentinfo_title:
900
+ 'La page ne doit pas avoir plus d’un point de repère contentinfo',
901
+ landmarkNoDuplicateContentinfo_description:
902
+ 'Vérifie qu’au plus un point de repère contentinfo (role="contentinfo" ou un <footer> non imbriqué) existe sur la page.',
903
+ landmarkNoDuplicateContentinfo_summary_cantTell:
904
+ 'Cette page a plus d’un point de repère contentinfo.',
905
+ landmarkNoDuplicateContentinfo_hint_cantTell:
906
+ 'Ne conservez qu’un seul point de repère contentinfo (footer/role="contentinfo") par page.',
907
+ landmarkNoDuplicateMain_title: 'La page ne doit pas avoir plus d’un point de repère main',
908
+ landmarkNoDuplicateMain_description:
909
+ 'Vérifie qu’au plus un point de repère main (role="main" ou <main>) existe sur la page.',
910
+ landmarkNoDuplicateMain_summary_cantTell: 'Cette page a plus d’un point de repère main.',
911
+ landmarkNoDuplicateMain_hint_cantTell:
912
+ 'Ne conservez qu’un seul point de repère main (<main>/role="main") par page.',
913
+ landmarkOneMain_title: 'La page devrait avoir un point de repère main',
914
+ landmarkOneMain_description:
915
+ 'Vérifie que la page a au moins un point de repère main (role="main" ou <main>).',
916
+ landmarkOneMain_summary_cantTell_missing: 'Cette page n’a aucun point de repère main.',
917
+ landmarkOneMain_hint_cantTell_missing:
918
+ 'Ajoutez un point de repère main (<main> ou role="main") autour du contenu principal de la page.',
919
+ landmarkUnique_title:
920
+ 'Les points de repère partageant le même rôle doivent avoir des noms uniques',
921
+ landmarkUnique_description:
922
+ 'Vérifie que lorsque deux points de repère ou plus partagent le même rôle, chacun a un nom accessible distinct.',
923
+ landmarkUnique_summary_cantTell_duplicateName:
924
+ 'Ce point de repère {{role}} partage son nom accessible avec un autre point de repère {{role}}.',
925
+ landmarkUnique_summary_cantTell_bothUnnamed:
926
+ 'Ce point de repère {{role}} n’a pas de nom accessible, et plus d’un point de repère {{role}} sans nom existe sur cette page.',
927
+ landmarkUnique_hint_cantTell:
928
+ 'Donnez à chaque point de repère {{role}} un nom distinct via aria-label ou aria-labelledby.',
929
+ emptyHeading_title: 'Les titres ne doivent pas être vides',
930
+ emptyHeading_description:
931
+ 'Vérifie que les éléments de titre (<h1>-<h6> ou role="heading") ont un nom accessible non vide.',
932
+ emptyHeading_summary_cantTell: 'Ce titre n’a pas de nom accessible.',
933
+ emptyHeading_hint_cantTell:
934
+ 'Ajoutez du contenu textuel (ou aria-label/aria-labelledby) à ce titre, ou retirez-le s’il n’est pas nécessaire.',
935
+ headingOrder_title: 'Les niveaux de titre ne doivent pas sauter un niveau',
936
+ headingOrder_description:
937
+ 'Vérifie que les niveaux de titre n’augmentent que d’un niveau à la fois, dans l’ordre du document.',
938
+ headingOrder_summary_cantTell:
939
+ 'Ce titre passe du niveau {{fromLevel}} au niveau {{toLevel}}, en sautant un niveau.',
940
+ headingOrder_hint_cantTell:
941
+ 'Utilisez des niveaux de titre consécutifs (ne sautez pas de niveau en descendant dans la hiérarchie) afin que le plan du document reste prévisible.',
942
+ pageHasHeadingOne_title: 'La page devrait avoir un titre de niveau un',
943
+ pageHasHeadingOne_description:
944
+ 'Vérifie que la page a au moins un titre de niveau un (<h1> ou role="heading" avec aria-level="1").',
945
+ pageHasHeadingOne_summary_cantTell: 'Cette page n’a aucun titre de niveau un.',
946
+ pageHasHeadingOne_hint_cantTell:
947
+ 'Ajoutez un titre de niveau un (<h1> ou role="heading" aria-level="1") identifiant le contenu principal de la page.',
948
+ accesskeys_title: 'Les valeurs accesskey doivent être uniques',
949
+ accesskeys_description:
950
+ 'Vérifie qu’aucun élément de la page ne partage la même valeur d’attribut accesskey qu’un autre.',
951
+ accesskeys_summary_cantTell:
952
+ 'L’accesskey de cet élément est partagée avec un autre élément de la page.',
953
+ accesskeys_hint_cantTell: 'Rendez chaque valeur accesskey unique sur l’ensemble de la page.',
954
+ scopeAttrValid_title: 'L’attribut scope doit avoir une valeur valide',
955
+ scopeAttrValid_description: 'Vérifie que scope="..." vaut row, col, rowgroup, ou colgroup.',
956
+ scopeAttrValid_summary_cantTell: 'Cette valeur d’attribut scope n’est pas reconnue.',
957
+ scopeAttrValid_hint_cantTell: 'Utilisez row, col, rowgroup, ou colgroup pour l’attribut scope.',
958
+ tabindex_title: 'tabindex ne devrait pas être supérieur à 0',
959
+ tabindex_description:
960
+ 'Vérifie que les valeurs de tabindex sont égales à 0 ou négatives, jamais un nombre positif.',
961
+ tabindex_summary_cantTell:
962
+ 'Cet élément a un tabindex positif, ce qui modifie l’ordre naturel de tabulation.',
963
+ tabindex_hint_cantTell:
964
+ 'Utilisez tabindex="0" (ou une valeur négative pour le retirer de l’ordre de tabulation) plutôt qu’un nombre positif ; corrigez l’ordre dans le DOM si un ordre de tabulation différent est nécessaire.',
965
+ emptyTableHeader_title: 'Les cellules d’en-tête de tableau ne doivent pas être vides',
966
+ emptyTableHeader_description:
967
+ 'Vérifie que les éléments <th> ont un contenu textuel visible — un en-tête nommé uniquement via aria-label/aria-labelledby est aussi signalé, car la prise en charge réelle par les lecteurs d’écran/navigateurs est incohérente.',
968
+ emptyTableHeader_summary_cantTell:
969
+ 'Cette cellule d’en-tête de tableau n’a pas de nom accessible.',
970
+ emptyTableHeader_hint_cantTell:
971
+ 'Ajoutez du contenu textuel (ou aria-label/aria-labelledby) à cette cellule d’en-tête, ou retirez-la si elle n’est pas nécessaire.',
972
+ emptyTableHeader_summary_cantTell_ariaOnly:
973
+ 'Cette cellule d’en-tête de tableau n’a pas de texte visible — son seul nom accessible provient de aria-label/aria-labelledby, que des combinaisons réelles de lecteur d’écran/navigateur (ex. NVDA+Firefox, iOS VoiceOver+Safari) sont connues pour ignorer sur les éléments <th>.',
974
+ emptyTableHeader_hint_cantTell_ariaOnly:
975
+ 'Ajoutez du contenu textuel visible à cette cellule d’en-tête (en plus de, ou à la place de, aria-label/aria-labelledby) — le texte visible est le seul mécanisme de nommage confirmé comme fonctionnel sur les lecteurs d’écran testés.',
976
+ labelTitleOnly_title:
977
+ 'Les contrôles de formulaire ne devraient pas utiliser title comme seule étiquette',
978
+ labelTitleOnly_description:
979
+ 'Vérifie qu’un contrôle de formulaire ayant un attribut title possède aussi une véritable étiquette (élément label, aria-label, ou aria-labelledby).',
980
+ labelTitleOnly_summary_cantTell:
981
+ 'Ce contrôle de formulaire repose sur l’attribut title comme seule étiquette.',
982
+ labelTitleOnly_hint_cantTell:
983
+ 'Ajoutez une <label> visible (ou aria-label/aria-labelledby) en plus de, ou à la place de, l’attribut title.',
984
+ imageRedundantAlt_title:
985
+ 'Le texte alt d’une image ne doit pas dupliquer le texte visible adjacent',
986
+ imageRedundantAlt_description:
987
+ 'Vérifie que le texte alt d’un <img> n’est pas identique à un autre texte visible déjà présent dans son élément parent immédiat.',
988
+ imageRedundantAlt_summary_cantTell:
989
+ 'Le texte alt de cette image duplique un autre texte visible juste à côté.',
990
+ imageRedundantAlt_hint_cantTell:
991
+ 'Videz le texte alt (alt="") si l’image est purement décorative à côté du texte, ou supprimez la duplication redondante.',
992
+ tableDuplicateName_title: 'La légende d’un tableau ne doit pas dupliquer son attribut summary',
993
+ tableDuplicateName_description:
994
+ 'Vérifie que le texte de la <caption> d’un <table> n’est pas identique à son attribut summary (obsolète).',
995
+ tableDuplicateName_summary_cantTell: 'La légende de ce tableau duplique son attribut summary.',
996
+ tableDuplicateName_hint_cantTell:
997
+ 'Retirez l’attribut summary redondant, ou faites en sorte qu’il apporte une information différente de la légende.',
998
+ metaViewportLarge_title: 'La balise meta viewport devrait permettre un zoom jusqu’à 500 %',
999
+ metaViewportLarge_description:
1000
+ 'Vérifie que <meta name="viewport"> ne définit pas user-scalable=no ni maximum-scale en dessous de 5 (500 %).',
1001
+ metaViewportLarge_summary_cantTell:
1002
+ 'Cette balise meta viewport restreint le zoom en dessous de l’objectif de bonne pratique de 500 %.',
1003
+ metaViewportLarge_hint_cantTell:
1004
+ 'Retirez user-scalable=no et augmentez maximum-scale à au moins 5 (500 %) si possible.',
1005
+ presentationRoleConflict_title:
1006
+ 'Un rôle de présentation ne doit pas entrer en conflit avec un attribut ARIA global ou la focalisabilité',
1007
+ presentationRoleConflict_description:
1008
+ 'Vérifie que role="presentation"/"none" (y compris le rôle presentation implicite d’un <img alt="">) n’est pas combiné avec un attribut ARIA global (aria-label, aria-hidden, aria-describedby, ...) ou avec la focalisabilité (tabindex/native).',
1009
+ presentationRoleConflict_summary_cantTell:
1010
+ 'Cet élément role="{{role}}" a aussi une condition conflictuelle ({{attrs}}), qui restaure son rôle implicite et annule l’intention présentationnelle.',
1011
+ presentationRoleConflict_hint_cantTell:
1012
+ 'Retirez le(s) attribut(s) de nommage conflictuel(s) et/ou la focalisabilité (tabindex/native) si l’élément doit rester présentationnel, ou retirez role="presentation"/"none" s’il doit être exposé aux technologies d’assistance.',
1013
+ region_title: 'Le contenu de la page devrait se trouver à l’intérieur d’un point de repère',
1014
+ region_description: 'Vérifie que le contenu sous <body> est contenu dans un point de repère.',
1015
+ region_summary_cantTell: 'Ce contenu n’est contenu dans aucun point de repère.',
1016
+ region_hint_cantTell:
1017
+ 'Déplacez ce contenu à l’intérieur d’un point de repère (main, nav, aside, une section nommée, etc.).',
1018
+ skipLink_title: 'Un lien d’évitement doit avoir une cible qui se résout et qui est utilisable',
1019
+ skipLink_description:
1020
+ 'Vérifie que le fragment href d’un lien « aller au... » se résout vers un élément réel et actuellement utilisable du document.',
1021
+ skipLink_summary_cantTell: 'La cible de ce lien d’évitement n’existe pas.',
1022
+ skipLink_hint_cantTell:
1023
+ 'Faites pointer le href du lien d’évitement vers un id qui existe dans le document, ou ajoutez l’élément cible manquant.',
1024
+ skipLink_summary_unusableTarget_cantTell:
1025
+ 'Ce lien d’évitement pointe vers une cible qui existe mais qui n’est pas actuellement utilisable.',
1026
+ skipLink_hint_unusableTarget_cantTell:
1027
+ 'Faites pointer ce lien d’évitement vers une cible exposée et utilisable comme destination de navigation.',
1028
+ autocompleteValid_title: 'L’attribut autocomplete doit être une valeur d’auto-remplissage valide',
1029
+ autocompleteValid_description:
1030
+ 'Vérifie qu’un attribut autocomplete non vide vaut « on »/« off » ou une liste de jetons d’auto-remplissage bien formée.',
1031
+ autocompleteValid_summary_fail:
1032
+ 'Cette valeur d’attribut autocomplete n’est pas une valeur d’auto-remplissage valide.',
1033
+ autocompleteValid_hint_fail:
1034
+ 'Utilisez « on »/« off », ou une liste de jetons d’auto-remplissage valide (ex. « shipping street-address », « cc-number »).',
1035
+ htmlXmlLangMismatch_title: 'lang et xml:lang ne doivent pas se contredire',
1036
+ htmlXmlLangMismatch_description:
1037
+ 'Vérifie que les attributs lang et xml:lang de l’élément <html> déclarent la même langue principale, lorsque les deux sont présents.',
1038
+ htmlXmlLangMismatch_summary_fail:
1039
+ 'Les attributs lang (« {{lang}} ») et xml:lang (« {{xmlLang}} ») déclarent des langues différentes.',
1040
+ htmlXmlLangMismatch_hint_fail:
1041
+ 'Faites en sorte que lang et xml:lang déclarent la même langue principale, ou retirez l’attribut obsolète xml:lang.',
1042
+ avoidInlineSpacing_title:
1043
+ 'Un style en ligne ne doit pas forcer l’espacement du texte avec !important',
1044
+ avoidInlineSpacing_description:
1045
+ 'Vérifie qu’un style en ligne ne définit pas line-height, letter-spacing, ou word-spacing avec !important, ce qui bloque les surcharges d’espacement de texte par l’utilisateur.',
1046
+ avoidInlineSpacing_summary_fail:
1047
+ 'Le style en ligne de cet élément force {{properties}} avec !important, bloquant les surcharges d’espacement de texte par l’utilisateur.',
1048
+ avoidInlineSpacing_hint_fail:
1049
+ 'Retirez !important de line-height/letter-spacing/word-spacing dans les styles en ligne afin que les utilisateurs puissent surcharger l’espacement du texte.',
1050
+ metaRefreshNoExceptions_title: 'La page ne doit utiliser aucun rafraîchissement meta (AAA)',
1051
+ metaRefreshNoExceptions_description:
1052
+ 'Vérifie que <meta http-equiv="refresh"> n’est présent en aucun cas, quel que soit le délai — la variante plus stricte, de niveau AAA, de la vérification de niveau A qui ne porte que sur les délais positifs.',
1053
+ metaRefreshNoExceptions_summary_fail:
1054
+ 'Cette page utilise un rafraîchissement meta, un changement de contexte automatique non initié par l’utilisateur.',
1055
+ metaRefreshNoExceptions_hint_fail:
1056
+ 'Retirez le rafraîchissement meta ; déclenchez la redirection/le rafraîchissement uniquement en réponse à une action de l’utilisateur.',
1057
+ validLang_title: 'L’attribut lang d’un élément doit être syntaxiquement valide',
1058
+ validLang_description:
1059
+ 'Vérifie que tout élément (autre que la racine <html>) ayant un attribut lang non vide utilise une étiquette de langue syntaxiquement valide.',
1060
+ validLang_summary_fail:
1061
+ 'Cette valeur d’attribut lang (« {{value}} ») n’est pas une étiquette de langue syntaxiquement valide.',
1062
+ validLang_hint_fail: 'Utilisez une étiquette de langue BCP47 valide (ex. « fr », « es-MX »).',
1063
+ linkInTextBlock_title:
1064
+ 'Les liens dans des blocs de texte doivent être distinguables du texte environnant sans se fier uniquement à la couleur',
1065
+ linkInTextBlock_description:
1066
+ 'Vérifie qu’un lien à l’intérieur d’un bloc de texte est visuellement distinguable du texte environnant par un soulignement, une différence de graisse/style de police, ou un contraste de couleur suffisant (>= 3:1) — pas seulement par la couleur.',
1067
+ linkInTextBlock_summary_fail:
1068
+ 'Ce lien dans un bloc de texte se distingue du texte environnant uniquement par la couleur.',
1069
+ linkInTextBlock_hint_fail:
1070
+ 'Ajoutez un soulignement, une différence de graisse/style de police, ou augmentez le contraste de couleur entre le lien et le texte environnant à au moins 3:1.',
1071
+ noAutoplayAudio_title:
1072
+ 'Un audio en lecture automatique devrait proposer un mécanisme de pause/arrêt ou de contrôle du volume',
1073
+ noAutoplayAudio_description:
1074
+ 'Signale les éléments <audio>/<video> qui se lancent automatiquement sans être coupés et sans attribut controls natif, pour une revue manuelle par rapport à l’exemption de 3 secondes de la WCAG 1.4.2.',
1075
+ noAutoplayAudio_summary_cantTell:
1076
+ 'Cet élément lit un audio automatiquement sans mécanisme natif de pause/arrêt ou de contrôle du volume.',
1077
+ noAutoplayAudio_hint_cantTell:
1078
+ 'Si ce clip dure plus de 3 secondes, ajoutez un attribut controls (ou un mécanisme personnalisé équivalent) afin que les utilisateurs puissent le mettre en pause/l’arrêter ou contrôler son volume indépendamment du volume du système.',
1079
+ videoCaption_title: 'Une vidéo préenregistrée devrait proposer une piste de sous-titres',
1080
+ videoCaption_description:
1081
+ 'Signale les éléments <video> sans enfant <track kind="captions"|"subtitles">, pour une revue manuelle visant à déterminer si la vidéo a une piste audio nécessitant des sous-titres.',
1082
+ videoCaption_summary_cantTell:
1083
+ 'Cette vidéo n’a aucune piste de sous-titres (captions ou subtitles).',
1084
+ videoCaption_hint_cantTell:
1085
+ 'Si cette vidéo a une piste audio porteuse d’information, ajoutez un <track kind="captions" src="..."> avec le contenu sous-titré.',
1086
+ scrollableRegionFocusable_title:
1087
+ 'Les régions défilantes sans contenu focalisable devraient être focalisables au clavier',
1088
+ scrollableRegionFocusable_description:
1089
+ 'Signale les éléments dont le CSS déclare overflow:auto/scroll, qui ne contiennent aucun descendant focalisable, et qui ne sont pas eux-mêmes focalisables au clavier, pour une revue manuelle visant à déterminer si leur contenu déborde réellement et nécessite un accès au défilement au clavier.',
1090
+ scrollableRegionFocusable_summary_cantTell:
1091
+ 'Cet élément déclare overflow:auto/scroll, n’a aucun descendant focalisable, et n’est pas lui-même focalisable au clavier.',
1092
+ scrollableRegionFocusable_hint_cantTell:
1093
+ 'Si le contenu de cette région déborde réellement, ajoutez tabindex="0" (et une étiquette adaptée) afin que les utilisateurs du clavier puissent la focaliser et faire défiler avec les flèches.',
1094
+ identicalLinksSamePurpose_title:
1095
+ 'Les liens partageant le même nom accessible devraient mener à la même destination',
1096
+ identicalLinksSamePurpose_description:
1097
+ 'Signale les groupes de liens qui partagent le même nom accessible mais mènent à plus d’une destination distincte, pour une revue manuelle visant à déterminer s’ils servent le même objectif.',
1098
+ identicalLinksSamePurpose_summary_cantTell:
1099
+ 'Ce lien partage un nom accessible avec d’autres liens de la page qui mènent à une destination différente.',
1100
+ identicalLinksSamePurpose_hint_cantTell:
1101
+ 'Assurez-vous que les liens ayant le même texte servent le même objectif, ou rendez le texte du lien suffisamment distinct pour décrire chaque destination.',
1102
+ ariaBrailleEquivalent_title:
1103
+ 'aria-braillelabel/aria-brailleroledescription doivent avoir un équivalent non braille',
1104
+ ariaBrailleEquivalent_description:
1105
+ 'Vérifie que les éléments utilisant aria-braillelabel ont aussi un nom accessible ordinaire, et que ceux utilisant aria-brailleroledescription ont aussi aria-roledescription.',
1106
+ ariaBrailleEquivalent_summary_fail:
1107
+ 'Cet élément a {{attr}} mais pas {{requires}}, son équivalent non braille.',
1108
+ ariaBrailleEquivalent_hint_fail:
1109
+ '{{attr}} est un complément spécifique au braille, pas un remplacement — fournissez aussi {{requires}}.',
1110
+ ariaConditionalAttr_title:
1111
+ 'aria-errormessage exige que aria-invalid soit défini à une valeur autre que false',
1112
+ ariaConditionalAttr_description:
1113
+ 'Vérifie que les éléments ayant aria-errormessage ont aussi aria-invalid défini à « true », « grammar », ou « spelling » — sinon le message d’erreur est retiré de l’arbre d’accessibilité.',
1114
+ ariaConditionalAttr_summary_fail:
1115
+ 'Cet élément a aria-errormessage mais aria-invalid est absent ou « false », donc le message d’erreur n’est pas exposé.',
1116
+ ariaConditionalAttr_hint_fail:
1117
+ 'Définissez aria-invalid à « true » (ou « grammar »/« spelling ») chaque fois que aria-errormessage doit être exposé aux technologies d’assistance.',
1118
+ ariaCheckedStateMismatch_title:
1119
+ 'L’aria-checked d’une case à cocher/d’un bouton radio natif devrait correspondre à son état réel',
1120
+ ariaCheckedStateMismatch_description:
1121
+ 'Signale un <input type="checkbox">/<input type="radio"> natif dont la valeur explicite d’aria-checked ne correspond pas à son état réel (coché/indéterminé), pour une revue manuelle.',
1122
+ ariaCheckedStateMismatch_summary_cantTell:
1123
+ 'La valeur d’aria-checked de cet élément ne correspond pas à son état réel (coché/indéterminé).',
1124
+ ariaCheckedStateMismatch_hint_cantTell:
1125
+ 'Définissez aria-checked pour qu’il corresponde à l’état réel de l’élément, ou retirez-le — une case à cocher/un bouton radio natif expose déjà cet état sans lui.',
1126
+ cssOrientationLock_title: 'Le CSS ne doit pas verrouiller la page à une seule orientation',
1127
+ cssOrientationLock_description:
1128
+ 'Vérifie qu’aucune règle @media (orientation: portrait|landscape) ne définit un transform: rotate(...) sur la page, une technique connue pour contourner l’orientation de l’appareil.',
1129
+ cssOrientationLock_summary_fail:
1130
+ 'Une media query « {{mediaText}} » fait pivoter « {{selectorText}} », verrouillant la page à une seule orientation.',
1131
+ cssOrientationLock_hint_fail:
1132
+ 'Retirez la transformation rotate() de la media query d’orientation ; laissez la page répondre naturellement à l’orientation de l’appareil au lieu de forcer une rotation visuelle.',
1133
+ ariaText_title: 'Les éléments role="text" ne devraient avoir aucun descendant focalisable',
1134
+ ariaText_description:
1135
+ 'Vérifie que les éléments ayant role="text" ne contiennent aucun descendant focalisable (lien, bouton, contrôle de formulaire, tabindex, iframe, ou contenteditable).',
1136
+ ariaText_summary_cantTell: 'Cet élément role="text" contient un descendant focalisable.',
1137
+ ariaText_hint_cantTell:
1138
+ 'Retirez role="text" (ou retirez le descendant focalisable) — une région de « texte brut » ne devrait pas contenir de contenu focalisable.',
1139
+ focusOrderSemantics_title:
1140
+ 'Les éléments ajoutés à l’ordre de tabulation devraient avoir une sémantique interactive',
1141
+ focusOrderSemantics_description:
1142
+ 'Signale les éléments ayant tabindex >= 0 dont le rôle explicite est un rôle structurel/documentaire non interactif (ex. heading, list, region, presentation), pour une revue manuelle.',
1143
+ focusOrderSemantics_summary_cantTell:
1144
+ 'Cet élément est dans l’ordre de tabulation (tabindex="{{tabindex}}") mais a un rôle non interactif (« {{role}} »).',
1145
+ focusOrderSemantics_hint_cantTell:
1146
+ 'Retirez tabindex si cet élément n’est pas censé être interactif, ou utilisez un rôle interactif correspondant à son comportement réel.',
1147
+ pAsHeading_title:
1148
+ 'Un <p> stylé pour ressembler à un titre devrait probablement être un véritable titre',
1149
+ pAsHeading_description:
1150
+ 'Signale les éléments <p> courts dont tout le texte est en gras et affiché à >= 18px, pour une revue manuelle visant à déterminer si un véritable élément de titre devrait être utilisé à la place.',
1151
+ pAsHeading_summary_cantTell:
1152
+ 'Ce paragraphe est entièrement en gras et affiché à une taille évoquant un titre.',
1153
+ pAsHeading_hint_cantTell:
1154
+ 'Si ce texte introduit une nouvelle section, utilisez un véritable élément de titre (<h1>-<h6> ou role="heading") plutôt que de styler un paragraphe pour qu’il y ressemble.',
1155
+ tableFakeCaption_title:
1156
+ 'La première ligne d’un tableau ne devrait pas tenir lieu de véritable <caption>',
1157
+ tableFakeCaption_description:
1158
+ 'Signale les tableaux sans <caption> dont la première ligne a une seule cellule non vide alors que les autres lignes ont plusieurs cellules, pour une revue manuelle visant à déterminer si cette cellule fait office de légende factice.',
1159
+ tableFakeCaption_summary_cantTell:
1160
+ 'Ce tableau n’a pas de <caption>, mais sa première ligne est une cellule unique placée au-dessus de lignes à plusieurs cellules — elle fait peut-être office de légende factice.',
1161
+ tableFakeCaption_hint_cantTell:
1162
+ 'Si cette cellule est censée décrire le tableau, utilisez un véritable élément <caption> plutôt qu’une cellule isolée en première ligne.',
1163
+ tdHasHeader_title: 'Les cellules de données des grands tableaux doivent avoir un en-tête associé',
1164
+ tdHasHeader_description:
1165
+ 'Vérifie que chaque <td> d’un tableau grand et simple (sans colspan/rowspan) a un en-tête associé — via un attribut headers, un <th> de colonne implicite au-dessus, ou un <th> de ligne implicite à sa gauche.',
1166
+ tdHasHeader_summary_fail:
1167
+ 'Cette cellule de données n’a pas d’en-tête associé (pas d’attribut headers, pas de <th> de colonne au-dessus, pas de <th> de ligne à gauche).',
1168
+ tdHasHeader_hint_fail:
1169
+ 'Ajoutez un attribut headers référençant le(s) id du/des <th> pertinent(s), ou restructurez le tableau afin que cette cellule ait un en-tête de ligne/colonne implicite.',
1170
+ mouseOnlyEventHandlers_title:
1171
+ 'Les gestionnaires d’événements en ligne réservés au pointeur devraient avoir un équivalent accessible au clavier',
1172
+ mouseOnlyEventHandlers_description:
1173
+ 'Signale les éléments ayant un gestionnaire d’événement en ligne réservé au pointeur (onmouseover, onmouseout, onmousedown, onmouseup, ondblclick, onmousemove, onmouseenter, onmouseleave) sans équivalent accessible au clavier (onkeydown/onkeyup/onkeypress/onfocus/onblur), pour une revue manuelle.',
1174
+ mouseOnlyEventHandlers_summary_cantTell:
1175
+ 'Cet élément a {{attrs}} mais aucun gestionnaire équivalent accessible au clavier.',
1176
+ mouseOnlyEventHandlers_hint_cantTell:
1177
+ 'Ajoutez onkeydown/onkeyup/onkeypress (ou onfocus/onblur pour un comportement déclenché au survol) afin que cette fonctionnalité soit aussi accessible au clavier.',
1178
+ linkNameQuality_title: 'Le texte des liens devrait être descriptif, pas générique',
1179
+ linkNameQuality_description:
1180
+ 'Signale les liens dont le nom accessible complet est une formule connue comme non descriptive (ex. « cliquez ici », « en savoir plus », « plus »), pour une revue manuelle visant à déterminer si l’objet du lien est clair sans contexte supplémentaire.',
1181
+ linkNameQuality_summary_cantTell:
1182
+ 'Le nom accessible de ce lien (« {{name}} ») est une formule générique et non descriptive.',
1183
+ linkNameQuality_hint_cantTell:
1184
+ 'Faites en sorte que le texte du lien lui-même décrive sa destination/son objet (ex. « Télécharger le guide tarifaire 2026 » plutôt que « Télécharger »), ou confirmez que le contexte environnant rend déjà l’objet clair.'
1185
+ };