Tutorial: Implementing Hreflang Tags for a Multilingual Website

This tutorial guides you through implementing hreflang tags for a multilingual website from start to finish.

Prerequisites

Step 1: Audit Your Current Language Versions

import requests
from bs4 import BeautifulSoup

def audit_language_versions(site_url, expected_locales):
    results = []
    for locale in expected_locales:
        url = f"{site_url}/{locale}"
        try:
            response = requests.get(url, timeout=10)
            soup = BeautifulSoup(response.text, "html.parser")
            hreflang_tags = soup.find_all("link", rel="alternate", hreflang=True)
            results.append({
                "locale": locale,
                "url": url,
                "status": response.status_code,
                "existing_hreflang_count": len(hreflang_tags)
            })
        except Exception as e:
            results.append({"locale": locale, "error": str(e)})
    return results

Step 2: Choose Implementation Method

Site Size Recommended Method
< 100 pages per language HTML link tags
100-10,000 pages per language XML sitemap
> 10,000 pages per language XML sitemap + partial HTML

Step 3: Implement HTML Link Tags

<head>
  <link rel="alternate" hreflang="en" href="https://example.com/en/about" />
  <link rel="alternate" hreflang="de" href="https://example.com/de/ueber-uns" />
  <link rel="alternate" hreflang="fr" href="https://example.com/fr/a-propos" />
  <link rel="alternate" hreflang="ja" href="https://example.com/ja/about" />
  <link rel="alternate" hreflang="x-default" href="https://example.com/en/about" />
  <link rel="canonical" href="https://example.com/en/about" />
</head>

Step 4: Generate XML Sitemap with Hreflang

import xml.etree.ElementTree as ET

def generate_hreflang_sitemap(pages, locales, base_url):
    urlset = ET.Element("urlset")
    urlset.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
    urlset.set("xmlns:xhtml", "http://www.w3.org/1999/xhtml")
    for page in pages:
        url_elem = ET.SubElement(urlset, "url")
        loc = ET.SubElement(url_elem, "loc")
        loc.text = f"{base_url}/{locales[0]}/{page[