Astro has built-in routing for sites in more than one language. It handles the URLs, and you decide how the content gets translated.
Turn on routing
Add the i18n block to your Astro config:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr', 'de'],
routing: { prefixDefaultLocale: false },
},
});
With prefixDefaultLocale: false, English stays at /about/ and French lives at /fr/about/. Turning it on puts every language under a prefix, including the default.
Add the pages
Each locale gets a folder in src/pages:
src/pages/
about.astro
fr/about.astro
de/about.astro
For sites with many pages, a dynamic [locale] route that reads from content collections saves copying files around.
Link between languages
Use Astro’s helpers instead of building URLs by hand, so your links follow your routing settings:
---
import { getRelativeLocaleUrl } from 'astro:i18n';
---
<a href={getRelativeLocaleUrl('fr', 'about')}>Français</a>
Decide what to do about the rest
Routing is the easy part. Think about these before you start:
- Interface text. Buttons and labels need a home, such as a small dictionary file or a library like Paraglide.
hreflang. Tell search engines which pages are translations of each other. The@astrojs/sitemapintegration can include these links.- Keeping up. Translations drift as the source changes. A tool like Lunaria can track what’s out of date.
- Who translates. Agents can draft quickly, but have a person review anything customers will read.
See it across a fleet
Em Region shows which sites are translated, and into which languages, so you can see where translation is a natural next project.