2 min read

Astro 国际化:数据集合的默认语言路径格式

Astro 框架原生支持 国际化 特性,可以快速创建多语言版本的网站,但对于内容集合的国际化有一点小问题。根据官方指南的建议,使用 /src/pages/[locale]/blog/[...slug].astro 的方式为内容集合增加多语言支持时,其中 [locale] 部分是必须的,从而使得即使是默认语言的链接也是带语言前缀的。

我希望用户在使用默认语言时,所访问的 URL 中不存在语言前缀。例如,名为 quotes 的数据集合,如果用户使用默认语言 en 时,访问链接应该是 https://tireless.dev/quotes/quote-1,而不是 https://tireless.dev/en/quotes/quote-1,后者看起来相当违反直觉。

解决方案是创建两个动态页面模板,分别过滤并展示数据集的默认语言子集,和其它语言子集。

src/pages/quotes/[id].astro 用于默认语言。

---
...
export async function getStaticPaths() {
  return (await getCollection("quotes"))
    .filter(
      (quote) =>
        !startsWithLanguages(quote.id) ||
        startsWithLanguage(quote.id, defaultLang)
    )
    .map((quote) => ({
      params: { id: stripLangPrefix(quote.id) },
      props: { quote },
    }));
}

const { quote } = Astro.props;
---

<QuotePage quote={quote} locale={defaultLang} />

src/pages/[locale]/quotes/[id].astro 用于其它语言。

---
...
export async function getStaticPaths() {
  return (await getCollection("quotes"))
    .filter((quote) => startsWithLanguages(quote.id))
    .map((quote) => {
      const [lang, ...slug] = quote.id.split("/");
      return {
        params: { locale: lang as Lang, id: slug.join("/") || undefined },
        props: { quote },
      };
    });
}

const { locale } = Astro.params;
const { quote } = Astro.props;
---

<QuotePage quote={quote} locale={locale} />

数据集合的内容组织,默认语言内容可以放在相应的语言目录,也可以不创建单独目录。

  • src/conent/quotes
    • quote-1.md
    • en
      • quote-2.md
    • zh
      • quote-1.md
      • quote-2.md

完整的示例代码请参考 样例项目