@surea11y/core 1.0.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 (164) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +145 -0
  4. package/bin/core.js +244 -0
  5. package/docs/BINDING_AUTHORS_GUIDE.md +41 -0
  6. package/docs/CLI.md +49 -0
  7. package/docs/ENGINE_OPTIONS.md +155 -0
  8. package/docs/I18N.md +47 -0
  9. package/docs/INTEGRATION.md +156 -0
  10. package/docs/LIMITATIONS.md +31 -0
  11. package/docs/OUTPUT_SCHEMA.md +237 -0
  12. package/docs/POLICY.md +71 -0
  13. package/docs/RULE_AUTHORING.md +375 -0
  14. package/docs/RULE_CATALOG.md +180 -0
  15. package/docs/RULE_TAXONOMY.md +145 -0
  16. package/docs/TROUBLESHOOTING.md +48 -0
  17. package/docs/WCAG_CONFORMANCE.md +49 -0
  18. package/package.json +60 -0
  19. package/src/catalogs/composites.wcag.js +490 -0
  20. package/src/checks/automatic/area-alt-present.js +225 -0
  21. package/src/checks/automatic/aria-allowed-attr.js +206 -0
  22. package/src/checks/automatic/aria-allowed-role.js +102 -0
  23. package/src/checks/automatic/aria-braille-equivalent.js +139 -0
  24. package/src/checks/automatic/aria-conditional-attr.js +110 -0
  25. package/src/checks/automatic/aria-deprecated-role.js +106 -0
  26. package/src/checks/automatic/aria-hidden-body.js +87 -0
  27. package/src/checks/automatic/aria-hidden-focus.js +480 -0
  28. package/src/checks/automatic/aria-prohibited-attr.js +156 -0
  29. package/src/checks/automatic/aria-prohibited-children.js +265 -0
  30. package/src/checks/automatic/aria-required-attr.js +154 -0
  31. package/src/checks/automatic/aria-required-children.js +274 -0
  32. package/src/checks/automatic/aria-required-parent.js +222 -0
  33. package/src/checks/automatic/aria-role-name-present.js +201 -0
  34. package/src/checks/automatic/aria-roles-valid.js +110 -0
  35. package/src/checks/automatic/aria-valid-attr-value.js +123 -0
  36. package/src/checks/automatic/aria-valid-attr.js +109 -0
  37. package/src/checks/automatic/autocomplete-valid.js +134 -0
  38. package/src/checks/automatic/avoid-inline-spacing.js +107 -0
  39. package/src/checks/automatic/binary-control-name-present.js +294 -0
  40. package/src/checks/automatic/button-name-present.js +146 -0
  41. package/src/checks/automatic/bypass-blocks-present.js +162 -0
  42. package/src/checks/automatic/canvas-text-alternative-present.js +140 -0
  43. package/src/checks/automatic/combobox-name-present.js +267 -0
  44. package/src/checks/automatic/contrast-computable.js +378 -0
  45. package/src/checks/automatic/contrast-enhanced.js +517 -0
  46. package/src/checks/automatic/contrast-minimum.js +512 -0
  47. package/src/checks/automatic/css-orientation-lock.js +206 -0
  48. package/src/checks/automatic/definition-list-children-valid.js +148 -0
  49. package/src/checks/automatic/deprecated-elements-not-used.js +91 -0
  50. package/src/checks/automatic/dialog-name-present.js +209 -0
  51. package/src/checks/automatic/dlitem-parent-valid.js +100 -0
  52. package/src/checks/automatic/duplicate-id-aria.js +126 -0
  53. package/src/checks/automatic/embed-text-alternative-present.js +190 -0
  54. package/src/checks/automatic/form-control-programmatic-label-present.js +409 -0
  55. package/src/checks/automatic/form-control-single-label.js +117 -0
  56. package/src/checks/automatic/html-xml-lang-mismatch.js +91 -0
  57. package/src/checks/automatic/iframe-focusable-content.js +141 -0
  58. package/src/checks/automatic/iframe-name-present.js +102 -0
  59. package/src/checks/automatic/iframe-title-unique.js +107 -0
  60. package/src/checks/automatic/img-alt-present.js +223 -0
  61. package/src/checks/automatic/input-image-alt-present.js +155 -0
  62. package/src/checks/automatic/label-in-name.js +326 -0
  63. package/src/checks/automatic/language-page-present.js +159 -0
  64. package/src/checks/automatic/link-in-text-block.js +218 -0
  65. package/src/checks/automatic/link-name-present.js +114 -0
  66. package/src/checks/automatic/list-children-valid.js +152 -0
  67. package/src/checks/automatic/listbox-name-present.js +236 -0
  68. package/src/checks/automatic/listitem-parent-valid.js +118 -0
  69. package/src/checks/automatic/menuitem-name-present.js +201 -0
  70. package/src/checks/automatic/meta-refresh-no-exceptions.js +105 -0
  71. package/src/checks/automatic/meta-refresh-timing-absent.js +107 -0
  72. package/src/checks/automatic/meta-viewport-zoom-enabled.js +118 -0
  73. package/src/checks/automatic/meter-name-present.js +160 -0
  74. package/src/checks/automatic/nested-interactive-controls-absent.js +135 -0
  75. package/src/checks/automatic/object-text-alternative-present.js +193 -0
  76. package/src/checks/automatic/option-name-present.js +157 -0
  77. package/src/checks/automatic/page-title-present.js +86 -0
  78. package/src/checks/automatic/progressbar-name-present.js +165 -0
  79. package/src/checks/automatic/role-img-alt-present.js +206 -0
  80. package/src/checks/automatic/searchbox-name-present.js +236 -0
  81. package/src/checks/automatic/server-side-image-map-absent.js +88 -0
  82. package/src/checks/automatic/slider-name-present.js +276 -0
  83. package/src/checks/automatic/spinbutton-name-present.js +236 -0
  84. package/src/checks/automatic/summary-name-present.js +153 -0
  85. package/src/checks/automatic/svg-image-text-alternative-present.js +220 -0
  86. package/src/checks/automatic/svg-text-alternative-present.js +298 -0
  87. package/src/checks/automatic/tab-name-present.js +200 -0
  88. package/src/checks/automatic/table-headers-attr-valid.js +122 -0
  89. package/src/checks/automatic/table-th-has-data-cells.js +117 -0
  90. package/src/checks/automatic/target-size-minimum.js +605 -0
  91. package/src/checks/automatic/td-has-header.js +151 -0
  92. package/src/checks/automatic/textbox-name-present.js +236 -0
  93. package/src/checks/automatic/tooltip-name-present.js +158 -0
  94. package/src/checks/automatic/treeitem-name-present.js +157 -0
  95. package/src/checks/automatic/valid-lang.js +100 -0
  96. package/src/checks/automatic/video-poster-text-alternative-present.js +193 -0
  97. package/src/checks/manual/accesskeys-manual.js +93 -0
  98. package/src/checks/manual/area-alt-decorative-manual.js +247 -0
  99. package/src/checks/manual/area-alt-quality-manual.js +204 -0
  100. package/src/checks/manual/aria-checked-state-mismatch-manual.js +141 -0
  101. package/src/checks/manual/aria-text-manual.js +109 -0
  102. package/src/checks/manual/canvas-text-alternative-quality-manual.js +170 -0
  103. package/src/checks/manual/css-hidden-focus.js +259 -0
  104. package/src/checks/manual/embed-text-alternative-quality-manual.js +204 -0
  105. package/src/checks/manual/empty-heading-manual.js +182 -0
  106. package/src/checks/manual/empty-table-header-manual.js +163 -0
  107. package/src/checks/manual/focus-order-semantics-manual.js +117 -0
  108. package/src/checks/manual/form-control-programmatic-label-quality-manual.js +291 -0
  109. package/src/checks/manual/heading-order-manual.js +130 -0
  110. package/src/checks/manual/identical-links-same-purpose-manual.js +142 -0
  111. package/src/checks/manual/image-redundant-alt-manual.js +118 -0
  112. package/src/checks/manual/img-alt-decorative-manual.js +148 -0
  113. package/src/checks/manual/img-alt-quality-manual.js +182 -0
  114. package/src/checks/manual/input-image-alt-decorative-manual.js +144 -0
  115. package/src/checks/manual/input-image-alt-quality-manual.js +144 -0
  116. package/src/checks/manual/label-title-only-manual.js +115 -0
  117. package/src/checks/manual/landmark-banner-is-top-level-manual.js +180 -0
  118. package/src/checks/manual/landmark-contentinfo-is-top-level-manual.js +169 -0
  119. package/src/checks/manual/landmark-main-is-top-level-manual.js +167 -0
  120. package/src/checks/manual/landmark-no-duplicate-banner-manual.js +177 -0
  121. package/src/checks/manual/landmark-no-duplicate-contentinfo-manual.js +169 -0
  122. package/src/checks/manual/landmark-no-duplicate-main-manual.js +132 -0
  123. package/src/checks/manual/landmark-one-main-manual.js +151 -0
  124. package/src/checks/manual/landmark-unique-manual.js +252 -0
  125. package/src/checks/manual/link-name-quality-manual.js +143 -0
  126. package/src/checks/manual/media-transcript-present-manual.js +373 -0
  127. package/src/checks/manual/meta-viewport-large-manual.js +119 -0
  128. package/src/checks/manual/mouse-only-event-handlers-manual.js +134 -0
  129. package/src/checks/manual/no-autoplay-audio-manual.js +116 -0
  130. package/src/checks/manual/object-text-alternative-quality-manual.js +194 -0
  131. package/src/checks/manual/p-as-heading-manual.js +163 -0
  132. package/src/checks/manual/page-has-heading-one-manual.js +110 -0
  133. package/src/checks/manual/page-title-patterns-manual.js +262 -0
  134. package/src/checks/manual/presentation-role-conflict-manual.js +159 -0
  135. package/src/checks/manual/region-manual.js +183 -0
  136. package/src/checks/manual/scope-attr-valid-manual.js +93 -0
  137. package/src/checks/manual/scrollable-region-focusable-manual.js +168 -0
  138. package/src/checks/manual/skip-link-manual.js +150 -0
  139. package/src/checks/manual/svg-text-alternative-quality-manual.js +209 -0
  140. package/src/checks/manual/tabindex-manual.js +94 -0
  141. package/src/checks/manual/table-duplicate-name-manual.js +99 -0
  142. package/src/checks/manual/table-fake-caption-manual.js +122 -0
  143. package/src/checks/manual/video-caption-manual.js +118 -0
  144. package/src/checks/manual-review.js +95 -0
  145. package/src/checks/rules-and-tags.full.csv +19 -0
  146. package/src/checks/rules-and-tags.full.json +259 -0
  147. package/src/core/aria-helpers.js +906 -0
  148. package/src/core/contrast-helpers.js +1147 -0
  149. package/src/core/dom-helpers.js +4085 -0
  150. package/src/core/dom-runner.js +627 -0
  151. package/src/core/frame-messaging.js +210 -0
  152. package/src/core/frame-scan.js +178 -0
  153. package/src/core/rollup-composites.js +135 -0
  154. package/src/core/rule-meta.js +140 -0
  155. package/src/core.js +79055 -0
  156. package/src/coverage/wcag-facets.js +1079 -0
  157. package/src/coverage/wcag-version-map.js +84 -0
  158. package/src/i18n/en.js +919 -0
  159. package/src/i18n/fr.js +527 -0
  160. package/src/index.js +4 -0
  161. package/src/policy/contracts.js +18 -0
  162. package/src/policy/resolvePolicy.js +55 -0
  163. package/src/policy/schemas/engine-options.schema.json +103 -0
  164. package/src/policy/schemas/policy-contract.schema.json +40 -0
