diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index beaf507..6805c07 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -15,6 +15,9 @@ interface Props { // When provided, the language switch links to it; otherwise it falls back to // the section landing page (/ for EN, /zh/ for ZH). switchHref?: string; + // Absolute URL of the other-language version of THIS page (built by each + // page) — drives hreflang so EN/ZH twins don't compete for the same query. + altLocaleUrl?: string; article?: { publishedTime: string; modifiedTime?: string; @@ -30,12 +33,23 @@ const { ogImage = '/og-default.png', type = 'website', switchHref, + altLocaleUrl, article, } = Astro.props; const canonical = new URL(Astro.url.pathname, SITE.url).href; const ogImageUrl = new URL(ogImage, SITE.url).href; +// hreflang: only emitted when the page has a known counterpart in the other +// language. x-default points at the English version (English-first site). +const hreflang = altLocaleUrl + ? [ + { hreflang: 'en', href: lang === 'en' ? canonical : altLocaleUrl }, + { hreflang: 'zh', href: lang === 'zh' ? canonical : altLocaleUrl }, + { hreflang: 'x-default', href: lang === 'en' ? canonical : altLocaleUrl }, + ] + : []; + // Language switcher: opposite of current page lang. // If a per-page translation link is provided, use it; else fall back to the section landing. const isZh = lang === 'zh'; @@ -59,6 +73,11 @@ const nav = isZh + + {hreflang.map((alt) => ( + + ))} + @@ -69,6 +88,7 @@ const nav = isZh + {lang === 'zh' && } @@ -101,6 +121,7 @@ const nav = isZh