Lang and xml:lang Must Match

No Comments
Lang and xml:lang must match
TL;DR: If your <html> tag carries both a lang and an xml:lang attribute, the two must declare the same base language. When they disagree, browsers, screen readers, and search engines get conflicting language signals, and each one resolves the conflict differently. The clean fix in modern HTML: keep lang, make xml:lang identical or delete it.
Check ID
HT-026
Category
HTML Structure
Severity
Medium
Standard
WCAG 3.1.1
Fix Effort
Low

What this check actually flags

This one comes straight out of the axe-core ruleset (the rule is literally called xml-lang-mismatch), and it fires when your root element looks something like this:

<html lang="en" xml:lang="fr">

Two language declarations, two different languages. The lang attribute is the standard HTML way to declare a document's language. The xml:lang attribute is the XML way, a holdover from the XHTML era when everyone was told to serve both "for compatibility." Plenty of templates written between 2003 and 2012 still carry both, and they get copied forward into new builds without anyone looking at them.

The rule compares the primary language subtag of each attribute, so lang="en-US" xml:lang="en-GB" passes (both are English), while lang="en" xml:lang="de" fails. That base-subtag comparison matters: regional variants are fine, different languages are not.

Here is the part most people miss. In an HTML document (anything served as text/html, which is essentially every page you work on), xml:lang has no effect at all. The HTML spec only permits it on elements that also have a matching lang attribute, and browsers ignore it for language processing. It only becomes meaningful when the document is parsed as XML, such as XHTML served with an XML MIME type. So a mismatch means your dead attribute is contradicting your live one, and any tool that reads markup naively, including some crawlers, translation layers, and older assistive tech, can pick the wrong one.

Why an SEO should care about a dusty XML attribute

Fair question, because on its face this looks like a pure accessibility nitpick. It is a WCAG 3.1.1 (Language of Page) issue first: screen readers pick a speech synthesizer based on declared language, and English text read aloud with French pronunciation rules is genuinely unusable. But there is a real search angle too.

Google states in its documentation that it does not use the lang attribute to determine page language, it detects language from visible content. That is true and worth knowing. But your language declarations do not exist in a vacuum:

  • Hreflang consistency. If your hreflang annotations say a URL is the German version, your on-page language signals say French, and your content is actually German, you have introduced noise into a system that already fails silently when signals conflict. I have debugged enough hreflang clusters to tell you: the sites with messy language metadata are the same sites whose alternates never get picked up cleanly.
  • Other consumers. Bing, translation proxies, browser auto-translate prompts, and various AI crawlers do read declared language. A wrong xml:lang can trigger Chrome's "Translate this page?" bar on a page that needed no translation. That is a real user experience hit you can measure in bounce behavior.
  • Quality surface. This class of error correlates with template rot. When I see mismatched language attributes in an audit, I almost always find other inherited-template problems nearby: stale meta tags, duplicate IDs, leftover staging markup. It is a cheap early warning.

How the two attributes interact

<html lang="en" xml:lang="fr"> Two declarations, two languages: which one wins? Parsed as HTML (text/html) lang="en" wins xml:lang is ignored by the browser Parsed as XML (XHTML) xml:lang="fr" wins Same page, opposite answer The fix removes the ambiguity entirely: <html lang="en"> or <html lang="en" xml:lang="en">

How to detect it at scale

On a single page, view source and look at the <html> tag. Done. Across a site, you want tooling:

  • Screaming Frog: set up two Custom Extractions with XPath, //html/@lang and //html/@xml:lang, crawl, export, and compare the columns in a spreadsheet. Filter rows where both are populated and the first two letters differ. Five minutes of setup, full-site coverage.
  • Lighthouse and axe DevTools: both run the axe xml-lang-mismatch rule per page. Good for spot checks and for CI if you run Lighthouse in your build pipeline.
  • Sitebulb: runs accessibility hints during a crawl and will surface language declaration conflicts site-wide without extra configuration.
  • W3C Nu HTML Checker: flags xml:lang that does not match lang as a validation error, since the HTML spec requires them to match when both are present.

