Accessibility

a11y/lang-valid

Every lang value is a valid BCP 47 language tag ("en", "en-GB", "pl"), never "en_US" or a language name.

seriousstaticWCAG 3.1.1, 3.1.2 · AAfe-a11y-core

Why

Screen readers pick the voice and pronunciation rules from lang. An invalid value is ignored, so Polish text may be read with English rules and become unintelligible. Locale codes from other systems (en_US with an underscore) are the usual cause.

Fix

Use a BCP 47 tag: language, then optional script and region, joined by hyphens (en, en-GB, pt-BR, zh-Hant). When the value comes from the app's locale, convert underscores to hyphens once (locale.replace('_', '-')) or use new Intl.Locale(locale).toString().

Examples

<!-- bad -->
<html lang="en_US"> … <p lang="polish">Dzień dobry</p>
<!-- good -->
<html lang="en-US"> … <p lang="pl">Dzień dobry</p>

Sources

Facts

Id
a11y/lang-valid
Severity
serious
Check
static checked in the source by audit
Applies to
html angular vue svelte astro jsx
WCAG 2.2
3.1.1, 3.1.2, level AA
Same problem in
axe-core html-lang-valid, axe-core valid-lang, Lighthouse html-lang-valid, Lighthouse valid-lang
Taught by the skill
fe-a11y-core Accessibility, WCAG 2.2 map
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain a11y/lang-valid