Design wechseln

Astro i18n Konfigurationsleitfaden: Mehrsprachige Website in 30 Minuten (inkl. Sprachumschalter)

Easton editorial illustration: monorepo project desk

Sie haben einen schönen Astro-Blog für den internationalen Markt vorbereitet – und stellen fest: Mehrsprachigkeit klappt nicht. locales, defaultLocale, prefixDefaultLocale wirken unverständlich, die Inhaltsorganisation ist unklar, Content Collections klingen abstrakt, und ein Sprachumschalter? Keine Ahnung, wo anfangen.

Astro i18n ist nicht so kompliziert – die offizielle Doku ist nur sehr technisch. Dieser Artikel führt Sie durch den gesamten Astro-i18n-Workflow: von der Basis-Konfiguration bis zum Sprachumschalter, mit vollständigem Code in jedem Schritt. In etwa 30 Minuten kann Ihre Website mehrere Sprachen bedienen.

Astro i18n Basis-Konfiguration (in 10 Minuten erledigt)

astro.config.mjs im Detail

Zuerst die wichtigste Datei – die Konfiguration. Ab Astro v4.0 ist i18n eingebaut und relativ einfach. Öffnen Sie astro.config.mjs und ergänzen Sie:

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  i18n: {
    // Welche Sprachen Ihre Website unterstützt
    locales: ['en', 'zh-cn', 'ja'],

    // Standardsprache (muss in locales enthalten sein)
    defaultLocale: 'en',

    // Ob der Standardsprache ein URL-Präfix vorangestellt wird
    prefixDefaultLocale: false,
  }
});

Die einzelnen Optionen im Überblick:

locales – alle unterstützten Sprachen. Standard-Sprachcodes wie 'en' (Englisch), 'zh-cn' (vereinfachtes Chinesisch), 'ja' (Japanisch). Feinere Varianten sind möglich, z. B. 'en-US', 'en-GB'.

defaultLocale – die Sprache, die Besucher beim ersten Besuch sehen. Muss in der locales-Liste stehen, sonst meldet Astro einen Fehler.

prefixDefaultLocale – eine Option, über die viele lange nachdenken. Bei false hat die Standardsprache kein Sprachpräfix in der URL (z. B. /about), andere schon (/zh-cn/about, /ja/about). Bei true haben alle Sprachen ein Präfix (/en/about, /zh-cn/about).

In den meisten Fällen reicht false – die URL der Hauptsprache bleibt kurz. Bei starkem Fokus auf einheitliche URLs oder speziellen SEO-Anforderungen kann true sinnvoll sein.

Drei Routing-Strategien im Vergleich

Astro bietet drei i18n-Routing-Strategien. Die folgende Tabelle hilft bei der Wahl:

StrategieKonfigurationURL-BeispieleEinsatzVor- und Nachteile
Strategie 1: Standardsprache ohne PräfixprefixDefaultLocale: false/about
/zh-cn/about
/ja/about
Die meisten Websites (empfohlen)✅ Kurze URL für Standardsprache
❌ URLs nicht einheitlich formatiert
Strategie 2: Alle Sprachen mit PräfixprefixDefaultLocale: true/en/about
/zh-cn/about
/ja/about
Einheitliche URLs oder spezielle SEO-Anforderungen✅ Einheitliches URL-Schema
✅ Einfache Sprachumschalt-Logik
❌ Längere URL für Standardsprache
Strategie 3: Manueller Modusrouting: 'manual'Vollständig anpassbarKomplexe i18n-Anforderungen, volle Routing-Kontrolle✅ Sehr flexibel
❌ Aufwendige Konfiguration, viel eigene Logik nötig

Für einfache Projekte (Blog, Dokumentation) reicht Strategie 1. Wer aufgeräumte URLs legt Wert, wählt Strategie 2. Strategie 3 eignet sich bei besonderen Anforderungen – z. B. dynamische Sprachwahl nach Nutzerverhalten oder verschiedene Sprachen auf Subdomains.

Für ein zweisprachiges Chinesisch-Englisch-Blog reicht es oft, die Konfiguration oben anzupassen: locales auf ['zh-cn', 'en'], defaultLocale auf 'zh-cn' (wenn Ihre Hauptzielgruppe chinesischsprachig ist) – fertig.

Astro i18n Mehrsprachigkeit konfigurieren

Vollständige Schritte zur mehrsprachigen Astro-Website in 30 Minuten

  1. 1

    Step 1: astro.config.mjs konfigurieren

    i18n in astro.config.mjs ergänzen:
  2. 2

    Step 2: Mehrsprachige Inhalte organisieren

    Organisationsansatz wählen:
  3. 3

    Step 3: UI-Übersetzungswörterbuch anlegen

    Übersetzungswörterbuch in src/i18n/ui.ts:
  4. 4

    Step 4: Sprachumschalter implementieren

    Mit getRelativeLocaleUrl und Astro.currentLocale:
  5. 5

    Step 5: SEO optimieren

    hreflang-Tags im Layout, Sitemap konfigurieren, Meta-Infos lokalisieren

Mehrsprachige Inhalte organisieren (zwei Ansätze)

Die Konfiguration steht – als Nächstes die Inhalte. Viele scheitern hier: Wo liegen die Dateien? Astro bietet zwei Wege.

Ansatz 1: Ordner pro Sprache (für Einsteiger empfohlen)

Der intuitivste Weg – pro Sprache ein Ordner:

src/pages/
├── about.astro        # Standardsprache (z. B. Chinesisch)
├── blog.astro
├── index.astro
├── en/                # Englische Version
│   ├── about.astro
│   ├── blog.astro
│   └── index.astro
└── ja/                # Japanische Version
    ├── about.astro
    ├── blog.astro
    └── index.astro

Bei prefixDefaultLocale: false liegen die Dateien der Standardsprache direkt unter pages/. Andere Sprachen bekommen Unterordner.

Vorteil: klare Struktur, Änderungen an einer Sprache beeinflussen andere nicht. Nachteil: bei vielen Seiten und Sprachen viel Duplikat – 20 Seiten × 5 Sprachen = 100 Dateien.

Ansatz 2: Dynamisches Routing (fortgeschritten empfohlen)

Weniger Dateien, eine Route für alle Sprachen:

src/pages/
└── [lang]/
    └── [...slug].astro

In [...slug].astro Inhalt anhand von lang rendern:


---

// src/pages/[lang]/[...slug].astro
export function getStaticPaths() {
  const locales = ['zh-cn', 'en', 'ja'];
  const slugs = ['about', 'blog', 'contact'];

  return locales.flatMap((lang) =>
    slugs.map((slug) => ({
      params: { lang, slug },
    }))
  );
}

const { lang, slug } = Astro.params;
// Inhalt anhand von lang und slug laden

---

Hohe Wiederverwendung, geringere Wartung – erfordert aber Verständnis für dynamisches Routing in Astro. Einsteiger starten besser mit Ansatz 1.

Content Collections für Mehrsprachigkeit (für Blogs unverzichtbar)

Für Blogs sind Content Collections zentral – Astros empfohlene Verwaltung für inhaltsstarke Sites.

Verzeichnisstruktur:

src/content/
└── blog/
    ├── en/
    │   ├── post-1.md
    │   └── post-2.md
    ├── zh-cn/
    │   ├── post-1.md
    │   └── post-2.md
    └── ja/
        ├── post-1.md
        └── post-2.md

Schema in src/content/config.ts:

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blogCollection = defineCollection({
  schema: z.object({
    title: z.string(),
    author: z.string(),
    date: z.date(),
    lang: z.enum(['en', 'zh-cn', 'ja']),  // Sprachfeld
  }),
});

export const collections = {
  blog: blogCollection,
};

Artikel der aktuellen Sprache laden:


---

// src/pages/blog/index.astro
import { getCollection } from 'astro:content';

const currentLang = Astro.currentLocale;  // aktuelle Sprache
const posts = await getCollection('blog', ({ data }) => {
  return data.lang === currentLang;  // nur Artikel der aktuellen Sprache
});

---

So sehen Nutzer automatisch Artikel in ihrer gewählten Sprache. Die offizielle Astro-Doku nutzt diesen Ansatz – bewährt und zuverlässig.

UI-Übersetzungsdateien verwalten

Neben Inhalten brauchen Sie Übersetzungen für feste UI-Texte – Navigation, Buttons, Formularlabels. Ein zentrales Wörterbuch ist praktisch:

// src/i18n/ui.ts
export const ui = {
  'en': {
    'nav.home': 'Home',
    'nav.about': 'About',
    'nav.blog': 'Blog',
    'btn.readMore': 'Read More',
  },
  'zh-cn': {
    'nav.home': '首页',
    'nav.about': '关于',
    'nav.blog': '博客',
    'btn.readMore': '阅读更多',
  },
  'ja': {
    'nav.home': 'ホーム',
    'nav.about': '概要',
    'nav.blog': 'ブログ',
    'btn.readMore': '続きを読む',
  },
} as const;

Hilfsfunktionen:

// src/i18n/utils.ts
import { ui } from './ui';

