|
Dokumentation
Demo buchenPlattform
PlattformMCPCLIAPIWorkflows
Leitfäden
Changelog

Lokalisierung

  • Überblick
  • Translation API
  • Lokalisierung für Web-Apps
  • Lokalisierung für mobile Apps
  • iOS mit String Catalogs
  • Android mit strings.xml
  • E-Mail-Lokalisierung
  • Statische Inhalte (z. B. .md, .json)
  • Next.js mit Markdoc
  • Rails mit i18n

Workflows

  • Engine-Setup mit MCP
  • Jira-Triage
  • CI/CD

Next.js App Router-Lokalisierung mit Markdoc

Die Lingo.dev CLI übersetzt Markdoc-Dateien und JSON-Kataloge mit UI-Strings über eine konfigurierte Lokalisierungs-Engine. Markdoc ist ein Markdown-basiertes Authoring-Format mit typisierten, React-gestützten Custom Tags – ideal für Next.js App Router-Websites, die umfangreiche Inhalte mit interaktiven Komponenten verbinden.

Dieser Leitfaden zeigt dir Schritt für Schritt, wie du eine Next.js App Router-Website vollständig lokalisierst: von der CLI-Konfiguration über die Organisation sprachspezifischer Inhalte und das Rendern von Markdoc in dynamischen Routen bis hin zur Automatisierung der Übersetzungen mit der Lingo.dev GitHub App.

Demo-Repository

Klone oder forke lingodotdev/markdoc-nextjs-localization-example, um direkt mitzumachen. Das Repository enthält eine lauffähige Next.js App Router-App mit Markdoc-Inhalten, einer Lingo.dev CLI-Konfiguration und einem CI-Workflow.

So funktioniert die Lokalisierung mit Next.js + Markdoc#

Die meisten Next.js App Router-Websites unterteilen lokalisierte Inhalte in zwei Ebenen:

EbeneInhaltBeispieldatei
Umfangreiche InhalteMarketingseiten, Dokumentation, Blogbeiträgesrc/content/en/pages/home.md
UI-StringsNavbar-Labels, CTAs, Button-Statussrc/content/en/ui.json

Die Routen liegen unter src/app/[lang]/ und lesen zur Laufzeit die Dateien der passenden Sprache. Eine Middleware wählt anhand des Accept-Language-Headers des Browsers eine Standardsprache aus und leitet einfache Pfade wie / zu /en weiter – oder zur jeweils besten Übereinstimmung.

Die CLI verarbeitet Markdoc-Dateien, ohne Frontmatter oder benutzerdefinierte Tags anzutasten, und behandelt den UI-String-Katalog als JSON. In beiden Fällen wird das Delta über deine Lokalisierungs-Engine übersetzt und als sprachspezifische Dateien neben den Quelldateien abgelegt.

Voraussetzungen#

1

Eine Lokalisierungs-Engine erstellen

Bei jedem CLI-Durchlauf laufen Inhalte durch eine Lokalisierungs-Engine – die Konfiguration, die festlegt, welches LLM-Modell, Glossar, welche Markenstimme und welche Regeln verwendet werden. Erstelle sie im Lingo.dev dashboard und generiere einen API key für CI.

2

Node.js prüfen

Die CLI setzt Node.js 22 oder höher voraus:

bash
node -v
3

Ihr Next.js-Projekt einrichten

Dein Projekt braucht den App Router (src/app/) und ein Inhaltsverzeichnis pro Sprache. Das Demo-Repository verwendet unter src/content/ ein Verzeichnis je Sprache (zum Beispiel src/content/en/) mit zwei Unterordnern (pages/ und blog/) sowie einer ui.json-Datei. Die Grundlagen zum Routing findest du unter Next.js internationalization.

Inhalte organisieren#

Teilen Sie Inhalte nach ihrer Funktion auf. Umfangreiche Seiten und Beiträge werden in Markdoc verfasst, kurze UI-Strings liegen in JSON, damit Komponenten sie direkt laden können.

text
src/content/
  en/                  # Source locale
    pages/home.md      # Long-form Markdoc
    blog/hello.md
    ui.json            # UI strings (navbar, CTAs, button states)
  es/                  # Target locales – generated by Lingo.dev
  fr/
  de/

Markdoc-Dateien unterstützen Frontmatter für seitenbezogene Metadaten wie Titel, Beschreibung, Datum und Autor sowie Custom Tags, die als React-Komponenten gerendert werden. Eine minimale Seite sieht so aus:

markdown
---
title: Author once in Markdoc, ship in every language.
description: An example Next.js App Router app that localizes Markdoc with Lingo.
---

{% inline-callout type="info" %}
This page is authored in Markdoc and translated by Lingo.dev.
{% /inline-callout %}

## Built from three pieces

Markdoc custom tags render as React components – even interactive ones.

Die CLI konfigurieren#

Installiere die CLI und melde dich an:

bash
npm install -g @lingo.dev/cli
lingo login

Erstelle anschließend das Konfigurationsgerüst und verknüpfe es mit deiner Engine:

bash
lingo init
lingo link

lingo init erstellt .lingo/config.json mit deiner Quell- und deinen Zielsprachen sowie den Dateimustern für die Übersetzung; lingo link ergänzt deinen orgId und engineId. Committe .lingo/config.json, damit dein Team und alle CI-Läufe dieselbe Konfiguration nutzen.

Für dieses Projekt definiert die Konfiguration zwei Dateimuster – eines für Markdoc-Inhalte und eines für den UI-String-Katalog:

json
{
  "orgId": "org_...",
  "engineId": "eng_...",
  "sourceLocale": "en",
  "targetLocales": ["es", "fr", "de"],
  "files": [
    { "pattern": "src/content/en/pages/*.md" },
    { "pattern": "src/content/en/blog/*.md" },
    { "pattern": "src/content/en/ui.json" }
  ]
}

Das Sprachsegment in jedem Pfad wird für jede Zielsprache ersetzt: src/content/en/pages/home.md wird zu src/content/es/pages/home.md, und src/content/en/ui.json wird zu src/content/de/ui.json. Der Quellpfad muss den Sprachcode enthalten. Die Formate werden anhand der Dateiendung automatisch erkannt, daher brauchen Markdoc-Dateien (.md) und JSON-Dateien (.json) keinen expliziten Typ. Details findest du unter Configuration und Formats.

Einzeldatei-Kataloge

Die neue CLI erwartet eine Datei pro Sprache, wobei der Sprachcode im Pfad enthalten ist (wie oben). Wenn deine UI-Strings in einer einzigen mehrsprachigen JSON-Datei liegen, wird dieses Layout (der frühere json-per-locale-Bucket) von der neuen CLI noch nicht unterstützt – bleib in dem Fall bei der legacy CLI und verfolge das Changelog, bis Support verfügbar ist. Empfohlen ist die Aufteilung in eine Datei pro Sprache.

Markdoc im App Router rendern#

Eine typische dynamische Route lädt ein Dokument und rendert den transformierten Baum. Das Demo-Repository stellt dafür einen kleinen Helper bereit:

ts
// src/lib/markdoc.ts
export async function loadDoc(
  locale: Locale,
  collection: "pages" | "blog",
  slug: string,
) {
  const raw = await fs.readFile(
    path.join(process.cwd(), "src/content", locale, collection, `${slug}.md`),
    "utf8",
  );
  const ast = Markdoc.parse(raw);
  const frontmatter = ast.attributes.frontmatter
    ? parseFrontmatter(ast.attributes.frontmatter)
    : {};
  const content = Markdoc.transform(ast, { ...schema, variables: { frontmatter } });
  return { frontmatter, content };
}

Die App Router-Seite ist ein schlanker Wrapper, der das Dokument mit sprachspezifischen UI-Strings kombiniert:

tsx
// src/app/[lang]/page.tsx
export default async function Home({ params }: PageProps<"/[lang]">) {
  const { lang } = await params;
  const doc = await loadDoc(lang, "pages", "home");
  const { home } = await getMessages(lang);

  return (
    <main>
      <h1>{doc.frontmatter.title}</h1>
      {renderMarkdoc(doc.content)}
    </main>
  );
}

Custom Tags in Markdoc (callout, bento, blog-hero usw.) werden in markdoc.schema.ts deklariert und mit React-Komponenten unter src/components/markdoc/ verknüpft. Die vollständige API finden Sie in den Markdoc schema docs.

Sprache in der Middleware erkennen#

Die Next.js-Middleware prüft die Anfrage, bevor eine Route gerendert wird. Verwenden Sie sie, um einfache Pfade anhand des Accept-Language-Headers zur am besten passenden Sprache weiterzuleiten:

ts
// src/middleware.ts
export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  const hasLocale = locales.some(
    (locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`),
  );
  if (hasLocale) return;

  const locale = pickLocale(request); // parses Accept-Language
  const url = request.nextUrl.clone();
  url.pathname = `/${locale}${pathname === "/" ? "" : pathname}`;
  return NextResponse.redirect(url);
}

export const config = {
  matcher: ["/((?!_next|api|.*\\..*).*)", ],
};

Besucher landen auf /en, /es, /fr oder /de, ohne das Präfix selbst eingeben zu müssen.

Lokal übersetzen#

Führe nach lingo login einen Push aus. Beim ersten Durchlauf – oder nachdem du eine neue Zielsprache hinzugefügt hast – füllst du zunächst alles auf:

bash
lingo push --backfill-missing

Bei späteren Durchläufen pushst du dann einfach nur das Delta:

bash
lingo push

lingo push liest alle Dateien, die deinen Mustern entsprechen, erkennt mithilfe der Lock-Datei (.lingo/lock.json, eingecheckt) nicht übersetzte Einträge, übersetzt das Delta über deine Lokalisierungs-Engine, wartet auf den Abschluss und schreibt die Ergebnisse in das Verzeichnis der jeweiligen Zielsprache. Frontmatter-Schlüssel, benutzerdefinierte Markdoc-Tags und JSON-Strukturen bleiben erhalten – nur der übersetzbare Text ändert sich. Um Übersetzungen abzurufen, die anderswo erzeugt wurden (zum Beispiel in CI), führe lingo pull aus.

Um einen Durchlauf auf bestimmte Dateien einzugrenzen, übergib ein Glob-Muster:

bash
lingo push "src/content/en/blog/*.md"

In CI automatisieren#

Installiere die Lingo.dev GitHub App und verbinde sie mit deinem Repository. Sie liest .lingo/config.json und die verknüpfte engineId serverseitig aus und öffnet bei jeder Änderung der Quellinhalte automatisch einen Übersetzungs-Pull-Request – ganz ohne Workflow-Datei, Runner, API-Key-Secret oder manuelles Jonglieren mit Lock-Dateien.

Vor dem Deployment prüfen#

Verwende lingo check als Deployment-Gate, damit keine unübersetzten Inhalte in Produktion gehen. Der Befehl endet mit einem Nicht-Null-Status, wenn noch Einträge übersetzt werden müssen:

bash
lingo check

Fügen Sie dies vor Ihrem Next.js-Build als separaten CI-Schritt hinzu:

yaml
- name: Verify translations
  run: lingo check
  env:
    LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}
- name: Build
  run: pnpm build

Nächste Schritte#

Static Content Localization
Markdown-, MDX-, JSON-, YAML- und weitere Dateiformate
Web-App-Lokalisierung
UI-String-Muster in gängigen Web-Frameworks
CI/CD-Workflows
Patterns für GitHub App und Self-Hosted Runner
Glossare
Markennamen und Fachbegriffe vor Übersetzungen schützen

War diese Seite hilfreich?

Max PrilutskiyMax Prilutskiy·Aktualisiert vor 13 Tagen·6 Min. Lesezeit