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
13 changes: 12 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
Expand Down
12 changes: 11 additions & 1 deletion src/layouts/DocsLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -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;
---
<!DOCTYPE html>
Expand All @@ -25,6 +26,15 @@ const currentPath = Astro.url.pathname;
<meta name="description" content={description}>
<title>{title} | Vivliostyle Documentation</title>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="canonical" href={`${Astro.url.origin}${currentPath}`}>
{availableLanguages.map((language) => (
<link
rel="alternate"
hreflang={language}
href={`${Astro.url.origin}/${language}${currentPath.replace(/^\/[^/]+/, '')}`}
/>
))}
<link rel="sitemap" href="/sitemap-index.xml">
<link rel="stylesheet" href="/styles/global.css">
<!-- Prism.js syntax highlighting -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css" media="(prefers-color-scheme: light)">
Expand Down
58 changes: 58 additions & 0 deletions src/layouts/LanguageSwitchLayout.astro
Original file line number Diff line number Diff line change
@@ -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;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vivliostyle Documentation</title>
<meta name="robots" content="noindex">
<link rel="canonical" href={`${Astro.url.origin}/${defaultLanguage}${targetPath}`}>
<link rel="stylesheet" href="/styles/global.css">
<script data-target-path={targetPath} data-supported-languages={availableLanguages.join(',')} data-default-language={defaultLanguage}>
// 言語検出とリダイレクト
(function() {
const supportedLangs = document.currentScript.getAttribute('data-supported-languages').split(',');
const defaultLang = document.currentScript.getAttribute('data-default-language');

// ブラウザの言語設定を取得
const browserLang = navigator.language || '';
const langCode = browserLang.split('-')[0].toLowerCase();

// サポートされている言語かチェック
const targetLang = supportedLangs.includes(langCode) ? langCode : defaultLang;

// リダイレクト
const targetPath = document.currentScript.getAttribute('data-target-path');
window.location.replace(`/${targetLang}${targetPath}`);
})();
</script>
<noscript>
<meta http-equiv="refresh" content={`0; url=/${defaultLanguage}${targetPath}`}>
</noscript>
</head>
<body>
<noscript>
<meta http-equiv="refresh" content={`0; url=/${defaultLanguage}${targetPath}`}>
</noscript>
<p style="font-size: 0">Welcome to the documentation. Please navigate to <a href={`/${defaultLanguage}${targetPath}`}>English documentation</a>.</p>
</body>
</html>
69 changes: 69 additions & 0 deletions src/pages/[...slug].astro
Original file line number Diff line number Diff line change
@@ -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;
---

<LanguageSwitchLayout
targetPath={`/${Astro.params.slug}/`}
availableLanguages={availableLanguages}
defaultLanguage={defaultLanguage}
/>
7 changes: 6 additions & 1 deletion src/pages/en/cli/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout title={title} description={description} lang="en">
<DocsLayout
title={title}
description={description}
lang="en"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<div slot="header" class="language-switcher-container">
<LanguageSwitcher currentLang="en" pagePath={pagePath} hasTranslation={hasJaTranslation} />
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/pages/en/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ const title = indexDoc?.data?.title || 'Welcome to Vivliostyle Documentation';
const description = indexDoc?.data?.description || 'Official documentation for Vivliostyle';
---

<DocsLayout title={title} description={description} lang="en">
<DocsLayout
title={title}
description={description}
lang="en"
availableLanguages={['en', 'ja']}
>
<LanguageSwitcher slot="header" currentLang="en" pagePath="/" hasTranslation={true} />
<nav slot="sidebar">
<h3>Documentation</h3>
Expand Down
5 changes: 3 additions & 2 deletions src/pages/en/reference/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ for (let i = currentIndex + 1; i < sortedDocs.length; i++) {
}
---

