Astro Integration

Learn how to integrate i18next with Astro websites for internationalization.

Integrate i18next with your Astro website to support multiple languages using Lengrise-managed translations, with both server-side rendering and client-side capabilities.

Prerequisites

  • Astro project (v2.0.0+)
  • Node.js (v16.0.0+)
  • Package manager (npm, yarn, or pnpm)
  • Translations downloaded from Lengrise

Pull Translation Files

First, you must pull your translation files from Lengrise API. These files will contain all the translated text for your application.

  1. Go to the Installation Guide and follow the steps to download your translations
  2. Place the downloaded JSON files in your project as shown in the project structure below
  3. Ensure that each language has its own JSON file named with the language code (e.g., en.json, es.json)

Integration Setup

After downloading your translation files, install the necessary i18next packages:

javascript npm install astro-i18next i18next --save

Project Structure

package.jsonadd
astro.config.mjsadd
astro-i18next.config.mjsadd
tsconfig.jsonadd
srcadd
pagesadd
index.astroadd
[...slug].astroadd
esadd
index.astroadd
componentsadd
Layout.astroadd
LanguageSwitcher.astroadd
layoutsadd
MainLayout.astroadd
publicadd
localesadd
en.jsonadd
es.jsonadd

Configuration Steps

1. Configure astro-i18next

Create a file called astro-i18next.config.mjs in your project root:

/** @type {import('astro-i18next').AstroI18nextConfig} */
export default {
  defaultLocale: "en",
  locales: ["en", "es"],
  load: ["server", "client"], // Load translations on both server and client
  i18nextServer: {
    debug: false, // Set to true during development
    initImmediate: false,
    backend: {
      loadPath: "./public/locales/{{lng}}.json",
    },
  },
  i18nextClient: {
    debug: false, // Set to true during development
  },
  routing: {
    prefixDefaultLocale: false, // Don't add a prefix for the default locale (e.g., /en/page)
  },
};

2. Update astro.config.mjs

Update your astro.config.mjs file to integrate the i18next plugin:

import { defineConfig } from "astro/config";
import astroI18next from "astro-i18next";

// https://astro.build/config
export default defineConfig({
  integrations: [astroI18next()],
});

3. Create a Language Switcher Component

Create a file at src/components/LanguageSwitcher.astro:

---
import { t, localizeUrl } from "astro-i18next";
import { localizePath } from "astro-i18next";
import i18next from "i18next";

const currentLocale = i18next.language;
const allLocales = ["en", "es"];
---

<div class="language-switcher">
  <ul>
    {allLocales.map((locale) => (
      <li>
        <a
          href={localizePath(Astro.url.pathname, locale)}
          class={locale === currentLocale ? "active" : ""}
        >
          {locale === "en" ? "English" : "Español"}
        </a>
      </li>
    ))}
  </ul>
</div>

<style>
  .language-switcher {
    margin: 1rem 0;
  }
  ul {
    display: flex;
    list-style-type: none;
    padding: 0;
  }
  li {
    margin-right: 1rem;
  }
  a {
    text-decoration: none;
    color: #333;
  }
  .active {
    font-weight: bold;
    color: #0066cc;
  }
</style>

4. Create a Layout Component

Create a file at src/layouts/MainLayout.astro:

---
import { t } from "astro-i18next";
import LanguageSwitcher from "../components/LanguageSwitcher.astro";

interface Props {
  title?: string;
  description?: string;
}

const { title = "Astro", description = "Astro Site" } = Astro.props;
---

<html lang={i18next.language}>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content={description} />
    <title>{title}</title>
  </head>
  <body>
    <header>
      <h1>{t("site.title")}</h1>
      <nav>
        <ul>
          <li>
            <a href="/">{t("nav.home")}</a>
          </li>
          <li>
            <a href="/blog">{t("nav.blog")}</a>
          </li>
          <li>
            <a href="/about">{t("nav.about")}</a>
          </li>
        </ul>
      </nav>
      <LanguageSwitcher />
    </header>

    <main>
      <slot />
    </main>

    <footer>
      <p>{t("footer.copyright", { year: new Date().getFullYear() })}</p>
    </footer>
  </body>
</html>

<style>
  /* Add your styles here */
  header {
    display: flex;
    flex-direction: column;
    padding: 1rem;
    border-bottom: 1px solid #ddd;
  }

  nav ul {
    display: flex;
    list-style-type: none;
    padding: 0;
  }

  nav li {
    margin-right: 1rem;
  }

  main {
    padding: 1rem;
  }

  footer {
    padding: 1rem;
    border-top: 1px solid #ddd;
    text-align: center;
  }
</style>

5. Create Your Home Page

Create a file at src/pages/index.astro:

---
import { t, changeLanguage } from "astro-i18next";
import MainLayout from "../layouts/MainLayout.astro";

// Set the language to English for this page
changeLanguage("en");
---

