多语言
在 Astro 配置里设置 i18n,minidocs 就会按语言组织内容,为每种语言生成页面。这一页讲多语言站点和单语言站点的不同之处。
配置
// astro.config.mjs
export default defineConfig({
i18n: { locales: ['zh', 'en'], defaultLocale: 'zh' },
integrations: [mdx(), minidocs()],
});
默认语言的地址不带语言段,比如 /docs/;其他语言带,比如 /en/docs/。想让默认语言也带上,设置 Astro 的 routing: { prefixDefaultLocale: true }。
locales 只支持字符串,routing: 'manual' 也还不支持。没有翻译的页面怎么显示,用下文 minidocs 的 fallback 声明,不要用 Astro 的 i18n.fallback。
内容
集合的第一级目录是语言:
src/content/docs/
├── zh/
│ ├── index.mdx
│ └── guides/sidebar.mdx
└── en/
├── index.mdx
└── guides/sidebar.mdx
页面 id 不含语言,两种语言里的 guides/sidebar.mdx 是同一个页面 guides/sidebar 的两个版本。
路由和数据
和单语言站点相比,有三处不同:
- 路由文件前面多一层
[...locale],比如src/pages/[...locale]/docs/[...slug].astro,page.params里多了locale defineTree返回每种语言一棵树,渲染时用tree[locale]toHref要传语言:toHref('docs', 'guides/sidebar', locale)
listPages 返回的每个页面都带着 locale,就是它所在的语言,布局里直接用:
---
const { id, locale } = Astro.props;
const nav = navState(tree[locale], id);
---
<html lang={locale}>
没有翻译的页面
页面还没有翻译时,可以先显示另一种语言的内容:
minidocs({ fallback: { en: 'zh' } })
这样英文站上缺的页面会显示中文内容,地址仍然在英文站下,页头、侧边栏这些界面也还是英文。可以依次列出几种语言,按顺序找:{ 'zh-tw': ['zh', 'en'] }。
显示的是另一种语言的内容时,页面的 isFallback 是 true,contentLocale 是内容实际的语言。可以借此提示读者,并让搜索引擎指向原文:
---
const { id, isFallback, contentLocale } = Astro.props;
---
{isFallback && <link rel="canonical" href={toHref('docs', id, contentLocale)} />}
{isFallback && (
<Callout.Root>
This page is not translated yet. <a href={toHref('docs', id, contentLocale)}>View the original</a>
</Callout.Root>
)}
没有声明 fallback 时,缺翻译的页面在那种语言里就不存在。dir() 会跳过它;page() 引用它时,构建会报错。
语言切换器
每个页面的 alternates 列出它存在的所有语言和对应的地址,包括当前语言:
---
const { locale, alternates } = Astro.props;
---
<nav aria-label="Language">
{alternates.map((alt) => (
<a href={alt.href} hreflang={alt.locale} aria-current={alt.locale === locale ? 'true' : undefined}>
{alt.locale}
</a>
))}
</nav>
同样的数据也可以写进 <head>:<link rel="alternate" hreflang={alt.locale} href={alt.href} />。
站点自己的页面
首页这类不来自集合的页面,也放在 [...locale] 下面,用 toLocaleParam 为每种语言生成一份:
---
// src/pages/[...locale]/index.astro
import { type Locale, toLocaleParam } from '@minidocs/astro/runtime';
const locales: Locale[] = ['zh', 'en'];
export function getStaticPaths() {
return locales.map((locale) => ({ params: { locale: toLocaleParam(locale) }, props: { locale } }));
}
---
默认语言不带语言段时,toLocaleParam 返回 undefined,生成的就是 /。
404 页面放在 src/pages/404.astro,不放在 [...locale] 下面,因为托管平台通常只认站点根目录的 404.html。
正文里的链接
正文里链接到同一个语言目录里的文件,链接就留在这种语言里,没有翻译的页面也是如此,见正文里的链接。