package/src/i18n/fr.js ADDED
@@ -0,0 +1,527 @@
1
+ 'use strict';
2
+
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.",
206
+
207
+ // --- 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).',
213
+
214
+ "contrastComputable_cantTell_generic":
215
+ 'Le contraste peut ne pas être calculable ({{reasonCode}}).',
216
+
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}}).',
219
+
220
+ "contrastComputable_cantTell_bgImage":
221
+ "Le contraste ne peut pas être calculé car l’arrière-plan utilise une image ({{blockerProperty}}={{blockerValue}}).",
222
+
223
+ "contrastComputable_cantTell_bgGradient":
224
+ "Le contraste ne peut pas être calculé car l’arrière-plan utilise un dégradé ({{blockerProperty}}={{blockerValue}}).",
225
+
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}}).",
228
+
229
+ "contrastComputable_cantTell_mixBlendMode":
230
+ 'Le contraste n’est pas calculable car mix-blend-mode est utilisé ({{blockerProperty}}={{blockerValue}}).',
231
+
232
+ "contrastComputable_cantTell_filter":
233
+ "Le contraste ne peut pas être calculé car la propriété filter est utilisée ({{blockerProperty}}={{blockerValue}}).",
234
+
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}}).',
237
+
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.',
240
+
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}}).',
243
+
244
+ "contrastComputable_cantTell_backdropFilter":
245
+ "Le contraste ne peut pas être calculé car la propriété backdrop-filter est utilisée ({{blockerProperty}}={{blockerValue}}).",
246
+
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}}).",
249
+
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.',
254
+
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}}).",
257
+
258
+ "contrastMinimum_pass_allAboveThreshold":
259
+ 'Tout le texte calculable respecte le contraste minimum (AA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
260
+
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.',
263
+
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}}).',
266
+
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.',
271
+
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.",
275
+
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.",
280
+
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}}.",
283
+
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.",
288
+
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}}).",
291
+
292
+ "contrastEnhanced_pass_allAboveThreshold":
293
+ 'Tout le texte calculable respecte le contraste renforcé (AAA). Nœuds de texte éligibles : {{eligibleTextCount}}. Calculables : {{computableTextCount}}.',
294
+
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.',
297
+
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}}).',
300
+
301
+ // --- 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.",
304
+
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).",
309
+
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}}.",
312
+
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.",
317
+
318
+ // --- 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).",
321
+
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.",
326
+
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}}.",
329
+
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}}).",
338
+
339
+ "roleImg_textAlternativePresent_title":
340
+ 'Les éléments avec role="img" doivent avoir une alternative textuelle accessible',
341
+
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.',
344
+
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.',
348
+
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.',
351
+
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.",
445
+
446
+ /* =========================
447
+ * Résumé des règles composites
448
+ * ========================= */
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
+ }
package/src/index.js ADDED
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+
3
+ // surea11y public API: export the generated core surface verbatim
4
+ module.exports = require('./core');
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ POLICY_CONTRACTS: {
5
+ a11y: {
6
+ id: 'a11y',
7
+ allowedOutcomes: ['fail', 'pass', 'cantTell', 'notApplicable'],
8
+ allowedConfidence: ['high', 'medium', 'low'],
9
+ coerceManualFailToCantTell: true
10
+ },
11
+ generic: {
12
+ id: 'generic',
13
+ allowedOutcomes: ['fail', 'pass', 'cantTell', 'notApplicable'],
14
+ allowedConfidence: ['high', 'medium', 'low'],
15
+ coerceManualFailToCantTell: false
16
+ }
17
+ }
18
+ };
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ function resolvePolicy(POLICY_CONTRACTS, engineOptions) {
4
+ function normalizePolicyContract(POLICY_CONTRACTS, contract, fallbackId) {
5
+ const fallback = POLICY_CONTRACTS[fallbackId] || POLICY_CONTRACTS.a11y;
6
+ if (typeof contract === 'string') return POLICY_CONTRACTS[contract] || fallback;
7
+
8
+ if (contract && typeof contract === 'object') {
9
+ const allowedOutcomes = Array.isArray(contract.allowedOutcomes)
10
+ ? contract.allowedOutcomes.slice()
11
+ : fallback.allowedOutcomes.slice();
12
+
13
+ const allowedConfidence = Array.isArray(contract.allowedConfidence)
14
+ ? contract.allowedConfidence.slice()
15
+ : fallback.allowedConfidence.slice();
16
+
17
+ return {
18
+ id: (typeof contract.id === 'string' && contract.id.trim())
19
+ ? contract.id.trim()
20
+ : (fallback.id || fallbackId || 'custom'),
21
+ allowedOutcomes,
22
+ allowedConfidence,
23
+ coerceManualFailToCantTell:
24
+ typeof contract.coerceManualFailToCantTell === 'boolean'
25
+ ? contract.coerceManualFailToCantTell
26
+ : !!fallback.coerceManualFailToCantTell
27
+ };
28
+ }
29
+
30
+ return fallback;
31
+ }
32
+
33
+ function normalizePolicyOverrides(policy) {
34
+ const p = (policy && typeof policy === 'object') ? policy : {};
35
+ return {
36
+ allowedOutcomes: Array.isArray(p.allowedOutcomes) ? p.allowedOutcomes.slice() : null,
37
+ allowedConfidence: Array.isArray(p.allowedConfidence) ? p.allowedConfidence.slice() : null,
38
+ coerceManualFailToCantTell: typeof p.coerceManualFailToCantTell === 'boolean' ? p.coerceManualFailToCantTell : null
39
+ };
40
+ }
41
+
42
+ const opts = (engineOptions && typeof engineOptions === 'object') ? engineOptions : {};
43
+ const contract = normalizePolicyContract(POLICY_CONTRACTS, opts.policyContract, 'a11y');
44
+ const ov = normalizePolicyOverrides(opts.policy);
45
+
46
+ return {
47
+ contractId: contract.id,
48
+ allowedOutcomes: ov.allowedOutcomes || contract.allowedOutcomes.slice(),
49
+ allowedConfidence: ov.allowedConfidence || contract.allowedConfidence.slice(),
50
+ coerceManualFailToCantTell:
51
+ ov.coerceManualFailToCantTell !== null ? ov.coerceManualFailToCantTell : !!contract.coerceManualFailToCantTell
52
+ };
53
+ }
54
+
55
+ module.exports = { resolvePolicy };