<DocsLayout
title={title}
<DocsLayout
title={title}
description={description}
lang="en"
section="reference"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<!-- Language switcher in header -->
{hasJaTranslation && (
Expand Down
3 changes: 2 additions & 1 deletion src/pages/en/reference/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ const description = indexDoc?.data?.description || 'Reference documentation for
---

<DocsLayout
title={title}
title={title}
description={description}
lang="en"
section="reference"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<!-- Language switcher in header -->
{hasJaTranslation && (
Expand Down
7 changes: 6 additions & 1 deletion src/pages/en/themes/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout title={title} description={description} lang="en">
<DocsLayout
title={title}
description={description}
lang="en"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<div slot="header" class="language-switcher-container">
<LanguageSwitcher currentLang="en" pagePath={pagePath} hasTranslation={hasJaTranslation} />
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/pages/en/vfm/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout title={title} description={description} lang="en">
<DocsLayout
title={title}
description={description}
lang="en"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<div slot="header" class="language-switcher-container">
<LanguageSwitcher currentLang="en" pagePath={pagePath} hasTranslation={hasJaTranslation} />
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/pages/en/viewer/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout
title={title}
<DocsLayout
title={title}
description={description}
lang="en"
section="viewer"
availableLanguages={hasJaTranslation ? ['en', 'ja'] : []}
>
<!-- ヘッダーに言語切り替え -->
{hasJaTranslation && (
Expand Down
43 changes: 3 additions & 40 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,42 +1,5 @@
---
/**
* ルートページ - 言語検出とリダイレクト
*
* Accept-Languageヘッダーを確認し、適切な言語ページにリダイレクト。
* SSRが必要な場合はクライアントサイドで処理。
*/
import LanguageSwitchLayout from '../layouts/LanguageSwitchLayout.astro';
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vivliostyle Documentation</title>
<script>
// 言語検出とリダイレクト
(function() {
const supportedLangs = ['en', 'ja'];
const defaultLang = 'en';

// ブラウザの言語設定を取得
const browserLang = navigator.language || '';
const langCode = browserLang.split('-')[0].toLowerCase();

// サポートされている言語かチェック
const targetLang = supportedLangs.includes(langCode) ? langCode : defaultLang;

// リダイレクト
window.location.replace('/' + targetLang + '/');
})();
</script>
<noscript>
<meta http-equiv="refresh" content="0; url=/en/">
</noscript>
</head>
<body>
<noscript>
<meta http-equiv="refresh" content="0; url=/en/">
</noscript>
<p>Welcome to the documentation. Please navigate to <a href="/en/">English documentation</a>.</p>
</body>
</html>

<LanguageSwitchLayout targetPath="/" />
7 changes: 6 additions & 1 deletion src/pages/ja/cli/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout title={title} description={description} lang="ja">
<DocsLayout
title={title}
description={description}
lang="ja"
availableLanguages={hasEnTranslation ? ['en', 'ja'] : []}
>
<div slot="header" class="language-switcher-container">
<LanguageSwitcher currentLang="ja" pagePath={pagePath} hasTranslation={hasEnTranslation} />
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/pages/ja/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ const title = indexDoc?.data?.title || 'Vivliostyle ドキュメントへよう
const description = indexDoc?.data?.description || 'Vivliostyle公式ドキュメント';
---

<DocsLayout title={title} description={description} lang="ja">
<DocsLayout
title={title}
description={description}
lang="ja"
availableLanguages={['en', 'ja']}
>
<LanguageSwitcher slot="header" currentLang="ja" pagePath="/" hasTranslation={true} />
<nav slot="sidebar">
<h3>ドキュメント</h3>
Expand Down
5 changes: 3 additions & 2 deletions src/pages/ja/reference/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ for (let i = currentIndex + 1; i < sortedDocs.length; i++) {
}
---

<DocsLayout
title={title}
<DocsLayout
title={title}
description={description}
lang="ja"
section="reference"
availableLanguages={hasEnTranslation ? ['en', 'ja'] : []}
>
<!-- ヘッダーに言語切り替え -->
{hasEnTranslation && (
Expand Down
5 changes: 3 additions & 2 deletions src/pages/ja/reference/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ const title = indexDoc?.data?.title || 'リファレンス';
const description = indexDoc?.data?.description || 'Vivliostyle関連ドキュメントのリファレンス集';
---

<DocsLayout
title={title}
<DocsLayout
title={title}
description={description}
lang="ja"
section="reference"
availableLanguages={hasEnTranslation ? ['en', 'ja'] : []}
>
<!-- ヘッダーに言語切り替え -->
{hasEnTranslation && (
Expand Down
7 changes: 6 additions & 1 deletion src/pages/ja/themes/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,12 @@ const prevPage = currentIndex > 0 ? sortedDocs[currentIndex - 1] : null;
const nextPage = currentIndex < sortedDocs.length - 1 ? sortedDocs[currentIndex + 1] : null;
---

<DocsLayout title={title} description={description} lang="ja">
<DocsLayout
title={title}
description={description}
lang="ja"
availableLanguages={hasEnTranslation ? ['en', 'ja'] : []}
>
<div slot="header" class="language-switcher-container">
<LanguageSwitcher currentLang="ja" pagePath={pagePath} hasTranslation={hasEnTranslation} />
</div>
Expand Down
Loading