<MainLayout title={t("home.title")} description={t("site.description")}>
  <h1>{t("home.welcome")}</h1>
  <p>{t("home.description")}</p>

  <section>
    <h2>{t("features.title")}</h2>
    <ul>
      <li>{t("features.easy")}</li>
      <li>{t("features.fast")}</li>
      <li>{t("features.flexible")}</li>
    </ul>
  </section>

  <!-- Example with parameters -->
  <p>{t("greeting", { name: "Astro Developer" })}</p>
</MainLayout>

6. Create a Spanish Home Page

Create a file at src/pages/es/index.astro:

---
import { t, changeLanguage } from "astro-i18next";
import MainLayout from "../../layouts/MainLayout.astro";

// Set the language to Spanish for this page
changeLanguage("es");
---

<MainLayout title={t("home.title")} description={t("site.description")}>
  <h1>{t("home.welcome")}</h1>
  <p>{t("home.description")}</p>

  <section>
    <h2>{t("features.title")}</h2>
    <ul>
      <li>{t("features.easy")}</li>
      <li>{t("features.fast")}</li>
      <li>{t("features.flexible")}</li>
    </ul>
  </section>

  <!-- Example with parameters -->
  <p>{t("greeting", { name: "Desarrollador Astro" })}</p>
</MainLayout>

Using Translations

In Astro Components

Use the t function from astro-i18next in your Astro components:

---
import { t } from "astro-i18next";
---

<div>
  <h1>{t("welcome.title")}</h1>
  <p>{t("welcome.description")}</p>
</div>

Translations with Parameters

Pass parameters to your translations:

---
import { t } from "astro-i18next";

const username = "John";
const messageCount = 5;
---

<div>
  <p>{t("greeting", { name: username })}</p>
  <p>{t("messages.count", { count: messageCount })}</p>
</div>

Client-Side Components

For client-side components using frameworks like React, Vue, or Svelte:

// src/components/ClientGreeting.jsx
import React from "react";
import { useTranslation } from "react-i18next";

export default function ClientGreeting() {
  const { t } = useTranslation();

  return (
    <div>
      <h2>{t("greeting", { name: "Client" })}</h2>
    </div>
  );
}

Then import it in your Astro component:

---
import { changeLanguage } from "astro-i18next";
import ClientGreeting from "../components/ClientGreeting";

changeLanguage("en");
---

<ClientGreeting client:load />

Path Localization

To localize paths in your templates:

---
import { localizePath } from "astro-i18next";
---

<a href={localizePath("/blog")}>Blog</a>

Translation Examples

Your public/locales/en.json file should contain:

{
  "site": {
    "title": "My Multilingual Astro Site",
    "description": "A website built with Astro and i18next"
  },
  "nav": {
    "home": "Home",
    "blog": "Blog",
    "about": "About"
  },
  "home": {
    "title": "Welcome to My Site",
    "welcome": "Hello, World!",
    "description": "This is a multilingual Astro site."
  },
  "features": {
    "title": "Features",
    "easy": "Easy to use",
    "fast": "Fast translation",
    "flexible": "Flexible integration"
  },
  "greeting": "Hello, {{name}}!",
  "messages": {
    "count": "You have {{count}} message",
    "count_plural": "You have {{count}} messages"
  },
  "footer": {
    "copyright": "© {{year}} My Website. All rights reserved."
  }
}

And your public/locales/es.json file:

{
  "site": {
    "title": "Mi Sitio Astro Multilingüe",
    "description": "Un sitio web construido con Astro e i18next"
  },
  "nav": {
    "home": "Inicio",
    "blog": "Blog",
    "about": "Acerca de"
  },
  "home": {
    "title": "Bienvenido a mi sitio",
    "welcome": "¡Hola, Mundo!",
    "description": "Este es un sitio Astro multilingüe."
  },
  "features": {
    "title": "Características",
    "easy": "Fácil de usar",
    "fast": "Traducción rápida",
    "flexible": "Integración flexible"
  },
  "greeting": "¡Hola, {{name}}!",
  "messages": {
    "count": "Tienes {{count}} mensaje",
    "count_plural": "Tienes {{count}} mensajes"
  },
  "footer": {
    "copyright": "© {{year}} Mi Sitio Web. Todos los derechos reservados."
  }
}

Advanced Features

Handling Dynamic Routes

For dynamic routes like blog posts, create a file at src/pages/[...slug].astro:

---
import { t, changeLanguage } from "astro-i18next";
import MainLayout from "../layouts/MainLayout.astro";
import i18next from "i18next";

export async function getStaticPaths() {
  return [
    { params: { slug: "blog/post-1" }, props: { locale: "en" } },
    { params: { slug: "es/blog/post-1" }, props: { locale: "es" } },
    // Add more paths as needed
  ];
}

const { slug } = Astro.params;
const { locale } = Astro.props;

changeLanguage(locale);

// Extract the actual slug (removing locale prefix if present)
const actualSlug = slug.startsWith("es/") ? slug.substring(3) : slug;
---

<MainLayout title={`Blog - ${actualSlug}`}>
  <h1>{t("blog.title")}</h1>
  <p>Slug: {actualSlug}</p>

  <!-- Your blog post content here -->
</MainLayout>

Resources

For more detailed information, check out these resources: