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 prefixese.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.
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:
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.
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.