diff --git a/src/content.config.ts b/src/content.config.ts
index c94a30a..c35b6ba 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -21,6 +21,9 @@ const posts = defineCollection({
// lang is NOT set in frontmatter anymore — it's derived from the folder:
// posts/hello-world.md -> en (flat)
// posts/zh/hello-world.md -> zh (subfolder)
+ // Explicit link to the other-language version (its full slug, e.g. "zh/how-i-host-this-blog").
+ // When absent, the language switch falls back to the section landing page (/ or /zh/).
+ translation: z.string().optional(),
ogImage: z.string().optional(),
}),
});
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index 47d84d5..8e82335 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -10,6 +10,10 @@ interface Props {
lang?: string;
ogImage?: string;
type?: 'website' | 'article';
+ // Optional: direct URL of this page's translation (the other-language version).
+ // When provided, the language switch links to it; otherwise it falls back to
+ // the section landing page (/ for EN, /zh/ for ZH).
+ switchHref?: string;
article?: {
publishedTime: string;
modifiedTime?: string;
@@ -24,6 +28,7 @@ const {
lang = SITE.lang,
ogImage = '/og-default.png',
type = 'website',
+ switchHref,
article,
} = Astro.props;
@@ -31,9 +36,9 @@ const canonical = new URL(Astro.url.pathname, SITE.url).href;
const ogImageUrl = new URL(ogImage, SITE.url).href;
// Language switcher: opposite of current page lang.
-// English pages link to /zh/ (Chinese landing); Chinese pages link back to /.
+// If a per-page translation link is provided, use it; else fall back to the section landing.
const isZh = lang === 'zh';
-const switchHref = isZh ? '/' : '/zh/';
+const resolvedSwitchHref = switchHref ?? (isZh ? '/' : '/zh/');
const switchLabel = isZh ? 'EN' : '中文';
---
@@ -127,7 +132,7 @@ const switchLabel = isZh ? 'EN' : '中文';
categories
about
rss
- {switchLabel}
+ {switchLabel}
diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro
index 2ff06ad..41615e2 100644
--- a/src/pages/posts/[...slug].astro
+++ b/src/pages/posts/[...slug].astro
@@ -37,6 +37,14 @@ const related = all
.sort((a, b) => b.score - a.score)
.slice(0, 3)
.map((r) => r.post);
+
+// Translation link for the language switch:
+// 1. Explicit `translation` field wins.
+// 2. Else auto-match the other-language slug (strip/add the `zh/` prefix).
+const otherLangSlug = lang === 'en' ? `zh/${post.slug}` : post.slug.replace(/^zh\//, '');
+const translation = post.data.translation
+ ?? (all.some((p) => p.slug === otherLangSlug) ? otherLangSlug : undefined);
+const switchHref = translation ? `/posts/${translation}/` : undefined;
---