Back

Astro logo with international flags

Astro Localization & i18n Guide: Mastering Multi-Language Sites


Introduction

Building multi-language websites with Astro has become significantly simpler with its native internationalization (i18n) support, introduced in [email protected]. This guide dives deep into Astro localization, exploring best practices for leveraging Astro’s i18n capabilities, addressing common pitfalls encountered with the official recipe, and providing expert alternative solutions to help you master your Astro internationalization strategy.

Astro provides a i18n recipe explaining how to implement i18n in your Astro project. The recipe is a great starting point, but can lead to some common pitfals.

Don’t use getRelativeLocaleUrl to change current page language

Astro provides a great api to generate dynamic locale URLs using getRelativeLocaleUrl. However, it’s not ideal for switching languages on the same page.

It either redirects to the root page or creates an unexpected double-prefixed URL:

  • Using getRelativeLocaleUrl(locale: string) in your language switcher will redirect you to the root page with the seleceted language.

  • Using getRelativeLocaleUrl("en", Astro.url.pathname) will generate a double-prefixed URL with the current and new language as prefixes e.g. /es/en/blog.

Alternative: Custom changeLanguage Function

To solve this issue, I created a custom function changeLanguage(lang: string, path: string) that will change the current page language and stay on the same page.

This function works by intelligently stripping any existing language prefix from the path before applying the new one, thus avoiding the double-prefix issue and ensuring correct navigation.

src/i18n/utils.ts
LANGUAGES = {
ENGLISH: "en",
SPANISH: "es",
EUSKERA: "eus",
};
export const showDefaultLang = false;
export const defaultLang = LANGUAGES.SPANISH;
export function changeLanguage(lang: string, path: string) {
const languagePrefixes = Object.values(LANGUAGES);
const hasLanguagePrefix = languagePrefixes.some((prefix) =>
path.includes(prefix)
);
if (hasLanguagePrefix) {
path = path.replace(new RegExp(`/${languagePrefixes.join("|")}`), "");
}
return !showDefaultLang && lang === defaultLang ? path : `/${lang}${path}`;
}

showDefaultLang is a boolean that represents if the default language is in the url. This should match your Astro configuration.

defaultLang is the default language of your site. This should match your Astro configuration.

When to Use getRelativeLocaleUrl

This function shines for navigating to different pages in various locales:

<a href={`${getRelativeLocaleUrl(currentLocale, "/blog/i18n-with-astro/")}`} >

This will generate a url with the current locale as a prefix, e.g. /es/blog/i18n-with-astro/ if the current locale is Spanish.

Content Localization Beyond Astro’s i18n Recipe

Astro’s i18n recipe demonstrates translating UI strings directly within your Astro components. While this is suitable for small pieces of text like button labels or short messages, it can become cumbersome and less manageable for localizing larger content blocks across multiple languages.

For more extensive content localization, using separate JSON files per language offers better organization, easier maintenance (especially if working with translators), and cleaner component code.

Here’s an effective approach to manage your translations:

src/i18n/index.ts
import english from "./en.json";
import spanish from "./es.json";
import euskera from "./eus.json";
export const getI18N = ({
currentLocale = "es",
}: {
currentLocale: string | undefined;
}) => {
if (currentLocale === LANGUAGES.ENGLISH) return english;
if (currentLocale === LANGUAGES.SPANISH) return spanish;
if (currentLocale === LANGUAGES.EUSKERA) return euskera;
return spanish;
};

Then we can use the getI18N function to get the content for the current locale.

src/pages/index.astro
import { getI18N } from "src/i18n";
const currentLocale = Astro.currentLocale ? Astro.currentLocale : "es";
const i18n = getI18N({ currentLocale });
---
<h1>{i18n.greeting}</h1>
<p>{i18n.intro}</p>

i18n will contain the content for the current locale.

Conclusion

Mastering Astro localization and its native i18n capabilities empowers you to build truly global, multi-language websites effectively. By understanding common pitfalls, such as those with getRelativeLocaleUrl for language switching, and by implementing robust alternative approaches like custom utility functions and JSON-based content localization, you can craft seamless and user-friendly experiences for diverse audiences.