Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion scripts/docs-site/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ function layout({ page, nav, activeTab, html, toc, prev, next }) {
<meta name="description" content="${escapeAttr(description)}">
<title>${escapeHtml(title)}</title>
${canonicalUrl ? `<link rel="canonical" href="${escapeAttr(canonicalUrl)}">` : ""}
${page.hidden ? '<meta name="robots" content="noindex,nofollow">' : ""}
${hreflangLinks(page)}${page.hidden ? '<meta name="robots" content="noindex,nofollow">' : ""}
<meta property="og:type" content="website">
<meta property="og:site_name" content="${escapeAttr(config.name)}">
<meta property="og:title" content="${escapeAttr(ogTitle)}">
Expand Down Expand Up @@ -909,6 +909,28 @@ function pageRoute(page) {
return page.slug === "index" ? (prefix || "/") : `${prefix}/${page.slug}`;
}

function hreflangLinks(page) {
// hreflang alternates require absolute URLs; skip when no canonical origin is set
// or when the page is excluded from indexing.
if (!canonicalOrigin || page.hidden) return "";
// Collect every locale that publishes this same slug, using the current page for
// its own locale and skipping any locale variant that is itself hidden.
const variants = [];
for (const locale of locales) {
const variant = locale.code === page.locale ? page : allPageByKey.get(pageKey(locale.code, page.slug));
if (variant && !variant.hidden) variants.push(variant);
}
// Nothing to cross-link if the page exists in only one locale.
if (variants.length < 2) return "";
const links = variants.map(
(variant) => `<link rel="alternate" hreflang="${escapeAttr(htmlLang(variant.locale))}" href="${escapeAttr(`${canonicalOrigin}${pageRoute(variant)}`)}">`,
);
// x-default points at the English variant when available, otherwise the current page.
const defaultPage = variants.find((variant) => variant.locale === "en") ?? page;
links.push(`<link rel="alternate" hreflang="x-default" href="${escapeAttr(`${canonicalOrigin}${pageRoute(defaultPage)}`)}">`);
return `${links.join("\n")}\n`;
}

function pageMarkdownRoute(page) {
const prefix = page.locale === "en" ? "" : `/${page.locale}`;
return page.slug === "index" ? `${prefix || ""}/index.md` : `${prefix}/${page.slug}.md`;
Expand Down
15 changes: 15 additions & 0 deletions scripts/docs-site/smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,28 @@ if (!/class="tab-link active" href="(?:\/docs)?\/it\/channels"/.test(itChannels)
if (!/<section class="nav-section"><h2>Overview<\/h2>/.test(itChannels)) {
throw new Error("it channels: localized sidebar is missing");
}
if (!itChannels.includes(`<link rel="alternate" hreflang="it" href="${expectedOrigin}/it/channels">`)) {
throw new Error("it channels: self-referential hreflang alternate is missing");
}
if (!itChannels.includes(`<link rel="alternate" hreflang="en" href="${expectedOrigin}/channels">`)) {
throw new Error("it channels: hreflang alternate back to English is missing");
}
if (!itChannels.includes(`<link rel="alternate" hreflang="x-default" href="${expectedOrigin}/channels">`)) {
throw new Error("it channels: x-default hreflang alternate is missing");
}
const index = fs.readFileSync(path.join(site, "index.html"), "utf8");
if (!index.includes(`<link rel="canonical" href="${expectedOrigin}/">`)) {
throw new Error(`index: canonical link should use ${expectedOrigin}`);
}
if (!index.includes(`<meta property="og:url" content="${expectedOrigin}/">`)) {
throw new Error(`index: og:url should use ${expectedOrigin}`);
}
if (!index.includes(`<link rel="alternate" hreflang="en" href="${expectedOrigin}/">`)) {
throw new Error("index: self-referential hreflang alternate is missing");
}
if (!index.includes(`<link rel="alternate" hreflang="x-default" href="${expectedOrigin}/">`)) {
throw new Error("index: x-default hreflang alternate is missing");
}
const gettingStarted = fs.readFileSync(path.join(site, "start/getting-started/index.html"), "utf8");
const gettingStartedOgImage = `${expectedOrigin}/og/start/getting-started.png`;
if (!fs.existsSync(path.join(site, "og/start/getting-started.png"))) {
Expand Down