What does hreflang actually do?
hreflang is an annotation that tells Google which URL is the version of a page for which language and region. Google's guide Tell Google about localized versions of your page says the annotations help it serve the right version to the right user. They do not promise a position in search results, and I make no such promise either. Which version appears for whom remains the search engine's decision.
The same guide adds something useful about duplicates: localized versions are only considered duplicates if the main content of the page remains untranslated. A properly translated page is therefore not a duplicate of its original, and there is no reason to point the canonical address of one language at the other.
Why does each language need its own URL?
In Managing multi-regional and multilingual sites, Google recommends different URLs for each language version rather than cookies or browser settings that change the language on the same address. A script that swaps the text when a visitor presses a button leaves one address that a search engine sees in one language, and a visitor cannot share a link to the version they were reading.
The same page advises a single language for content and navigation on each page and warns against translating only the boilerplate while leaving the main content in another language. So build real pages: for a bilingual website that means a full set of pages in each language, each at its own address.
Where do the hreflang tags go?
Google lists three methods: link elements in the HTML head, a Link header in the HTTP response, and entries in the XML sitemap. It states that they are equivalent from its perspective, so choose the one you can maintain. For ordinary HTML pages the head is the simplest. The header method is meant for non-HTML files such as PDFs. A sitemap keeps all the pairs in one file. Using several methods at once gives no benefit in Search.
What are the rules that make hreflang work?
Rule one: the links must be reciprocal. Google states that each language version must list itself as well as all the other versions, that if two pages do not point to each other the tags are ignored, and that the set of annotations should be identical on every version. If the English page lists the German page but the German page lists nothing, the English tag is wasted.
Rule two: the URLs must be fully qualified. Google states that alternate URLs have to include the protocol, for example https://example.com/de/page/, and a bare path such as /de/page/ does not meet that.
Rule three: the codes must be valid. The language is an ISO 639-1 code, optionally followed by a region as an ISO 3166-1 Alpha 2 code. A region cannot be given alone, and codes such as es-419 are not supported.
When do you add a region, and when only a language?
Add the region when the audience is tied to a country. The Fedenko site serves the Swiss market, so its versions are declared as de-CH for German in Switzerland and en-CH for English in Switzerland, plus x-default. If the audience is defined by language rather than by country, a plain language code is enough, and that is what this site uses: en and uk. The point is to describe the real audience and not to add precision you cannot back.
What is x-default for?
x-default is the fallback for users whose language settings match none of your versions. Google says it is used when no other language or region matches, that it needs no language code, and that it was designed for language selector pages. Many sites point it at the version they consider the main one, and so does this site, whose x-default is the English page.
Which mistakes break a bilingual setup most often?
- One-way links, where a page lists the other language but is not listed back. Google ignores such tags.
- A region code without a language, or a code outside the ISO lists.
- A missing self-reference: each version must list itself too.
- A language switch that sends the visitor to the home page of the other language instead of the equivalent page.
- Redirecting visitors automatically by their browser language. Google warns that such redirects can prevent users and search engines from seeing all versions, and suggests links that let people choose.
- Mixing languages on one page, for example a translated menu above an untranslated body.
- Relying on the lang attribute. Google says it does not use code-level language information such as lang attributes or the URL to determine the language of a page. It reads the visible content instead.
What about a page that exists in one language only?
It happens: a guide written in one language, or a service that only one market needs. The rules above work in your favour here. hreflang describes pairs that exist, so a page without a counterpart simply carries no alternate tags, and you should not create an empty or machine-translated copy just to complete a set. Google also notes that a page translated only in its boilerplate is a poor experience, so a hollow copy would do more harm than the gap.
What the visitor needs is a language switch that does not dead-end. On this site the Ukrainian article about what affects the cost of a website has no English version, so its EN link leads to the English blog index instead of a missing page. That choice is mine, not a Google rule, but it keeps the switch working on every page.
Should titles, descriptions and URLs be translated too?
Titles and descriptions: yes. They are visible content, and a Ukrainian page with an English title in the results is half-translated. Each version needs its own title, its own description and exactly one heading of the first level in its own language.
URLs are a matter of choice. You can translate the words in the path, transliterate them into Latin letters or keep one slug for all languages. This site uses Latin transliteration for Ukrainian paths, for example /uk/posluhy/ for the services index. Any of these can work if the address is stable, readable and the same everywhere it is declared: in the page, the canonical tag, the hreflang tags and the sitemap.
How do you keep the pairs correct over time?
Most hreflang errors are not made at launch. They appear later, when a page is renamed in one language and not the other, or a new page is added to one version only. Treat the set as a unit: any change to an address, a language or a title goes into both versions in the same edit, and the pairs are re-checked before publishing. On this site the build script refuses to pass if a pair is not reciprocal, which turns the rule into a check that cannot be forgotten.
How does it look on a real site?
On Fedenko, the German and English versions of the home, cleaning, renovation, about, contact, legal and thank-you pages are linked with hreflang for de-CH, en-CH and x-default, and the launch also covered canonical addresses, a sitemap and structured data. The Fedenko case has the full list.
This site follows the same pattern. Every page that exists in both languages has a canonical address, hreflang for en, uk and x-default, and the same pairs in the sitemap. The language switch leads to the equivalent page, and the build script checks that each pair points back at the other. I keep one exception visible rather than hidden: a page that exists in one language only gets no hreflang at all, because there is nothing to pair it with.
How can you check your own site?
- Open the page source of each language version and find the alternate links in the head.
- Compare the lists. They must be identical on every version and each one must include the page itself.
- Open every address in the list. It must load without a redirect and show the right language.
- Click the language switch on three different pages and confirm that it lands on the equivalent page, not on the home page.
- If the sitemap carries the pairs, check that they match the head. Two different sets on the same site only create confusion.
- Repeat the whole check after any page is renamed or added.
Technical setup of this kind is part of the SEO, analytics and Google setup service and of the bilingual website scope.