RatedWithAI

RatedWithAI

Accessibility scanner

GuidesSeptember 18, 2026

One Attribute Decides Which Voice Reads Your Page Aloud

<html lang="en"> is the cheapest accessibility fix on the web: one attribute, one element, usually one template. It is also missing from about one home page in six, and when it is wrong rather than missing, every screen reader on earth reads the page in the wrong voice.

~1 in 6
Home pages in the WebAIM Million with no document language
Level A
SC 3.1.1 Language of Page: the lowest bar, not a stretch goal
1 line
The whole fix, in most sites' layout template

What the Attribute Actually Does

A screen reader is a text-to-speech engine with a set of voices, and each voice knows the pronunciation rules of one language. When it opens a page it reads the lang on the html element and picks the voice to match. That is the whole mechanism, and it is why the attribute matters far more than its size suggests.

With no language declared, the reader falls back to whatever its user set as default. A Spanish page opened by someone whose reader defaults to English is spoken with English phonetics: every word audible, almost none of them understandable. The same attribute drives braille translation tables, the browser's "translate this page?" prompt, automatic hyphenation, the style of quotation marks and the spell-check dictionary in form fields.

None of that shows up on screen. A page with no lang, or the wrong one, looks identical to a correct page in every browser, every design review and every visual QA pass. The only person who notices is the one listening to it.

What WCAG Requires

CriterionLevelWhat it requires
3.1.1 Language of PageAThe default human language of each page can be programmatically determined. In HTML that means a valid lang on the html element.
3.1.2 Language of PartsAAPassages in a different language carry their own lang. Proper names, technical terms and words absorbed into the surrounding language are exempt.

Because 3.1.1 is level A, it sits under every accessibility standard that cites WCAG: the ADA Title II rule for state and local government, Section 508, EN 301 549 and the European Accessibility Act. It is also one of the checks every automated scanner runs, which is why it shows up in demand letters that quote a scanner's output line by line.

The Four Ways It Fails

Missing. No lang on the html element at all. Common on hand-built sites, old CMS themes, email-builder landing pages and static pages exported from design tools.

Empty. <html lang="">. Usually a template variable that resolved to nothing, like a locale setting left blank in the CMS. On the html element this fails 3.1.1 exactly as a missing attribute does. (On an inner element, lang="" is correct markup meaning "language unknown", and is not a failure.)

Not a language code. lang="english", lang="en_US" with an underscore, lang="{{locale}}" left unrendered. Screen readers cannot map any of those to a voice, so the page behaves as if nothing were declared.

Contradicted. A page that declares lang="en" and xml:lang="fr" on the same element has told assistive technology two different things. Some readers take one, some take the other.

<!-- Fails 3.1.1: no language -->
<html>

<!-- Fails 3.1.1: not a language tag -->
<html lang="english">
<html lang="en_US">

<!-- Passes -->
<html lang="en">
<html lang="en-US">

<!-- Right-to-left: declare direction too -->
<html lang="ar" dir="rtl">

<!-- 3.1.2: a passage in another language -->
<blockquote lang="fr">L'accessibilité n'est pas une option.</blockquote>
<a href="/de/" lang="de" hreflang="de">Deutsch</a>

Why a Wrong lang Is Worse Than a Missing One

The failure no presence check catches is the page that declares a language, just not its own. It happens when a theme or starter template ships with lang="en" hard-coded and the site is then written in German, Spanish or Dutch. Every automated check that only asks "is there a lang attribute?" passes it.

For the listener it is the worst of the options. A missing lang falls back to the user's own default, which for most people reading a site in their own language is right. A wrong lang overrides that default for everyone: every screen reader, whatever it is set to, reads the German storefront with an English voice. It was declared on purpose, so nothing downstream second-guesses it.

The same thing happens in multilingual sites, where the translated pages inherit the base language's layout and nobody changes the attribute per locale. The English site is fine; every other language is spoken in English.

The Codes People Get Wrong

  • uk is Ukrainian, not the United Kingdom. A British site declaring lang="uk" is asking for a Ukrainian voice. The code for British English is en-GB.
  • en-UK is not a real tag. The region is GB. It does no harm in practice, because every screen reader falls back to plain English, but it is worth correcting.
  • Underscores are locale syntax, not language tags. en_US is how many frameworks name a locale internally; the HTML attribute wants en-US with a hyphen.
  • Case does not matter. en-us, EN-US and en-US are the same tag. Three-letter codes such as fil or yue, and script subtags such as zh-Hant, are valid too.

