---
title: Internationalisierung
description: Konfigurieren Sie die UI-Sprache des Editors mit integrierter oder benutzerdefinierter Locale-Unterstützung.
---

# Internationalisierung

Die Editor-Oberfläche unterstützt den Wechsel der Locale. Jedes Label, jeder Tooltip, jeder Platzhalter und jede Nachricht wird durch einen Übersetzungsschlüssel gesteuert — keine fest codierten Zeichenketten.

Dabei sind zwei Sprachen im Spiel, und sie sind nicht dasselbe. `init({ locale })` legt die Sprache der **Editor-Oberfläche** fest. Die `settings.locale` einer Vorlage — das Feld „Inhaltssprache“ in den Vorlagen-Einstellungen — legt die Sprache der **verfassten E-Mail** fest und wird zu `<html lang>` in der gerenderten Ausgabe. Wer auf Deutsch arbeitet, aber eine englische Kampagne schreibt, setzt die erste auf `de` und die zweite auf `en`.

Die Schreibrichtung ist eine dritte, unabhängige Einstellung. `settings.direction` (`"ltr"` oder `"rtl"`) ist das `dir` der Leinwand und das gerenderte `<mjml dir>`. Ungesetzt folgt sie der Inhaltssprache (`ar`, `he`, `fa`, `ur`, … → RTL). Sie folgt weder `init({ locale })` noch der Host-Seite. Der Schalter „Rechts-nach-links“ in den Vorlagen-Einstellungen schreibt einen expliziten Wert; danach treibt die Locale sie nicht mehr.

## Locale festlegen

Übergeben Sie die Option `locale` an `init()`:

```ts
import { init } from '@templatical/editor';

const editor = await init({
  container: '#editor',
  locale: 'de',
});
```

## Integrierte Locales

| Code | Sprache |
|---|---|
| `en` | Englisch (Standard) |
| `de` | Deutsch |
| `pt-BR` | Portugiesisch (Brasilien) |
| `es` | Spanisch |
| `ca` | Katalanisch |
| `fr` | Französisch |
| `nl` | Niederländisch |

## Locale-Auflösung

Der Editor normalisiert Locale-Codes, indem er Regionssuffixe entfernt:

| Eingabe | Aufgelöst |
|---|---|
| `'en'` | `en` |
| `'en-US'` | `en` |
| `'en-GB'` | `en` |
| `'de-AT'` | `de` |
| `'fr-BE'` | `fr` |
| `'it'` | `en` (nicht unterstützt, fällt auf Englisch zurück) |

Wenn die aufgelöste Locale nicht unterstützt wird, fällt der Editor auf Englisch zurück und warnt einmalig auf der Konsole — mit einer Liste der Locales, die funktioniert hätten. Stillschweigend erfolgt der Rückfall nur beim Cloud-Teil, der absichtlich weniger Locales mitbringt (siehe unten).

## Asynchrones Laden

Locale-Dateien werden asynchron mit dynamischem `import()` geladen. Nur die aktive Locale wird in den Client gebündelt — die anderen Locale-Dateien sind nicht in Ihrem Build enthalten. Das bedeutet, dass das Wechseln von Locales zur Laufzeit eine erneute Initialisierung des Editors erfordert:

```ts
async function switchLocale(newLocale: string) {
  editor.unmount();
  editor = await init({
    container: '#editor',
    locale: newLocale,
  });
}
```

## Wie Übersetzungen funktionieren

Übersetzungen sind verschachtelte Objekte, die nach UI-Abschnitt organisiert sind:

```ts
{
  blocks: {
    paragraph: 'Paragraph',
    image: 'Image',
    button: 'Button',
    // ...
  },
  toolbar: {
    duplicate: 'Duplicate',
    delete: 'Delete',
    // ...
  },
  blockSettings: {
    spacing: 'Spacing',
    padding: 'Padding',
    // ...
  },
  templateSettings: {
    layout: 'Layout',
    // ...
  },
}
```

Einige Zeichenketten unterstützen Platzhalter-Interpolation mit `{placeholder}`-Syntax:

```ts
{
  header: {
    templatesUsed: '{used}/{max} templates used',
  },
}
```

## Standardtext für Blöcke

Neue Blöcke starten mit Platzhaltertext, und dieser folgt der Locale — ein
Button, der unter `locale: 'de'` eingefügt wird, zeigt „Hier klicken“ und nicht
„Click Here“.

Welcher Locale er folgt, hängt davon ab, für wen der Text bestimmt ist:

