Hreflang uses ISO 639-1 for language and ISO 3166-1 alpha-2 for region. The wrong codes get silently rejected by Google — your annotation looks fine in source, but Google treats it as missing. Common traps: en-UK (correct is en-GB), cn for Chinese (correct is zh), made-up regional variants. This guide lists the codes, the convention mistakes, and the validation patterns.
Hreflang values follow BCP 47 but in practice use one of two shapes:
<!-- Language only --> <link rel="alternate" hreflang="en" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <link rel="alternate" hreflang="fr" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- Language + region --> <link rel="alternate" hreflang="en-GB" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <link rel="alternate" hreflang="en-US" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <link rel="alternate" hreflang="fr-CA" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <link rel="alternate" hreflang="zh-CN" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- Special fallback --> <link rel="alternate" hreflang="x-default" href="/aipageseo-demo-pages/hreflang-fixes-index.html" />
- (not underscore)| Language | Code | Common mistake |
|---|---|---|
| English | en | — |
| French | fr | — |
| German | de | Some use ge — wrong |
| Spanish | es | Some use sp — wrong |
| Portuguese | pt | — |
| Italian | it | — |
| Chinese | zh | cn is a region code, not language |
| Japanese | ja | Some use jp — that's region |
| Korean | ko | Some use kr — that's region |
| Arabic | ar | — |
| Russian | ru | — |
| Dutch | nl | Some use du — wrong |
| Swedish | sv | Some use se — that's region |
| Hebrew | he | Some use iw (deprecated) |
| Hindi | hi | — |
| Polish | pl | — |
| Turkish | tr | — |
| Region | Code | Common mistake |
|---|---|---|
| United Kingdom | GB | UK is NOT an ISO code |
| United States | US | — |
| Germany | DE | — |
| France | FR | — |
| Spain | ES | — |
| Italy | IT | — |
| China | CN | — |
| Japan | JP | — |
| Brazil | BR | br is also Breton language — case matters in tooling |
| Canada | CA | — |
| Mexico | MX | — |
| Australia | AU | — |
| India | IN | — |
| Hong Kong | HK | — |
| Taiwan | TW | — |
| Netherlands | NL | — |
en — English, any region en-GB — English, United Kingdom (NOT en-UK) en-US — English, United States en-AU — English, Australia en-CA — English, Canada fr — French, any region fr-FR — French, France fr-CA — French, Canada fr-BE — French, Belgium fr-CH — French, Switzerland es — Spanish, any region es-ES — Spanish, Spain es-MX — Spanish, Mexico es-AR — Spanish, Argentina zh — Chinese, any region (rarely used alone) zh-CN — Chinese, China (simplified) zh-TW — Chinese, Taiwan (traditional) zh-HK — Chinese, Hong Kong zh-Hans — Chinese, simplified script (BCP 47 extension) zh-Hant — Chinese, traditional script pt — Portuguese pt-BR — Portuguese, Brazil pt-PT — Portuguese, Portugal x-default — Fallback for unmatched locales
// JavaScript example
const VALID_LANGUAGES = new Set([
'aa','ab','ae','af','ak','am','an','ar','as','av','ay','az',
'ba','be','bg','bh','bi','bm','bn','bo','br','bs',
'ca','ce','ch','co','cr','cs','cu','cv','cy',
'da','de','dv','dz',
'ee','el','en','eo','es','et','eu',
// ... full ISO 639-1 list
]);
const VALID_REGIONS = new Set([
'AD','AE','AF','AG','AI','AL','AM','AO','AQ','AR','AS','AT','AU','AW','AX','AZ',
'BA','BB','BD','BE','BF','BG','BH','BI','BJ','BL','BM','BN','BO','BQ','BR','BS',
// ... full ISO 3166-1 alpha-2 list
]);
function validateHreflang(code) {
if (code === 'x-default') return true;
const parts = code.split('-');
if (parts.length === 1) {
return VALID_LANGUAGES.has(parts[0].toLowerCase());
}
if (parts.length === 2) {
return VALID_LANGUAGES.has(parts[0].toLowerCase()) &&
VALID_REGIONS.has(parts[1].toUpperCase());
}
return false;
}
npm install bcp-47
const { parse } = require('bcp-47');
const result = parse('en-GB');
console.log(result.language); // 'en'
console.log(result.region); // 'GB'
// Returns null for invalid tags
<!-- WRONG: en-UK --> <link rel="alternate" hreflang="en-UK" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- RIGHT: en-GB --> <link rel="alternate" hreflang="en-GB" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- WRONG: cn for Chinese language --> <link rel="alternate" hreflang="en" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- RIGHT: zh for language, optionally zh-CN for China region --> <link rel="alternate" hreflang="zh-CN" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- WRONG: underscore separator --> <link rel="alternate" hreflang="en_GB" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- RIGHT: hyphen --> <link rel="alternate" hreflang="en-GB" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- WRONG: REGION-language order --> <link rel="alternate" hreflang="GB-en" href="/aipageseo-demo-pages/hreflang-fixes-index.html" /> <!-- RIGHT: language-REGION --> <link rel="alternate" hreflang="en-GB" href="/aipageseo-demo-pages/hreflang-fixes-index.html" />
Verify all language and region codes parse correctly.
Run Hreflang Checker →