diff --git a/astro.config.mjs b/astro.config.mjs index fd294ce..d72fd9c 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,11 +2,22 @@ import { defineConfig } from 'astro/config'; import sitemap from '@astrojs/sitemap'; +const languages = ['en', 'ja']; + // https://astro.build/config export default defineConfig({ site: 'https://docs.vivliostyle.org', output: 'static', - integrations: [sitemap()], + integrations: [sitemap({ + filter: (page) => { + const url = new URL(page); + return languages.includes(url.pathname.split('/')[1]); + }, + i18n: { + defaultLocale: 'en', + locales: Object.fromEntries(languages.map((lang) => [lang, lang])), + }, + })], build: { format: 'directory', }, diff --git a/src/layouts/DocsLayout.astro b/src/layouts/DocsLayout.astro index 4c2ccf5..b4fec7e 100644 --- a/src/layouts/DocsLayout.astro +++ b/src/layouts/DocsLayout.astro @@ -12,9 +12,10 @@ interface Props { description?: string; lang?: string; showBreadcrumb?: boolean; + availableLanguages?: ('en' | 'ja')[]; } -const { title, description = '', lang = 'en', showBreadcrumb = true } = Astro.props; +const { title, description = '', lang = 'en', showBreadcrumb = true, availableLanguages = [] } = Astro.props; const currentPath = Astro.url.pathname; --- @@ -25,6 +26,15 @@ const currentPath = Astro.url.pathname; {title} | Vivliostyle Documentation + + {availableLanguages.map((language) => ( + + ))} + diff --git a/src/layouts/LanguageSwitchLayout.astro b/src/layouts/LanguageSwitchLayout.astro new file mode 100644 index 0000000..db7f53c --- /dev/null +++ b/src/layouts/LanguageSwitchLayout.astro @@ -0,0 +1,58 @@ +--- +/** + * 言語切り替えレイアウト - 言語検出とリダイレクト + * + * Accept-Languageヘッダーを確認し、適切な言語ページにリダイレクト。 + * SSRが必要な場合はクライアントサイドで処理。 + */ + +interface Props { + targetPath: string; + availableLanguages?: ('en' | 'ja')[]; + defaultLanguage?: 'en' | 'ja'; +} + +const { + targetPath, + availableLanguages = ['en', 'ja'], + defaultLanguage = 'en', +} = Astro.props; +--- + + + + + + Vivliostyle Documentation + + + + + + + + +

Welcome to the documentation. Please navigate to English documentation.

+ + diff --git a/src/pages/[...slug].astro b/src/pages/[...slug].astro new file mode 100644 index 0000000..78d9481 --- /dev/null +++ b/src/pages/[...slug].astro @@ -0,0 +1,69 @@ +--- +import LanguageSwitchLayout from '../layouts/LanguageSwitchLayout.astro'; + +export async function getStaticPaths() { + const languages = ['en', 'ja'] as const; + const pageComponents = Object.entries( + import.meta.glob<{ + getStaticPaths?: () => Promise< + { params: { slug: string | undefined } }[] + >; + }>('./**/*.astro', { eager: true }) + ).flatMap((it) => { + const [key, value] = it; + const { getStaticPaths } = value; + const matched = /^\.\/(\w+)\/(.+\/)[^/]+\.astro$/.exec(key); + if (!getStaticPaths || !matched) { + return []; + } + const [, language, path] = matched; + if (!languages.includes(language as (typeof languages)[number])) { + return []; + } + return [ + { + getStaticPaths, + language: language as (typeof languages)[number], + path, + } as const, + ]; + }); + + const pages = ( + await Promise.all( + pageComponents.map(async ({ getStaticPaths, ...rest }) => ({ + ...rest, + staticPaths: await getStaticPaths(), + })) + ) + ).flatMap(({ staticPaths, path, language }) => + staticPaths.map(({ params }) => ({ + language, + slug: `${path}${params.slug ?? ''}`, + })) + ); + const allSlugs = new Set(pages.map(({ slug }) => slug)); + return Array.from(allSlugs).map((slug) => { + const availableLanguages = pages.flatMap((page) => + page.slug === slug ? [page.language] : [] + ); + return { + params: { slug }, + props: { + availableLanguages, + defaultLanguage: availableLanguages.includes('en') + ? 'en' + : availableLanguages[0], + }, + }; + }); +} + +const { availableLanguages, defaultLanguage } = Astro.props; +--- + + diff --git a/src/pages/en/cli/[...slug].astro b/src/pages/en/cli/[...slug].astro index 67f3446..97b8d85 100644 --- a/src/pages/en/cli/[...slug].astro +++ b/src/pages/en/cli/[...slug].astro @@ -88,7 +88,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null; const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null; --- - +
diff --git a/src/pages/en/index.astro b/src/pages/en/index.astro index 8322f8f..7daf517 100644 --- a/src/pages/en/index.astro +++ b/src/pages/en/index.astro @@ -36,7 +36,12 @@ const title = indexDoc?.data?.title || 'Welcome to Vivliostyle Documentation'; const description = indexDoc?.data?.description || 'Official documentation for Vivliostyle'; --- - +