Astro internationalization: i18n routing vs automatic translation
Astro v3.5 introduced native i18n routing — URL prefixes like /fr/, /de/, language detection, and getRelativeLocaleUrl(). It is solid infrastructure. But routing is not translation. Astro's i18n routing tells visitors where to go; it does not translate what they see when they get there. This article covers what Astro i18n actually gives you, what it does not, and how to add actual content translation.
What Astro's built-in i18n routing does
Since v3.5, Astro ships a first-party i18n config block in astro.config.mjs. Declaring your locales there gives you URL-based routing out of the box:
With this config, Astro automatically generates locale-prefixed URL paths — pages placed under src/pages/fr/ are served at /fr/about, /fr/pricing, and so on. The routing layer also provides two URL helpers:
getRelativeLocaleUrl(locale, path)— builds a locale-prefixed path relative to the site root.getAbsoluteLocaleUrl(locale, path)— same, but with the full origin prepended — useful for canonical tags and sitemaps.- Language detection via the
Accept-Languageheader in server (SSR) mode — Astro can redirect visitors to their preferred locale automatically.
What it does not do: translate your content. Enabling the i18n config block gives you URL structure and routing helpers. The actual content at /fr/about still needs to be written in French — either by creating src/pages/fr/about.astro with manually translated copy, or by using Content Collections with per-locale entries. The routing layer is purely structural.
The traditional approach: content collections per locale
The most common pattern for multilingual Astro sites is to pair the routing layer with locale-specific content directories. For a blog, this means structuring your content collection by language:
This approach works well in specific conditions: the site is small, a dedicated translator owns each locale directory, and the content changes infrequently. The structure is explicit and the output is auditable — every translated file is a discrete artifact with its own version history.
The maintenance arithmetic turns against you quickly. Twenty pages across five languages means 100 separate files to keep in sync. Every time the English version of a page is updated, the four locale variants lag behind until a translator catches up. Content drift — where the English page has been rewritten but the French version is six months stale — is the most common failure mode of this approach. At scale, the overhead of maintaining locale parity tends to erode into benign neglect.
Automatic translation: one script, all languages
The alternative requires no content duplication. Add Lingvit's script to your Astro layout before the closing </body> tag:
That is the complete integration. From there, Lingvit observes the rendered DOM and translates it into whichever target languages you have enabled in the dashboard. A few properties of this approach are worth noting:
Works across all Astro output modes
Static output (output: "static"), server-rendered (output: "server"), and hybrid mode all produce HTML that Lingvit can translate. The widget operates client-side after the page loads, so the output mode does not affect how it works.
Translates Astro islands
Islands built with React, Vue, Svelte, or Solid hydrate client-side and render their output into the DOM. Lingvit's MutationObserver picks up these nodes as they appear — regardless of which framework powers the island or which hydration directive (client:load, client:visible, etc.) was used.
New content is translated automatically
When you publish a new blog post or update a landing page, the translated versions reflect the change on the next page load. There are no locale files to update and no translator queue to unblock.
Editorial control via the dashboard
Any automatically translated string can be reviewed and overridden from the Lingvit dashboard. Overrides persist — if you correct a product name or a brand term in French, that correction applies every time that string appears.
Can you combine Astro i18n routing with automatic translation?
Yes, and it is the recommended approach for SEO-conscious sites. The two systems operate at different layers and complement each other cleanly.
Astro's built-in routing handles URL structure. URLs like /fr/about and /de/pricing are what search engines use when indexing multilingual content — each locale gets its own crawlable URL, its own canonical, and its own hreflangsignals. This is the correct foundation for multilingual SEO and Astro's routing layer provides it well.
Lingvit handles the actual content translation within those URLs. Rather than maintaining a separate src/pages/fr/about.astro with hand-translated copy, you keep a single source file and let Lingvit translate its rendered output automatically. The result is SEO-indexed URLs per language with automatic content translation and editorial control — without duplicating your source files.
Combined setup summary
- 1Configure Astro's
i18nblock inastro.config.mjswith your target locales. This establishes the URL structure. - 2Add the Lingvit script tag to
src/layouts/Layout.astrobefore</body>. This handles content translation. - 3Keep a single source file per page. Write and maintain content in one language; Lingvit handles all locale variants automatically.
When to use each approach
The choice is not always automatic translation. There are situations where the traditional locale-file approach is clearly the right call:
Astro routing + locale files
- ✓Small site with a dedicated translator per language
- ✓Content that rarely changes after publication
- ✓Legal or regulated copy requiring explicit approval per string
- ✓Community-translated open-source project
Astro routing + automatic translation
- ✓Larger sites where locale file parity is hard to maintain
- ✓Content that updates frequently (blog, changelog, docs)
- ✓Teams without dedicated translation resources
- ✓Adding languages to an existing Astro site with no i18n
Frequently asked questions
- Does automatic translation work with Astro islands?
- Yes. React, Vue, Svelte, and Solid islands hydrate client-side and render their output into the DOM. Lingvit's MutationObserver detects this content as it appears and translates it — regardless of which framework the island uses.
- Does it work with Astro's static output (SSG)?
- Yes. Lingvit runs entirely client-side after the page loads. For static output, the HTML is pre-built and Lingvit translates it in the browser. For SSR, Lingvit runs after hydration. Both work identically from Lingvit's perspective.
- How does Lingvit interact with Astro's built-in i18n routing?
- They operate at different layers. Astro routing handles URL structure (/fr/, /de/) and redirects. Lingvit handles the actual text content translation. You can use both together: Astro for routing, Lingvit for content.
- Does it translate Astro Content Collections?
- Yes. Content Collection content (MDX, Markdown) is rendered to HTML by Astro at build time. That HTML is then observed and translated by Lingvit client-side when the page loads in a visitor's browser.
Related guides
Add languages to your Astro site
Works with static, SSR, and hybrid Astro projects. One script tag, no content duplication.