| Standardwert | Folgt | Begründung |
|---|---|---|
| Text von Titel, Absatz und Button | `init({ locale })` | Hinweise an die bearbeitende Person. Sie sind zum Überschreiben gedacht und passen daher zur umgebenden Oberfläche. |
| Video-`alt`, Countdown-Einheitenlabels und Ablaufmeldung | `settings.locale` der Vorlage | Dieser Text wird mit der E-Mail ausgeliefert und folgt deshalb der Sprache der E-Mail — nicht der Sprache der bearbeitenden Person. |

Alles davon lässt sich mit [`blockDefaults`](/de/guide/defaults) überschreiben;
diese Angaben gewinnen gegen beide Locales:

```ts
const editor = await init({
  container: '#editor',
  locale: 'de',
  blockDefaults: {
    // Eigener Wortlaut, in beliebiger Sprache.
    button: { text: 'Jetzt kaufen' },
    paragraph: { content: '<p>Text hier eingeben</p>' },
  },
});
```

Zusammengeführt wird tief verschachtelt: Wird ein Feld überschrieben, bleibt der
Rest lokalisiert — `button: { backgroundColor: '#ff6600' }` behält das übersetzte
Label.

::: tip
Ohne gesetzte Locale verhält sich alles wie zuvor: Die englischen Standardwerte
sind mit den Werkseinstellungen identisch.
:::

## Datumsangaben

Relative Angaben („vor 5 Min.“) stammen aus Übersetzungsschlüsseln. Absolute
Datums- und Zeitangaben — Einträge der Versionshistorie, Tooltips gespeicherter
Blöcke, die Änderungszeit der Vorlage — werden von `Intl` aus
`init({ locale })` erzeugt und erscheinen damit in derselben Sprache wie die
Oberfläche daneben statt in der Sprache des Browsers.

Die Leinwand trägt außerdem die `settings.locale` der Vorlage als
`lang`-Attribut, damit Rechtschreibprüfung und Silbentrennung des Browsers den
Text nach den Regeln der Sprache bewerten, in der er tatsächlich verfasst ist.
Sie setzt `dir` aus `settings.direction` (aufgelöst wie oben), damit eine
RTL-Host-Seite nicht in eine LTR-E-Mail durchsickert und eine LTR-Host-Seite
arabischen Text nicht linksläufig belässt.

## Eine neue Locale beitragen

So fügen Sie eine neue Sprache hinzu:

1. Kopieren Sie `packages/editor/src/i18n/locales/en.ts` in eine neue Datei, benannt nach Ihrem Locale-Code (z. B. `<locale>.ts`)
2. Übersetzen Sie alle String-Werte, behalten Sie die Schlüsselstruktur bei und annotieren Sie das Objekt mit `typeof en` (siehe Beispiel unten)
3. Führen Sie `pnpm run typecheck` aus — durch die `typeof en`-Annotation schlagen fehlende, überzählige oder falsch verschachtelte Schlüssel bereits zur Compile-Zeit fehl
4. Führen Sie `pnpm run test` aus, um die Platzhalter-Parität zu überprüfen — Tests prüfen, dass jedes `{placeholder}`-Token aus den englischen Strings auch in Ihren Übersetzungen vorkommt

Ein Registrierungsschritt ist nicht nötig. Die Liste der unterstützten Locales wird zur Build-Zeit aus den Dateien in `locales/` abgeleitet — `<locale>.ts` ablegen genügt, und `init({ locale: '<locale>' })` findet sie automatisch.

Beispielstruktur für eine neue Locale:

```ts
// packages/editor/src/i18n/locales/<locale>.ts
import type en from './en';

const translations: typeof en = {
  blocks: {
    paragraph: '…',
    image: '…',
    button: '…',
    section: '…',
    divider: '…',
    spacer: '…',
    // ... all keys from en.ts
  },
  toolbar: {
    duplicate: '…',
    delete: '…',
    // ...
  },
  // ... all sections from en.ts
};

export default translations;
```

### Cloud-Strings sind optional

Die Übersetzungen sind in zwei Teile aufgeteilt. Der OSS-Teil (`locales/*.ts`) deckt alles im Open-Source-Editor ab. Ein separater Cloud-Teil (`locales/cloud/*.ts`) deckt Funktionen ab, die nur über `initCloud()` verfügbar sind — KI, Kollaboration, Template-Bewertung, das Lint-Speichergatter und Plan-Limits. Den Cloud-Teil müssen Sie nicht übersetzen: Existiert `locales/cloud/<locale>.ts` nicht, fallen Cloud-Funktionen auf Englisch zurück, während der Rest des Editors in Ihrer Sprache erscheint.

Reichen Sie einen Pull Request mit Ihrer Übersetzungsdatei ein. Beiträge für jede Sprache sind willkommen.
