Several languages
Internationalization (i18n) is preparing a site for several languages. Astro does not translate texts for you, but it helps with addresses: the English version at /about, the Russian one at /ru/about. Languages and address rules are set in the config, and the pages for each language live in their own folder.
Setting up languages
Add an i18n block to astro.config.mjs:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://blog.example.com',
i18n: {
locales: ['en', 'ru'],
defaultLocale: 'en',
routing: {
prefixDefaultLocale: false,
},
},
});locales is the list of languages, defaultLocale the main one. prefixDefaultLocale: false means the main language has no prefix in the address: English pages at /about, Russian ones at /ru/about.
Pages in another language
Russian pages go into a folder named after the language code:
src/pages/
├── index.astro → /
├── about.md → /about
└── ru/
├── index.astro → /ru
└── about.md → /ru/aboutCreate src/pages/ru/about.md with Russian text and it opens at /ru/about. Posts in different languages can be kept in subfolders of the collection, for example src/content/blog/ru/.
The current language
In a component, the language of the open page is in Astro.currentLocale. Use it in the layout src/layouts/BaseLayout.astro:
---
const lang = Astro.currentLocale ?? 'en';
---
<html lang={lang}>
<body>
<slot />
</body>
</html>At /about the attribute is lang="en", at /ru/about it is lang="ru". Browsers and search engines learn the page language from it.
Links to another language
The getRelativeLocaleUrl() function from the astro:i18n module builds an address according to the config:
---
import { getRelativeLocaleUrl } from 'astro:i18n';
---
<a href={getRelativeLocaleUrl('ru', 'about')}>Русский</a>
<a href={getRelativeLocaleUrl('en', 'about')}>English</a>The first link leads to /ru/about, the second to /about. If you later turn on the prefix for English too, the addresses change by themselves while the link code stays the same.
Interface strings
Labels such as "Read" and "Posts" are kept in a dictionary per language, for example an object { en: { read: 'Read' }, ru: { read: 'Читать' } } in src/i18n/ui.ts, and picked by Astro.currentLocale. Astro does not provide a ready dictionary; it is an ordinary JavaScript object.
Common mistake
People write links by hand, href="/ru/about", all over the site. Change the address rule and half of the links lead to a 404. Build addresses with getRelativeLocaleUrl() so the rule is written in one place, the config.