Deutsch
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 ü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:
- Kopieren Sie
packages/editor/src/i18n/locales/en.tsin eine neue Datei, benannt nach Ihrem Locale-Code (z. B.<locale>.ts) - Übersetzen Sie alle String-Werte, behalten Sie die Schlüsselstruktur bei und annotieren Sie das Objekt mit
typeof en(siehe Beispiel unten) - Führen Sie
pnpm run typecheckaus — durch dietypeof en-Annotation schlagen fehlende, überzählige oder falsch verschachtelte Schlüssel bereits zur Compile-Zeit fehl - Führen Sie
pnpm run testaus, 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.