😎

eslint-plugin-jsx-a11yのimg-redundant-altが日本語に対応していないことについて

2024/01/23に公開

はじめに

JSXにおけるアクセシビリティ観点のLintルールを持つESLintプラグインにeslint-plugin-jsx-a11yがある。
直近のメンテナンスがあまり活発ではない印象があるものの、主にReactアプリケーションのアクセシビリティ対応を静的解析でチェックするために広く利用されているプラグインだと思う。

このESLintプラグインの推奨設定であるrecommendedにはimg-redundant-altというルールが含まれているけど、このルールは現状日本語のようなマルチバイトの言語のJSXには対応していないと考えられるので、そのメモ。

img-redundant-alt

img-redundant-altは、<img />要素のalt属性において「image」や「photo」といった単語を使用禁止にするルール。
スクリーンリーダーのような支援技術はimg要素自体を「image」と読み上げるので、altの内容が「image」を含んでいると複数回同じことを繰り返し読み上げてしまうということがルールとして設けられている背景になる。

Enforce img alt attribute does not contain the word image, picture, or photo. Screenreaders already announce img elements as an image. There is no need to use words such as image, photo, and/or picture.

https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/img-redundant-alt.md

ソースコードを眺めると、recommendedでは、errorとして設定されていて、
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/1adec3517fc2c9797212ca4d38858deed917e7be/src/index.js#L97

img-redundant-altルールはソースコードにも書かれている通り、imagephotopictureのいずれかにマッチするaltの値かどうかをチェックする。
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/1adec3517fc2c9797212ca4d38858deed917e7be/src/rules/img-redundant-alt.js#L32
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/1adec3517fc2c9797212ca4d38858deed917e7be/src/rules/img-redundant-alt.js#L15-L19

従って日本語のReactアプリケーションなどでこのプラグインをrecommendedの設定をそのまま適用しても、img-redundant-altに関しては日本語へのチェックが実施されない、ということになると思う。
<img />要素を支援技術がどのように読み上げるかは正確に把握できていないけど、lang="ja"のHTMLにおいてVoiceOverでは「イメージ」と読み上げるので「イメージ 〇〇〇のイメージ」のような読み上げが発生し得る。

wordsオプション

日本語に限らずだけど、imagephotopicture以外の単語でチェックしたい場合には、ルールのオプションでwordsを指定することで任意の単語をマッチ対象に追加できる。

https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/1adec3517fc2c9797212ca4d38858deed917e7be/src/rules/img-redundant-alt.js#L63

そのためwordsオプションを指定すれば解決するように見える。

'jsx-a11y/img-redundant-alt': ['error', {
  words: ['イメージ'],
}],

が、実際にはwordsオプションを指定しても問題は解決しない。
wordsオプションを指定してもマルチバイトの文字ではルールが機能しないのは、以下の正規表現部分に原因がある。

https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/1adec3517fc2c9797212ca4d38858deed917e7be/src/rules/img-redundant-alt.js#L66

上記の正規表現において\bが使用されているけども、これは[A-Za-z0-9_]に相当するものなので、アルファベットや数字の単語境界をチェックすることには適しているものの、マルチバイト文字には対応していない。

単語境界の検査 \b は、その位置の一方が \w であり、反対側が \w でないかをチェックします。

しかし、\w はラテン文字 a-z (あるいは数字またはアンダーススコア)を意味するので、キリル文字や象形文字など、他の文字では機能しません。

https://ja.javascript.info/regexp-boundary

単語境界をチェックする必要がないようにテストケースからは感じたので、正気表現でチェックしない形の修正Pull Requestを送ってmergeはされたものの、npmパッケージとしてまだリリースされていない。
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/970

このPull Requestを含んだバージョンがリリースされれば、それを利用することでwordsオプションの指定内容に応じてマルチバイトでも適切にルールが機能すると思う。

まとめ

プロジェクトにおいて適用している全てのLintルールを把握しておくことは、労力を考えるとあまり現実的ではないと思う。そのためプラグイン側も推奨設定をextendsに記載して有効化できるようにrecommendedを提供しているはずだけど、ルール自体が機能していない状況も稀にあることを意識しておくと良いかもしれない。

参考

GitHubで編集を提案

Discussion