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 withlang="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
langas the source language. With nolangit 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 declaringlangon every page to corroborate the hreflang network. - SEO. Google uses
langas one of several signals to decide which country/language to surface the page for. Search Console’s International Targeting report flags pages with nolang. - AI extraction. Multilingual LLM systems chunk content with the declared language as a hint. Mis-declared
langlowers 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