// Sprache aus URL ermitteln
export function getLangFromUrl(url: URL) {
  const [, lang] = url.pathname.split('/');
  if (lang in ui) return lang as keyof typeof ui;
  return 'zh-cn';  // Standardsprache
}

// Übersetzungsfunktion
export function useTranslations(lang: keyof typeof ui) {
  return function t(key: keyof typeof ui[typeof lang]) {
    return ui[lang][key] || ui['zh-cn'][key];
  }
}

In Komponenten nutzen:


---

// Beispielkomponente
import { getLangFromUrl, useTranslations } from '@/i18n/utils';

const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);

---

<nav>
  <a href="/">{t('nav.home')}</a>
  <a href="/about">{t('nav.about')}</a>
  <a href="/blog">{t('nav.blog')}</a>
</nav>

Einfach und wartbar – alle UI-Übersetzungen an einem Ort. Bei sehr vielen Texten können Sie nach Modulen in mehrere JSON-Dateien aufteilen.

Sprachumschalter implementieren (mit vollständigem Code)

Konfiguration und Inhalte stehen – jetzt der Sprachumschalter. Mit den Astro-i18n-Helfern ist das überschaubar.

Astro-i18n-Helferfunktionen

getRelativeLocaleUrl(locale, path) – relativen Pfad für eine Sprache erzeugen.

import { getRelativeLocaleUrl } from 'astro:i18n';

// URL der englischen About-Seite
const url = getRelativeLocaleUrl('en', 'about');
// Ergebnis: '/en/about' oder '/about' (je nach Konfiguration)

getAbsoluteLocaleUrl(locale, path) – absolute URL inkl. Domain.

import { getAbsoluteLocaleUrl } from 'astro:i18n';

const url = getAbsoluteLocaleUrl('en', 'about');
// Ergebnis: 'https://example.com/en/about'

Astro.currentLocale – Sprache der aktuellen Seite.


---

const currentLang = Astro.currentLocale;
// z. B. 'zh-cn', 'en'

---

Astro.preferredLocale – bevorzugte Browsersprache (falls in locales unterstützt).


---

const browserLang = Astro.preferredLocale;
// Browsersprache, falls in locales enthalten

---

Sprachumschalt-Komponente

Eine einfache, direkt nutzbare Komponente:


---

// src/components/LanguageSwitcher.astro
import { getRelativeLocaleUrl } from 'astro:i18n';

// Unterstützte Sprachen (besser aus Config lesen; hier zur Demo fest codiert)
const locales = {
  'zh-cn': '简体中文',
  'en': 'English',
  'ja': '日本語',
};

