Search topics
Page language set wrong, so screen readers mispronounce it
A shared layout hardcodes lang="en", so a Spanish page is read aloud with English pronunciation rules, and a quote in another language is read in the page's voice.
lang="en" The problem
Screen reader and braille users hear a page read with the wrong language's pronunciation, which can make it hard or impossible to understand.
An outdoor shop has an English site and a Spanish one. A screen reader user opens the Spanish product page for a pair of hiking boots. The heading says "Botas de montaña", but the screen reader reads it as "BOH-tass dee mon-TANNA", with English vowels and stresses, and the description that follows is no easier. They know Spanish well; they cannot follow it read like this. Further down, a customer review is quoted in English. Once the page is fixed to Spanish, that quote would be read by the Spanish voice instead, unless it is marked too.
The site's shared layout starts with <html lang="en">, written once when the site was English only. When the Spanish version was added, the translation library swapped the words on each page, but nothing touched the lang attribute. Screen readers, read-aloud tools and braille translators use that attribute to pick a voice and pronunciation rules, so they read every Spanish page as English. WCAG 3.1.1 asks that the default human language of each page can be programmatically determined; here it can be determined, and it is wrong, which fails the same way as missing. WCAG 3.1.2 asks the same for each passage in a language other than the page's, such as the English review. Proper names, technical terms and words that have become part of the surrounding language are exempt.
The failure follows the translation: the English pages are fine, so a team that tests only in its own language never hears it. It also reaches beyond assistive technology. Browsers use lang to offer translation, choose fonts and hyphenation, and apply quotation marks, so a Spanish page marked as English may be offered a translation "from English" and hyphenate wrongly.
3 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Without vision Screen readers choose a voice and pronunciation rules from lang. With the wrong one, Spanish words are read as if they were English, and braille displays can apply the wrong contractions.
- Limited language, cognitive and learning abilities People who listen to text with read-aloud tools to help them read hear garbled speech, and the support they rely on stops working.
- Limited vision People who use a screen reader alongside magnification, or browser read-aloud, hear the same wrong pronunciation.
axe's html-has-lang and html-lang-valid check that the attribute exists and that its value is a real language tag. lang="en" on a Spanish page passes both, so the most common form of this failure, the wrong language rather than a missing one, goes unreported. A tool would have to detect the language of the text and compare it, and the usual page checks do not. No tool tells whether a quote, a review or a product name is in another language and needs its own lang, or whether it is a name that should be left alone. A coding assistant asked to "add a lang attribute" often writes lang="en" into the shared layout, which fixes the scan and keeps the failure on every translated page. Listen to each language version, or at least compare its lang with its text.
Try it
Listen to the Spanish product page.
Press Listen on each part to hear it with the voice its lang picks, if your device has one; the panel shows the voice and how it sounds. Switch language and listen again.
Broken Can you fix this?
Botas de montaña
Impermeables y ligeras, para todo el año.
Kept me dry for three days of rain.
Press Listen on a part of the page.
Set by: <html lang="en">
A recreated demo. The broken version is intentionally inaccessible.
The fix
Set the html lang from the page's actual language, and mark each passage in another language with its own lang.
- 1Every page's html element has a valid lang that matches its main content.
- 2When the language changes without a page load, the html lang changes with it.
- 3A passage in another language carries its own lang.
html
<!-- app.html, the shared layout --><html lang="en">html
<!-- the Spanish product page, words from the translation file --><h1>Botas de montaña</h1><p>Impermeables y ligeras, para todo el año.</p><blockquote>Kept me dry for three days of rain.</blockquote>The template sets lang from the page's locale
html
<!-- app.html, rendered on the server for each request --><html lang="{locale}"> <!-- "es" on /es/ pages, "en" on /en/ -->html
<h1>Botas de montaña</h1><p>Impermeables y ligeras, para todo el año.</p><blockquote lang="en">Kept me dry for three days of rain.</blockquote>The Spanish page says it is English, so it is read with English pronunciation. The English review has no lang of its own, so it will take whatever the page says.
Each page arrives with the language it is written in, before any script runs. The review keeps English pronunciation because it says so itself, whatever the page around it is set to.
Both pass 3.1.1 and 3.1.2. When each language has its own URL and the server renders the page, set lang in the template from the locale in the URL: there is no script to forget. When a language switcher changes the words in the browser, the server's value is only right for the first load, so the code that changes the locale must set document.documentElement.lang too; most i18n libraries have a hook or an option for it. Many sites need both, a server value for the first load and a client update for the switch.
Use the shortest tag that is right: en, es, ja. Add a region only when the text differs by region, such as pt-BR or zh-Hant for traditional Chinese. Some codes that look right but are not valid, and that html-lang-valid reports.
englishorspanish: use the code, not the name;es_ES: tags use a hyphen, not the underscore that some locale systems print;jporcn: these are country codes; the language codes arejaandzh.
Mark passages, not single borrowed words. A full sentence, a quote or a list of reviews in another language gets lang on its element; "café" in English text, a brand name, or a product called "Cumbre" does not. Content you do not write, such as reviews, comments and posts, often comes in many languages: if the source records the language, render it as lang; if not, leave the page's language rather than guessing.
A language switcher's own links, each written in its own language ("Español", "English"), need lang on each link as well, or "Español" is read by the English voice on the English page. Use hreflang too, if the link goes to that language's version. When content is translated by a service in the browser, the service usually updates lang itself; check that it does.
Fixing this with an AI coding assistant? Get this guide as Markdown
Verify the fix
5 checks, no mouse.
Test with: Screen reader
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat when a language is added.
Limits
This is a starting pattern, not a guarantee for every application. Screen readers switch voices only when a voice for that language is installed, and some ignore lang on short passages; that is outside your control, but the markup must still be right. Whether a passage is a name or a phrase in another language is a judgement no tool makes. Test each language version of your real pages, with someone who reads that language if you can.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
References
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.