Skip to main content
aapp-hacks
← Back to articles
Author
app-hacks
Published
Updated
Reviewed

SEO / i18n / Astro

canonical, hreflang, and x-default for Multilingual Sites

Set self-referencing canonicals, language URLs, and x-default consistently to prevent multilingual URL and reference mistakes.

canonical, hreflang, and x-default for Multilingual Sites

Do not treat a canonical and hreflang as the same instruction. A canonical identifies the preferred URL for the current page. hreflang identifies an equivalent page available in another language. Pointing a Japanese page’s canonical at its English version mixes those two roles.

This article uses a static site where Japanese is the default URL and English is under /en/.

Each language page uses a self-referencing canonical while hreflang connects the Japanese and English equivalents.

Make Every Canonical Self-Referencing

For a Japanese article at https://app-hacks.net/blog/example/ and its English version at https://app-hacks.net/en/blog/example/, each page identifies itself.

<!-- Japanese page -->
<link rel="canonical" href="https://app-hacks.net/blog/example/">

<!-- English page -->
<link rel="canonical" href="https://app-hacks.net/en/blog/example/">

The pages serve different language audiences even when their content corresponds. Keep protocol, hostname, and trailing-slash conventions consistent with the site’s chosen URL format.

Connect Existing Language Versions with hreflang

When both versions exist, emit ja, en, and x-default as one set.

<link rel="alternate" hreflang="ja" href="https://app-hacks.net/blog/example/">
<link rel="alternate" hreflang="en" href="https://app-hacks.net/en/blog/example/">
<link rel="alternate" hreflang="x-default" href="https://app-hacks.net/blog/example/">

x-default identifies the default URL for people who do not match a specific language or region. In this structure it is the Japanese URL. It does not redirect a browser; offer language links separately so the visitor controls navigation.

Centralize URL Construction

Building URLs differently in article, index, and static-page templates creates small inconsistencies, such as a missing slash or a development host in a published tag. Put canonical and alternate-link output in one shared component. A page then supplies its canonical URL, language, and known alternate path.

<SEOHead
  canonical={canonicalUrl}
  lang="ja"
  alternatePath={`/en/blog/${post.id}/`}
/>

The English page passes lang="en" and its Japanese alternate. Never emit an inferred alternate for a translation that does not exist. A nonexistent URL gives readers and crawlers a false relationship.

Verify the Built HTML in Both Languages

Source code alone cannot prove the URLs that were generated. After npm run build, inspect one Japanese/English pair.

rg -n 'canonical|hreflang' \
  dist/blog/example/index.html \
  dist/en/blog/example/index.html

Check that every canonical is the page’s own HTTPS URL, both documents name the same two alternate URLs, the x-default matches the site policy, and no localhost, preview, or untranslated URL appears. Repeat this check when a page type or language is added. Keeping self-canonical URLs separate from language relationships makes the metadata easier to maintain.