onpage

Declare the page language

MetricSpot checks for a valid lang attribute on <html>. Without it, screen readers mispronounce, hreflang loses its anchor, and translation tools guess.

What this check does

Reads the lang attribute on the root <html> element and verifies it’s a valid BCP 47 language tag (en, en-US, es, de-AT, pt-PT). The check fails when:

  • The attribute is missing.
  • The value is empty (lang="").
  • The value doesn’t match a known language subtag.

Why it matters

The lang attribute is one of the cheapest HTML hygiene wins — one attribute on one element — but its absence breaks three different consumers at once.

  • Screen readers switch voice / pronunciation engines based on lang. A French page with lang="en" gets read by the English voice mispronouncing every word. NVDA, JAWS, VoiceOver, and TalkBack all behave this way.
  • Browser translation (Chrome’s “Translate this page”, Safari’s translation menu) uses lang as the source language. With no lang it has to guess from content, which is slower and less reliable on short pages.
  • hreflang anchors. Your <link rel="alternate" hreflang="…"> tags need a self-declaration on the root page — Google’s documentation explicitly recommends declaring lang on every page to corroborate the hreflang network.
  • SEO. Google uses lang as one of several signals to decide which country/language to surface the page for. Search Console’s International Targeting report flags pages with no lang.
  • AI extraction. Multilingual LLM systems chunk content with the declared language as a hint. Mis-declared lang lowers the chunk’s confidence score.

How to fix it

Set lang on the <html> element. Use a two-letter language code for general content, or lang-region if your content is region-specific:

<!DOCTYPE html>
<html lang="en">
<html lang="pt-PT">  <!-- European Portuguese, distinct from pt-BR -->

Multi-language sites — declare per-page. The lang on <html> should match the page’s main content, not your site’s default. If you have a Spanish translation at /es/, that page needs <html lang="es">, not <html lang="en">.

Astro:

---
const { lang = "en" } = Astro.props;
---
<html lang={lang}>

Then pass lang="es" from your Spanish layout.

Next.js (App Router):

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Per-locale routes: split into app/[locale]/layout.tsx and read the locale from params.

WordPress: the <html> element is generated by your theme’s language_attributes() call, which reads the site language from Settings → General. The template already does this — the fail almost always means the theme overrode header.php and dropped the call. Re-add <html <?php language_attributes(); ?>>.

Mixed-language content. If a paragraph or block is in a different language than the page, declare it inline:

<p>The French call it <span lang="fr">le mot juste</span>.</p>

Screen readers switch voice for the span, then switch back.

Audit yourself: DevTools → Console → document.documentElement.lang → should return "en", not "".

Frequently asked questions

Should I use en or en-US?

Use en unless your content is specifically US English (or specifically British, Australian, etc.) and that matters for translation/pronunciation. en covers all English locales; en-US narrows it. For most sites, the broader tag is right.

What’s the difference between lang and xml:lang?

lang is for HTML, xml:lang is for XML (and XHTML). Modern HTML5 pages only need lang. Don’t add both — it’s just noise.

My CMS sets lang="en-US" everywhere. Is that wrong?

Not wrong; it’s just narrower than it needs to be. For US-targeted sites, leave it. For sites with global English-speaking audiences, switch to plain en.

Sources

Last updated 2026-05-11