Because this attribute lives in the page template, you rarely have hundreds of unique instances. You have one template bug replicated across hundreds of URLs, which is good news for the fix.

How to fix it, step by step

  1. Find the template. The <html> tag is set in your base layout: header.php in classic WordPress themes, the root layout in Next.js or Nuxt, _Layout.cshtml in .NET, and so on. One edit usually fixes every page.
  2. Decide the correct language. Use the language of the actual visible content, as a valid BCP 47 tag: en, en-GB, fr, pt-BR. Do not guess from the office location of the client.
  3. Prefer dropping xml:lang. If you serve text/html, which you almost certainly do, xml:lang buys you nothing. <html lang="en"> is complete and correct.
  4. If you must keep both, make them identical. Some CMS plugins or legacy XSLT pipelines re-add xml:lang. Fine: set both to exactly the same value.
  5. Check multilingual logic. On international sites, the language attribute is usually templated per locale. Verify the variable feeding it is the same one feeding your hreflang output, so the two can never drift apart.
  6. Re-crawl and confirm. Re-run the Screaming Frog extraction and confirm zero mismatched rows.

Reference: valid and invalid combinations

Root element markupVerdictWhy
<html lang="en">PassThe modern baseline. One attribute, no conflict possible.
<html lang="en" xml:lang="en">PassRedundant but consistent. Valid per the HTML spec.
<html lang="en-US" xml:lang="en-GB">Pass (axe)Same base language. Still sloppy, so align them anyway.
<html lang="en" xml:lang="de">FailDifferent base languages. This is the mismatch the check exists for.
<html xml:lang="fr">Failxml:lang alone does nothing in HTML. The page has no effective language declaration.

DO

  • Declare exactly one language source of truth per template
  • Use valid BCP 47 tags that match the visible content
  • Drive lang and hreflang from the same locale variable
  • Add a lang check to your crawl or CI so regressions get caught
  • Use lang on inline foreign-language snippets too, like <span lang="fr">

DON'T

  • Copy an old XHTML doctype template and inherit its attributes blind
  • Hardcode lang="en" on a multilingual site's shared layout
  • Use country codes as languages (lang="uk" is Ukrainian, not United Kingdom)
  • Rely on xml:lang alone on pages served as text/html
  • Assume Google ignoring lang means nothing else reads it

What good looks like

A clean site has one lang attribute on the root element of every page, valued with a correct BCP 47 tag for that page's content, no xml:lang at all (or an identical one where a legacy pipeline insists), and locale-aware templating on international builds so the attribute changes with the content. Your crawler's custom extraction shows one consistent value per locale folder and zero conflicts. That is the whole standard. It is one of the cheapest passes you will ever earn in an audit, which is exactly why leaving it broken looks bad.

FAQ

Does Google use the lang attribute for ranking or language detection?
Google has said it detects page language from the content itself rather than the lang attribute. But hreflang, Bing, browser translation features, screen readers, and various other crawlers do consume declared language, so keeping it correct still pays for itself.
Is lang="en-US" versus xml:lang="en-GB" a failure?
Not for the axe rule, which compares only the primary subtag, and both are "en". It will pass automated checks. I would still align them because there is no upside to letting two attributes disagree about anything.
Should I just delete xml:lang everywhere?
If your pages are served as text/html, yes, that is my default recommendation. The attribute only functions under XML parsing. The exception is a pipeline that genuinely processes your markup as XML, in which case keep both and keep them identical.
Does this rule apply to elements inside the page, not just the html tag?
Yes. Any element can carry both attributes, and they should match wherever they co-occur. In practice the root element is where 95 percent of real-world mismatches live, because that is what templates set.
Which WCAG criterion does a mismatch fail?
It maps to WCAG 3.1.1, Language of Page (Level A), because conflicting declarations can cause assistive technology to select the wrong language for pronunciation and processing.

Want every template-level signal checked, not just this one?

Language attributes are one of dozens of inherited-template issues that quietly contradict your international SEO setup. Our advanced audit crawls the lot, ranks what actually matters, and hands you fixes your dev team can ship.

Get the Advanced SEO Audit

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog