/astro-i18n-aut

The i18n integration for Astro πŸ§‘β€πŸš€

Primary LanguageTypeScriptMIT LicenseMIT

astro-i18n-aut The i18n integration for Astro πŸ§‘β€πŸš€

astro-i18n-aut

Built with ❀️ for all Astro crewmates πŸ§‘β€πŸš€

Total Downloads Latest Release License


Motivation

Provide an internationalization (i18n) integration for Astro that:

  • Supports the defaultLocale
  • Avoids template file duplication
  • Is adapter agnostic
  • Is UI framework agnostic
  • Is compatible with @astrojs/sitemap

Quick start

Install

Install via npm:

npm install astro-i18n-aut

Configure

In your Astro config file:

import { defineConfig } from "astro/config";
import i18n from "astro-i18n-aut";
import sitemap from "@astrojs/sitemap";

const defaultLocale = "en";
const locales = {
  en: "en-US", // the `defaultLocale` value must present in `locales` keys
  es: "es-ES",
  fr: "fr-CA",
};

export default defineConfig({
  site: "https://example.com",
  trailingSlash: "always",
  build: {
    format: "directory",
  },
  integrations: [
    i18n({
      locales,
      defaultLocale,
    }),
    sitemap({
      i18n: {
        locales,
        defaultLocale,
      },
    }),
  ],
});

Usage

Now that you have set up the config, each .astro page will have additional renders with your other languages. For example, src/pages/about.astro will render as:

  • /about
  • /es/about
  • /fr/about

Please note that the getStaticPaths() function will only run once. This limitation means that you cannot have translated urls, such as /es/acerca-de for /about. However, it also ensures compatibility with @astrojs/sitemap.

The Astro frontmatter and page content is re-run for every translated page. For example, the Astro.url.pathname will be:

  • /about
  • /es/about
  • /fr/about

It is up to you to detect which language is being rendered. You can use Astro content collections or any i18n UI framework, such as react-i18next, for your translations. Here is a pure Hello World example:

---
import Layout from "../layouts/Layout.astro";

const locale = Astro.url.pathname.slice(1, 3);

let title: string;
switch (locale) {
  case "es":
    title = "Β‘Hola Mundo!";
    break;
  case "fr":
    title = "Bonjour Monde!";
    break;
  default:
    title = "Hello World!";
}
---

<Layout title={title}>
  <h1>{title}</h1>
</Layout>

Options

  • include: glob pattern(s) to include (default: ["pages/**/*"])
  • exclude: glob pattern(s) to exclude (default: ["pages/api/**/*"])

Other Astro page file types:

  • βœ… .astro
  • ❌ .md
  • ❌ .mdx (with the MDX Integration installed)
  • ❌ .html
  • ❌ .js / .ts (as endpoints)

cannot be translated. If you choose to use them, please add them to the ignore glob patterns. For example, ["pages/api/**/*", "pages/**/*.md"]

License

MIT Licensed

Contributing

PRs welcome! Thank you for your contributions.

The How

Unfortunately, i18n is not a first-class concern for Astro. While Astro documents i18n in their cookbook, they do not support a defaultLocale.

The other community integrations that Astro links do not support all adapters:

  • astro-i18next An Astro integration for i18next including some utility components.
  • astro-i18n A TypeScript-first internationalization library for Astro.

Astro does not easily support two pages having the same content:

  • Route variables /[lang]/about cannot be undefined or an empty string
  • Middleware request.url is read-only, so it is not possible to retrieve content from a different url
  • Configured redirects do not support route transitions like '/article': '/blog/[...slug]', only '/blog/[...slug]': '/articles/[...slug]'
  • The injectRoute method cannot inject an entryPoint that is already being used in the build command

We duplicate the src/pages folder multiple times and use injectRoute as a workaround. You can safely delete any src/astro_tmp_pages_LOCALE folders, but those will be automatically cleaned on every started and completed build.