const currentLang = Astro.currentLocale || 'zh-cn';
const currentPath = Astro.url.pathname
  .replace(`/${currentLang}/`, '/')  // Sprachpräfix entfernen
  .replace(/^\//, '');  // führenden Slash entfernen

---

<div class="language-switcher">
  <button class="lang-button">
    {locales[currentLang]} ▼
  </button>
  <div class="lang-dropdown">
    {Object.entries(locales).map(([lang, label]) => {
      const url = getRelativeLocaleUrl(lang, currentPath);
      return (
        <a
          href={url}
          class={lang === currentLang ? 'active' : ''}
        >
          {label}
        </a>
      );
    })}
  </div>
</div>

<style>
  .language-switcher {
    position: relative;
    display: inline-block;
  }

  .lang-button {
    padding: 8px 16px;
    background: #f3f4f6;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    cursor: pointer;
  }

  .lang-button:hover {
    background: #e5e7eb;
  }

  .lang-dropdown {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 4px;
    background: white;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    min-width: 150px;
  }

  .language-switcher:hover .lang-dropdown {
    display: block;
  }

  .lang-dropdown a {
    display: block;
    padding: 10px 16px;
    color: #374151;
    text-decoration: none;
    transition: background 0.2s;
  }

  .lang-dropdown a:hover {
    background: #f3f4f6;
  }

  .lang-dropdown a.active {
    background: #dbeafe;
    color: #1e40af;
    font-weight: 500;
  }
</style>

<script>
  // Klick auf Mobilgeräten
  document.querySelector('.lang-button')?.addEventListener('click', (e) => {
    e.stopPropagation();
    const dropdown = document.querySelector('.lang-dropdown');
    dropdown?.classList.toggle('show');
  });

  document.addEventListener('click', () => {
    document.querySelector('.lang-dropdown')?.classList.remove('show');
  });
</script>

Im Layout oder in der Navigation einbinden:


---

// src/layouts/Layout.astro
import LanguageSwitcher from '@/components/LanguageSwitcher.astro';

---

<header>
  <nav>
    <!-- weitere Navigationspunkte -->
    <LanguageSwitcher />
  </nav>
</header>

Ablauf:

  1. Aktuelle Sprache und Pfad ermitteln
  2. URL für jede unterstützte Sprache erzeugen
  3. Aktuelle Sprache hervorheben
  4. Beim Klick zur entsprechenden Sprachversion wechseln

getRelativeLocaleUrl(lang, currentPath) sorgt dafür, dass Nutzer auf derselben Seite in einer anderen Sprache landen – nicht auf der Startseite.

Browser-Spracherkennung (optional, empfohlen)

Beim ersten Besuch zur Browsersprache weiterleiten – per Middleware:

// src/middleware.ts
import { defineMiddleware } from 'astro:middleware';

export const onRequest = defineMiddleware((context, next) => {
  const url = context.url;
  const currentLocale = context.currentLocale;
  const preferredLocale = context.preferredLocale;

  // Root-Pfad: bei abweichender Browsersprache weiterleiten
  if (url.pathname === '/' && preferredLocale && preferredLocale !== currentLocale) {
    return context.redirect(`/${preferredLocale}/`);
  }

  return next();
});

Nicht bei jedem Besuch erzwingen – sonst überschreibt es manuelle Sprachwahl. Besser mit Cookie kombinieren:

// Verbesserte Middleware
export const onRequest = defineMiddleware((context, next) => {
  const url = context.url;
  const currentLocale = context.currentLocale;
  const preferredLocale = context.preferredLocale;
  const savedLang = context.cookies.get('user-lang')?.value;

  // Gespeicherte Sprachpräferenz hat Vorrang
  if (savedLang && savedLang !== currentLocale && url.pathname === '/') {
    return context.redirect(`/${savedLang}/`);
  }

  // Sonst Browsersprache
  if (!savedLang && url.pathname === '/' && preferredLocale && preferredLocale !== currentLocale) {
    context.cookies.set('user-lang', preferredLocale, {
      path: '/',
      maxAge: 31536000,  // 1 Jahr
    });
    return context.redirect(`/${preferredLocale}/`);
  }

  return next();
});

Beim Sprachwechsel Cookie setzen:

<script>
  document.querySelectorAll('.lang-dropdown a').forEach((link) => {
    link.addEventListener('click', (e) => {
      const lang = e.target.getAttribute('data-lang');
      document.cookie = `user-lang=${lang}; path=/; max-age=31536000`;
    });
  });
</script>

So bleibt die gewählte Sprache beim nächsten Besuch erhalten.

Fortgeschrittene Techniken (Fallback, Domain-Mapping, SEO)

Für einfache Projekte können Sie diesen Abschnitt überspringen und bei Bedarf zurückkommen.

Fallback-Strategie

Während der Übersetzung fehlen manche japanischen Seiten noch – Fallback zeigt stattdessen Englisch:

// astro.config.mjs
export default defineConfig({
  i18n: {
    locales: ['en', 'zh-cn', 'ja'],
    defaultLocale: 'en',
    fallback: {
      ja: 'en',      // Japanisch fehlt → Englisch
      'zh-cn': 'en', // Chinesisch fehlt → Englisch
    },
  }
});

Existiert /ja/some-page nicht, liefert Astro /en/some-page statt 404 – praktisch während laufender Übersetzung.

Eigene Domain-Zuordnung

Manche Produkte nutzen Domains pro Sprache:

  • Englisch: example.com
  • Chinesisch: example.cn
  • Japanisch: example.jp

Astro unterstützt das – nur im SSR-Modus:

// astro.config.mjs
export default defineConfig({
  output: 'server',  // SSR erforderlich
  adapter: node(),   // Adapter konfigurieren
  i18n: {
    locales: ['en', 'zh-cn', 'ja'],
    defaultLocale: 'en',
    domains: {
      'zh-cn': 'https://example.cn',
      ja: 'https://example.jp',
    },
  }
});

Chinesische Inhalte landen auf example.cn, japanische auf example.jp. Im rein statischen Modus (Standard) ist Domain-Mapping nicht verfügbar.

SEO für mehrsprachige Sites

Suchmaschinen müssen wissen, welche Sprachversionen existieren – vor allem über hreflang.

Astro unterstützt i18n-SEO gut; einiges läuft automatisch. Folgendes sollten Sie manuell setzen:

1. hreflang-Tags im Layout


---

// src/layouts/Layout.astro
import { getAbsoluteLocaleUrl } from 'astro:i18n';

const locales = ['en', 'zh-cn', 'ja'];
const currentPath = Astro.url.pathname
  .replace(/^\/(en|zh-cn|ja)\//, '')
  .replace(/^\//, '');

---

<html>
<head>
  {locales.map((lang) => (
    <link
      rel="alternate"
      hreflang={lang}
      href={getAbsoluteLocaleUrl(lang, currentPath)}
    />
  ))}

  <link
    rel="alternate"
    hreflang="x-default"
    href={getAbsoluteLocaleUrl('en', currentPath)}
  />

  <meta name="description" content={description[currentLang]} />

  <link rel="canonical" href={getAbsoluteLocaleUrl(currentLang, currentPath)} />
</head>
</html>

2. Mehrsprachige sitemap.xml

Mit @astrojs/sitemap wird pro Sprache eine Sitemap erzeugt – site in der Config setzen:

// astro.config.mjs
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://example.com',  // erforderlich
  integrations: [sitemap()],
});

3. Meta-Infos lokalisieren

title, description, keywords pro Sprache übersetzen:


---

const meta = {
  'en': {
    title: 'Welcome to My Blog',
    description: 'A blog about web development',
  },
  'zh-cn': {
    title: '欢迎来到我的博客',
    description: '一个关于 Web 开发的博客',
  },
};

const currentLang = Astro.currentLocale || 'en';

---

<head>
  <title>{meta[currentLang].title}</title>
  <meta name="description" content={meta[currentLang].description} />
</head>

Damit indexieren Suchmaschinen Ihre Sprachversionen korrekt.

Fazit

Kurz der Astro-i18n-Workflow im Überblick:

Schritt 1: astro.config.mjs (ca. 5 Minuten)

  • locales (unterstützte Sprachen)
  • defaultLocale (Standardsprache)
  • prefixDefaultLocale nach Bedarf

Schritt 2: Mehrsprachige Inhalte

  • Einsteiger: Ordner pro Sprache
  • Fortgeschritten: dynamisches Routing + Content Collections
  • UI-Übersetzungswörterbuch nicht vergessen

Schritt 3: Sprachumschalter

  • getRelativeLocaleUrl für URLs
  • Astro.currentLocale für die aktuelle Sprache
  • Optional: Browserspracherkennung und Cookie

Astro i18n ist in der Praxis angenehm: einfache Konfiguration, hilfreiche Helfer, gute Performance (Routen werden beim Build vorgeneriert). Für mehrsprachige Sites lohnt sich die eingebaute Lösung.

Legen Sie jetzt los und rüsten Sie Ihre Astro-Website auf Mehrsprachigkeit auf. Bei Fragen: offizielle Astro-i18n-Dokumentation mit detaillierter API-Referenz.

Erfahrungen oder Stolpersteine? Teilen Sie sie gerne in den Kommentaren – gemeinsam lernt es sich leichter.

FAQ

Wie lange dauert die Astro-i18n-Konfiguration?
Die Basis-Konfiguration dauert nur 5–10 Minuten:
• Einschließlich locales, defaultLocale und prefixDefaultLocale in astro.config.mjs

Eine vollständige mehrsprachige Website (inkl. Sprachumschalter und SEO) braucht etwa 30 Minuten.
Soll prefixDefaultLocale true oder false sein?
In den meisten Fällen reicht false:
• Die URL der Standardsprache bleibt kurz (z. B. /about)

Bei einheitlichen URL-Formaten oder speziellen SEO-Anforderungen kann true sinnvoll sein (z. B. /en/about).
Wie organisiere ich mehrsprachige Inhalte?
Es gibt zwei Ansätze:

Ansatz 1: Ordner pro Sprache (für Einsteiger empfohlen):
• Klare Struktur, aber mehr Dateien

Ansatz 2: Dynamisches Routing (für Fortgeschrittene empfohlen):
• Hohe Code-Wiederverwendung, geringere Wartungskosten

Für Blogs: Content Collections zur Verwaltung mehrsprachiger Artikel.
Wie implementiere ich einen Sprachumschalter?
Mit getRelativeLocaleUrl von Astro mehrsprachige URLs erzeugen, mit Astro.currentLocale die aktuelle Sprache ermitteln.

Optional: Browser-Spracherkennung und Cookie zum Speichern der Sprachpräferenz – für bessere UX.
Wie optimiere ich SEO für mehrsprachige Websites?
Wichtige Schritte:
• hreflang-Tags im Layout – Suchmaschinen über Sprachversionen informieren
• Sitemap-Plugin für automatische mehrsprachige Sitemap
• title, description und andere Meta-Infos lokalisieren

Astro unterstützt i18n-SEO gut – vieles läuft automatisch.

10 Min. Lesezeit · Veröffentlicht am: 2. Dez. 2025 · Aktualisiert am: 14. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog