How hreflang works, with a full code example
A website with several language versions runs into a problem search engines cannot solve on their own: how does Google know that the German, Spanish and English versions of a page are the same content, just in a different language? Without an explicit signal, a search engine treats those three URLs as three separate, possibly even competing pages. That is exactly what hreflang addresses. The attribute groups every language version of a page together and, at the same time, states which language and, optionally, which country each version is meant for.
The value of the hreflang attribute follows a fixed syntax: first the language code in ISO 639-1 format, for example "en" for English or "de" for German, optionally followed by a hyphen and the region code in ISO 3166-1 Alpha-2 format, such as "en-GB" for English aimed at the United Kingdom or "es-MX" for Spanish aimed at Mexico. The order is mandatory: language first, region second, never the other way round. A value like "GB-en" is invalid and gets ignored. There is also a special value, "x-default", which marks the version shown when none of the defined language versions match a visitor's language or region, usually the international or English homepage.
The most common way to implement hreflang is as a group of link tags in the head of every page involved. That group must be identical across all versions: every page lists itself and every other version. Here is a complete block for a glossary entry with three language versions plus x-default, using our own domain as the example. The figure below shows the complete block for all three language versions.
This exact block, with the same four hreflang lines and the same canonical tag, needs to sit in the head of all three pages involved, not just the English one. The only thing that changes from page to page is the page's own canonical URL. On sites with many language versions, the head section quickly becomes hard to maintain; in that case, the XML sitemap is the better route, with each URL referencing its alternates through xhtml:link entries. For non-HTML documents such as PDFs, the correct method is the HTTP Link header with rel="alternate", since a PDF has no head section to place tags in.
Which of the three methods to pick depends mostly on the number of pages involved. A site with a few dozen multilingual pages can manage hreflang through link tags in the head without trouble, because mistakes can still be checked by hand. With several hundred or thousand URLs per language, the sitemap approach becomes far easier to maintain, since the mapping can be generated from a single data source instead of being kept in every template. Whichever method is used, the rule stays the same: the group has to be complete and internally consistent, or Google ignores the whole signal for those URLs.
One block, three pages — only the canonical line changes
<link rel="alternate" hreflang="es" href="https://zds.es/que-es-hreflang/"><link rel="alternate" hreflang="en" href="https://zds.es/en/what-is-hreflang/"><link rel="alternate" hreflang="de" href="https://zds.es/de/was-ist-hreflang/"><link rel="alternate" hreflang="x-default" href="https://zds.es/que-es-hreflang/"><link rel="canonical" href="https://zds.es/en/what-is-hreflang/">
Every page lists itself
The four hreflang lines are identical across all three versions, including the one pointing at the page's own URL.
x-default catches the rest
It marks the version shown when a visitor's language or region matches none of the defined versions.
Only the canonical changes
Each version's canonical points at itself, matching its own hreflang line character for character.
The group only works complete: one missing line or one differing URL and the signal lapses for every URL involved.
