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.
- Go to the Installation Guide and follow the steps to download your translations
- Place the downloaded JSON files in your project as shown in the project structure below
- 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
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: