HTML lang Attribute: Fixing a Missing or Wrong Value
The lang attribute on the opening <html> tag tells software which
language a page is written in. Screen readers use it to choose a voice and pronunciation rules, browsers
use it for spelling checks, hyphenation and translation offers, and accessibility checkers flag it when
it is missing.
The fault is common because many themes hard-code lang="en-US" or leave the
attribute out altogether. This guide shows how to choose a correct value, where to set it on the main
platforms, how to mark passages in a second language, and what the attribute does and does not do for
search.
What the lang attribute actually does
The attribute sits on the root element of the document and applies to everything inside it unless a child element sets its own value:
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<title>Boiler servicing in Chesterfield | Northgate Heating</title>
</head>
That one value is read by several different pieces of software, and each does something different with it:
| Reader | What it does with lang | What goes wrong without it |
|---|---|---|
| Screen readers such as NVDA, JAWS and VoiceOver | Pick the speech voice and pronunciation rules for the language, where the voice is installed | The reader falls back to the user's default voice, so a French page may be read aloud with English sounds |
| Browsers | Choose a spelling dictionary for form fields, and inform the offer to translate the page | Spell checks underline correct British spellings; translation offers appear at the wrong time or not at all |
| CSS | hyphens: auto needs a language to know where words may break; the :lang()
selector matches on it | Automatic hyphenation silently does nothing |
| Quotation marks | The <q> element uses the quotation style of the language | German or French text gets English quote marks |
| Accessibility checkers | Test WCAG 2.2 success criterion 3.1.1, Language of Page, at Level A | An automatic failure in audits and accessibility statements |
WCAG 2.2 has a second, related criterion: 3.1.2 Language of Parts, at Level AA. It asks that a passage
in a different language from the rest of the page is marked with its own lang, so assistive
technology can switch voice for that passage and switch back afterwards.
What lang does and does not do for search
This is where most confusion comes from, so it is worth being precise. Google's documentation on multilingual
sites says it works out the language of a page mainly from the visible content, and that it does not
rely on code-level signals such as the lang attribute. A page with lang="en"
written entirely in Spanish will be treated as a Spanish page. A missing lang will not,
on its own, stop an English page ranking for English searches.
That does not make the attribute pointless. It is an accessibility requirement, it affects how browsers
treat the page, and other search engines and tools may use it as one signal among several. It also tends
to be a symptom: a site with no lang, or with en-US on a British business,
often has other untouched template defaults in the head.
Three neighbouring signals are often mixed up with lang. They do different jobs:
langon the html element describes the language of this document, for software that processes it.- hreflang annotations tell search engines which other addresses hold the same content in another language or for another region. They matter only when you have more than one version. The hreflang language codes guide covers that syntax.
og:localetells social platforms the locale of the shared card, written with an underscore, such asen_GB. The og:locale guide covers it.
lang="en-GB", og:locale
of en_GB and an hreflang entry of en-gb is saying the same thing three ways,
each in the syntax its reader expects.Choosing a valid value
The value is a language tag in the format defined by BCP 47, the internet standard for language identifiers. For almost every site it is either a two-letter language code on its own, or a language code followed by a hyphen and a two-letter region code.
| Value | Valid? | When to use it |
|---|---|---|
en | Yes | English with no particular region intended |
en-GB | Yes | British English: the right choice for most UK businesses writing colour, organise and centre |
en-US | Yes | American English. Wrong for a UK site, and usually present only because a theme shipped with it |
en-UK | No | UK is not the registered region subtag for the United Kingdom; GB is |
en_GB | No | Underscores belong to og:locale and some software locales, not to HTML |
english or EN-GB-London | No | Language names and invented subtags are not recognised |
cy or cy-GB | Yes | Welsh |
gd | Yes | Scottish Gaelic |
zh-Hans / zh-Hant | Yes | Chinese in simplified or traditional script, where script matters more than region |
Empty: lang="" | Valid but unhelpful | Means the language is unknown; checkers treat it as missing |
Tags are case-insensitive, but the usual convention is a lower-case language and an upper-case region:
en-GB. Do not add a region you do not mean. If a page is written for English speakers anywhere,
plain en is more honest than picking a country.
Sites that serve more than one language
Each language version needs its own value on its own pages. The French pages of a bilingual site should
say lang="fr" (or fr-FR, fr-BE and so on), not inherit the English
value from a shared layout. The most common fault on multilingual sites is a single hard-coded value
in the master template, which makes every translation claim to be English.
Finding the problem
Start with the raw HTML the server sends, because a script can change the attribute after the page loads and browser tools show only the final state.
curl -s https://example.co.uk/ | grep -io "<html[^>]*>"
Then compare it with what the browser ends up with. In the developer tools console, type:
document.documentElement.lang
If the first shows nothing and the second shows a value, a script is setting it. That is better than nothing for screen reader users, but anything that reads the HTML without running scripts, including many validators, sees no language. Move the value into the server-rendered markup.
What checkers report
- Lighthouse has two related audits in its accessibility category: one fails when
the html element has no
langattribute, the other when the value is not a valid language tag. - axe reports a missing value, an invalid value, and a mismatch between
langandxml:langwhen both are present. - The Meta Tag Analyzer reads the head of the page with the other tags, which makes
it easy to see a
langofen-USnext to anog:localeofen_GBand fix both together.
Test more than the home page. Blog posts, product pages, landing pages built in a page builder and checkout pages are often served by different templates, and each can have its own html tag.
The fix, step by step
Step 1
Read the lang value the server sends
Run one page of each template through the Meta Tag Analyzer, then fetch the same addresses
with curl and look at the opening <html> tag. Write down what you find
for each page type: missing, empty, en-US, an invalid value such as en-UK,
or a correct value. Also note whether a script changes it afterwards, by comparing with document.documentElement.lang
in the browser console.
Step 2
Choose a valid language tag
Pick
the value that matches how the text is actually written. For a UK business writing British English, use
en-GB; for English written for no particular country, use en. For other languages
use the two-letter code, adding a region only when the content is genuinely regional. Never use en-UK,
underscores or language names, because none of them are valid tags, and checkers will keep failing the
page until they are replaced.
Step 3
Set lang once in the layout
Put
the attribute on the <html> element in the one file that every page shares: header.php
through language_attributes() in WordPress, theme.liquid in Shopify, the root
layout in Next.js, or the base template of a static site generator. Take the value from the site or page
language setting rather than typing it, so translated pages get their own value automatically and nobody
has to remember to change it later.
Step 4
Mark passages in other languages
Where
a page contains a quotation, a product name or a paragraph in another language, wrap that passage in
an element carrying its own attribute, such as <span lang="fr"> or <blockquote lang="cy">.
Screen readers then switch voice for that passage. Leave out common borrowed words and proper names that
English readers pronounce in the English way, because marking those makes speech sound stranger, not
better.
Step 5
Add dir for right-to-left scripts
If
any page or passage is in Arabic, Hebrew, Persian or Urdu, add dir="rtl" next to the language,
for example <html lang="ar" dir="rtl">. The lang attribute does not set
text direction on its own. For user-supplied text whose direction you cannot predict, such as names in
reviews, use dir="auto" or the <bdi> element so it does not scramble
the punctuation of the surrounding English.
Step 6
Retest with an accessibility checker
Clear
any page cache, then run Lighthouse or axe on one page of each template and confirm the language audits
pass. Run the Meta Tag Analyzer again on the same pages to check the value now matches og:locale
and any hreflang entries. Finally, open a page with a screen reader such as NVDA or VoiceOver and listen
to a marked passage to confirm the voice changes and changes back.
Where to set it on common platforms
WordPress
Well-built themes print the attribute through the language_attributes() function in header.php,
which reads the Site Language chosen under Settings, General. Choosing English (UK) there produces lang="en-GB".
<html <?php language_attributes(); ?>>
If changing the Site Language makes no difference, the theme has hard-coded the value. Edit it in a child theme rather than the parent, so a theme update does not undo the change. Multilingual plugins such as WPML and Polylang switch the value for each language through the same function, which is another reason not to hard-code it.
Shopify
Current Shopify themes set the value from the storefront's active language in layout/theme.liquid:
<html class="no-js" lang="{{ request.locale.iso_code }}">
If yours shows a fixed value, replace it with the Liquid variable, and check any alternative layout files such as a separate checkout or password layout. The published default language is set under Settings, Languages.
Next.js and other JavaScript frameworks
In the App Router the html element is written in the root app/layout.tsx, so the attribute
goes there directly. Sites with several languages usually put the locale in a route segment and read
it in that layout. In the Pages Router it belongs in pages/_document on the <Html>
component, or is set for you by the built-in i18n routing. Avoid setting it with client-side code, because
the first HTML the server sends will then have none.
export default function RootLayout({ children }) {
return (
<html lang="en-GB">
<body>{children}</body>
</html>
);
}
Static sites and hand-built pages
Every file has its own html tag, so a search across the project is the quickest check. Most static site generators, such as Hugo, Eleventy and Jekyll, keep it in one base layout and read a language value from the site configuration.
Edge cases and things that trip people up
xml:lang. Only needed for XHTML served as XML. On ordinary HTML pages it does nothing, and if it is present with a different value fromlang, checkers flag the mismatch. Remove it, or make it match.- The content-language meta tag.
<meta http-equiv="content-language">is not valid in current HTML and is not a substitute. Thelangattribute takes precedence where both exist. - Embedded content. An iframe carries its own document with its own html element.
A widget in the wrong language needs fixing at its source, or a
langon the iframe's own page. - Language switchers. Each option in a menu that lists languages by their own names,
such as Cymraeg or Français, should carry that language's
langso it is pronounced correctly. - Machine translation in the browser. When a visitor uses the browser's translate feature, the browser may update the attribute itself. That is not something to fix.
- SVG and MathML. Inline SVG inherits the page language; text inside it in another
language can take its own
langin the same way.
Keeping it right
- One source of truth. Take the value from the CMS or site configuration in one layout, never typed into several templates.
- A check in your build or monitoring. Automated accessibility tests such as axe in a continuous integration pipeline catch a missing or invalid value before release.
- A note for editors. Tell content authors how to mark a foreign-language quotation in the editor. Many editors, including the WordPress block editor, let you add an attribute through the HTML view or a custom class.
- Review after theme changes. A new theme, page builder or checkout template is the
most common way an old
en-UScreeps back.
For the rest of the head, the Meta Analyzer
Guide explains each check the analyzer runs, and the Accessibility
Guide covers the wider WCAG picture that lang is one small part of.
1. Does the lang attribute help my Google rankings?
Not directly. Google's documentation says it identifies the language of a page mainly from its visible text and does not rely on code-level signals such as the lang attribute. So a missing value will not stop an English page appearing for English searches, and a wrong value will not move it into another country. The attribute is still worth fixing because it is an accessibility requirement, it changes how browsers and screen readers handle the page, and other tools may use it as a signal.
2. Should a UK website use en-GB or en?
Use en-GB if the text is written in British English for a British audience, which is true of most UK business sites. Use plain en if you write for English speakers in general and have no particular country in mind. Both are valid and both pass accessibility checks. The practical difference is small: en-GB lets browsers pick a British spelling dictionary and lets screen readers that have a British voice installed use it, which suits spellings like colour and organise.
3. Is en-UK a valid lang value?
No. Language tags use the region codes from the international country code list, and the code for the United Kingdom there is GB, not UK. Validators and accessibility checkers will report en-UK as an invalid value, and software that reads the attribute may ignore it. The same mistake appears in og:locale as en_UK and in hreflang as en-uk. Change all of them to the GB form, written with a hyphen in HTML and hreflang, and with an underscore in og:locale.
4. Why does WordPress still say en-US after I changed the site language?
Because the theme is not using the language_attributes function and has typed the value directly into header.php, or a page builder or caching layer is serving an old copy. Clear any page and CDN cache first, then view the source. If the value is still en-US, open the theme's header file and replace the fixed value with a call to language_attributes, in a child theme so an update does not overwrite it. Some page builders have their own canvas template that needs the same change.
5. Do I need to mark every foreign word with its own lang?
No. The WCAG criterion on language of parts excludes proper names, technical terms, words of an unknown language, and words that have become part of the surrounding language, such as café, déjà vu or croissant in English. Mark whole phrases, sentences, quotations and passages where a listener would otherwise hear the text mispronounced so badly it is hard to follow. Marking single borrowed words usually makes speech sound more awkward, because the voice changes mid-sentence.
6. What is the difference between lang and hreflang?
The lang attribute describes the language of the document you are reading, for browsers, screen readers and other software that processes that page. Hreflang annotations are a list of links telling search engines where to find the equivalent page in other languages or for other regions, so they can show the right version to each searcher. A single-language site needs a lang attribute but no hreflang at all. A multilingual site needs both, and each translated page should carry its own lang value.
7. Can I set the lang attribute with JavaScript?
You can, and screen readers running in a browser will usually respect a value set by script. But anything that reads the raw HTML without running scripts, including many validators, crawlers and audit tools, will see a page with no language. It also adds a moment where the page exists without one. Put the value in the HTML the server sends, generated from your site or page language setting, and only change it with script if the page genuinely switches language without reloading.
The Meta Tag Analyzer reads the head of your page and checks the title, description, canonical, robots directives, viewport, lang, Open Graph and X card tags, then lists each finding with the guide that fixes it.
Open Meta Tag Fixes →