How to Check Your Own Page

The checker at the top of this article reads the HTML your page serves and reports the language it declares, whether that value is a real language tag, whether xml:lang agrees with it, and whether any inner element carries a value that is not a language code. Those are counted as failures, each under the criterion it fails.

It also reads the visible text and says which language it looks like. When the text is long enough and the signal clear enough, a mismatch with the declared language is listed for review, never counted against you, because a stop-word count is evidence, not proof. Close relatives such as Danish and Swedish, or Catalan and Spanish, are never compared at all. A right-to-left language with no dir attribute is flagged for review for the same reason: a stylesheet may already set direction.

It is one page, but the lang attribute almost always lives in the one layout template every page shares, so one page usually tells you about the site. What it cannot tell you is the rest of WCAG. The whole-site scan renders every page in a real browser and names each WCAG 2.1 AA violation by criterion, with the element and the page it is on. The checker's result hands your domain straight to it.

Where to Fix It

  • Next.js App Router: the root app/layout.tsx renders <html lang="en">. For a localised site, read the locale from the route segment rather than hard-coding it.
  • WordPress: themes should print language_attributes() on the html tag, which follows Settings → General → Site Language. A hard-coded lang in header.php is the usual culprit.
  • Shopify: theme.liquid should carry lang="{{ request.locale.iso_code }}", so each market's storefront declares its own language.
  • Static and exported pages: check every standalone HTML file, especially landing pages built in a separate tool. They skip the site's shared template and are where a missing lang most often survives.

Frequently Asked Questions

Is a missing html lang attribute a WCAG failure?

Yes. SC 3.1.1 Language of Page is level A, the lowest conformance level, and it requires the default human language of each page to be programmatically determinable. The lang attribute on the html element is how that is done. A page with no lang, or with lang="" on the html element, fails 3.1.1 outright. It is one of the six failures the WebAIM Million finds most often, on roughly one home page in six.

Should I use lang="en" or lang="en-US"?

Either passes WCAG. The primary subtag (en) is what 3.1.1 needs; the region (US, GB, AU) only refines pronunciation and spelling where a screen reader has a regional voice installed. Use the region if your content is written for one, and leave it off if it is not. What matters is that the value is a real language tag: en-UK is not one, because the ISO region code for the United Kingdom is GB, although every screen reader falls back to plain English, so nothing is mispronounced.

Is a wrong lang attribute worse than a missing one?

Usually, yes. With no lang declared, a screen reader falls back to its user's own default language, which is often right for that user. A wrong lang is applied to everyone: a German storefront left with lang="en" from an English theme is read in an English voice with English pronunciation rules by every screen reader, whatever its settings, so almost every word is mangled. The markup passes a presence check and fails the person listening.

What does WCAG 3.1.2 Language of Parts require?

SC 3.1.2 is level AA. It requires a lang attribute on any passage in a different language from the rest of the page, such as a French quotation on an English page or a language switcher that names each language in itself (Deutsch, Español). Proper names, technical terms and words that have entered the surrounding language are exempt. An inner lang value that is not a real language code fails it, while lang="" on an inner element is valid and means the language is unknown.

Does the lang attribute matter for SEO?

Less than people expect. Google says it ignores the html lang attribute and detects language from the visible text, and uses hreflang for alternate versions. Bing does read the lang attribute and the content-language header as signals. Browsers use it to decide whether to offer translation, and to choose hyphenation, quotation marks and spell-check dictionaries. The accessibility effect, which voice speaks the page, is the one that is certain.

Do I need dir="rtl" as well as lang for Arabic or Hebrew?

You should. lang tells assistive technology which language the text is in; dir sets the base direction of the text, punctuation, tables and form fields. Without dir="rtl" on the html element, mixed-direction text such as a price or an English brand name inside Arabic can be reordered wrongly. A stylesheet can set direction too, but the attribute survives reader modes, translation and copy-paste, and the CSS does not.

The Cheapest Fix Is the One to Check First

A missing or wrong lang is one line in one template, and it sits under level A of every standard that cites WCAG. Check it with the tool at the top of this article; if it is wrong, it is wrong on every page that shares that layout.

The whole-site scan renders every page and names each WCAG 2.1 AA failure with the element and page it is on. No signup, no card.

Open the html lang checker on its own page →