Handlebars
Lokalisieren Sie Handlebars-Templates mit Lingo.dev CLI
Was ist Handlebars?
Handlebars ist eine beliebte Template-Engine, die die notwendige Leistung bietet, um semantische Templates effektiv zu erstellen. Sie verwendet eine klare Syntax und kompiliert Templates in JavaScript-Funktionen, wodurch sie sowohl in clientseitigen als auch in serverseitigen Anwendungen weit verbreitet zur HTML-Generierung eingesetzt wird.
Was ist Lingo.dev CLI?
Lingo.dev CLI ist eine kostenlose, quelloffene CLI zur Übersetzung von Apps und Inhalten mit KI. Sie wurde entwickelt, um traditionelle Translation-Management-Software zu ersetzen und sich gleichzeitig in bestehende Pipelines zu integrieren.
Weitere Informationen finden Sie unter Übersicht.
Über diesen Leitfaden
Dieser Leitfaden erklärt, wie Sie Handlebars-Templates mit Lingo.dev CLI lokalisieren.
Sie lernen:
- Wie Sie Übersetzungsdateien für Handlebars-Projekte strukturieren
- Wie Sie eine Übersetzungs-Pipeline konfigurieren
- Wie Sie Übersetzungen mit KI generieren
Voraussetzungen
Um Lingo.dev CLI zu verwenden, stellen Sie sicher, dass Node.js v18+ installiert ist:
❯ node -v
v22.17.0
Der Handlebars-Lokalisierungsansatz
Handlebars-Templates sollten auf übersetzbare Inhalte aus JSON-Dateien verweisen, anstatt fest codierten Text zu enthalten. Dieser Ansatz bietet:
- Klare Trennung: Template-Struktur vs. übersetzbare Inhalte
- Versionskontrolle: Übersetzungen werden in JSON-Dateien nachverfolgt
- Keine Mehrdeutigkeit: Explizite Definition dessen, was übersetzbar ist
Um auf Übersetzungen in Templates zuzugreifen, benötigen Sie eine Übersetzungs-Hilfsfunktion. Gängige Optionen sind:
Einfacher benutzerdefinierter Helper:
{{t "product.title"}}
{{t "greeting" name="John"}}
handlebars-i18n - Funktionsreich mit Formatierung:
{{__ "product.title"}}
{{_date releaseDate}}
{{_price amount "USD"}}
handlebars-i18next - Alternative i18next-Integration:
{{t "product.title"}}
Dieser Leitfaden verwendet {{t}} in den Beispielen, aber der Workflow gilt für jede Helper-Wahl.
Schritt 1. Projekt einrichten
Erstellen Sie im Verzeichnis Ihres Projekts eine i18n.jsonDatei:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
Diese Datei definiert das Verhalten der Übersetzungs-Pipeline, einschließlich der Sprachen, zwischen denen übersetzt werden soll, und wo sich die lokalisierbaren Inhalte im Dateisystem befinden.
Um mehr über die verfügbaren Eigenschaften zu erfahren, siehe i18n.json.
Schritt 2. Source-Locale konfigurieren
Die Source-Locale ist die ursprüngliche Sprache und Region, in der Ihr Inhalt verfasst wurde. Um die Source-Locale zu konfigurieren, setzen Sie die Eigenschaft locale.source in der Datei i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
Die Source-Locale muss als BCP 47 Language Tag angegeben werden.
Für die vollständige Liste der Locale-Codes, die Lingo.dev CLI unterstützt, siehe Unterstützte Locale-Codes.
Schritt 3. Target-Locales konfigurieren
Die Target-Locales sind die Sprachen und Regionen, in die Sie Ihren Inhalt übersetzen möchten. Um die Target-Locales zu konfigurieren, setzen Sie die Eigenschaft locale.targets in der Datei i18n.json:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {}
}
Schritt 4. Source-Content erstellen
Erstellen Sie JSON-Dateien mit Ihrem übersetzbaren Inhalt. Diese Dateien sollten in einer Verzeichnisstruktur organisiert sein, die den Source-Locale-Code enthält:
project/
├── locales/
│ └── en/
│ ├── common.json
│ └── store.json
├── templates/
│ └── product.handlebars
└── i18n.json
Das Verzeichnis es/ und die übersetzten Dateien werden automatisch von Lingo.dev CLI erstellt, wenn Sie in Schritt 8 Übersetzungen generieren.
Beispiel-JSON-Dateien
locales/en/common.json:
{
"navigation": {
"home": "Home",
"products": "Products",
"about": "About",
"contact": "Contact"
},
"footer": {
"copyright": "All rights reserved",
"privacy": "Privacy Policy",
"terms": "Terms of Service"
}
}
locales/en/store.json:
{
"product": {
"title": "Wireless Headphones",
"description": "Premium sound quality with active noise cancellation",
"price": "Price",
"inStock": "In Stock",
"outOfStock": "Out of Stock"
},
"cart": {
"add": "Add to Cart"
},
"actions": {
"buyNow": "Buy Now"
}
}
Schritt 5. Bucket erstellen
-
Fügen Sie in der
i18n.jsonDatei ein"json"Objekt zumbucketsObjekt hinzu:{ "$schema": "https://lingo.dev/schema/i18n.json", "version": "1.10", "locale": { "source": "en", "targets": ["es"] }, "buckets": { "json": {} } } -
Definieren Sie im
"json"Objekt ein Array mit einem oder mehrerenincludeMustern:{ "$schema": "https://lingo.dev/schema/i18n.json", "version": "1.10", "locale": { "source": "en", "targets": ["es"] }, "buckets": { "json": { "include": ["./locales/[locale]/*.json"] } } }Diese Muster definieren, welche Dateien übersetzt werden sollen.
Die Muster selbst:
- müssen
[locale]als Platzhalter für die konfigurierte Locale enthalten - können auf Dateipfade verweisen (z. B.
"locales/[locale]/common.json") - können Sternchen als Wildcard-Platzhalter verwenden (z. B.
"locales/[locale]/*.json")
Rekursive Glob-Muster (z. B.
**/*.json) werden nicht unterstützt. - müssen
Schritt 6. Übersetzungen in Templates verwenden
Referenzieren Sie Übersetzungsschlüssel in Ihren Handlebars-Templates mithilfe Ihres gewählten Helpers:
templates/product.handlebars:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{t "product.title"}}</title>
</head>
<body>
<nav>
<a href="/">{{t "navigation.home"}}</a>
<a href="/products">{{t "navigation.products"}}</a>
<a href="/about">{{t "navigation.about"}}</a>
<a href="/contact">{{t "navigation.contact"}}</a>
</nav>
<main>
<article>
<h1>{{t "product.title"}}</h1>
<p>{{t "product.description"}}</p>
<div class="price">
<span>{{t "product.price"}}:</span>
<span>$299.99</span>
</div>
<div class="stock">
{{#if inStock}}
<span class="available">{{t "product.inStock"}}</span>
{{else}}
<span class="unavailable">{{t "product.outOfStock"}}</span>
{{/if}}
</div>
<div class="actions">
<button class="primary">{{t "cart.add"}}</button>
<button class="secondary">{{t "actions.buyNow"}}</button>
</div>
</article>
</main>
<footer>
<p>{{t "footer.copyright"}}</p>
<a href="/privacy">{{t "footer.privacy"}}</a>
<a href="/terms">{{t "footer.terms"}}</a>
</footer>
</body>
</html>
Wie Sie diese Übersetzungen laden und Ihre Templates kompilieren, hängt von Ihrem Build-Setup und der gewählten Helper-Bibliothek ab.
Schritt 7. LLM konfigurieren
Die Lingo.dev CLI verwendet Large Language Models (LLMs), um Inhalte mit KI zu übersetzen. Um eines dieser Modelle zu verwenden, benötigen Sie einen API-Schlüssel von einem unterstützten Anbieter.
Um so schnell wie möglich loszulegen, empfehlen wir die Verwendung der Lingo.dev Engine:
-
Führen Sie den folgenden Befehl aus:
npx lingo.dev@latest loginDies öffnet Ihren Standard-Browser und fordert Sie zur Authentifizierung auf.
-
Folgen Sie den Anweisungen.
Schritt 8. Übersetzungen generieren
Führen Sie im Verzeichnis, das die i18n.json Datei enthält, den folgenden Befehl aus:
npx lingo.dev@latest run
Dieser Befehl:
- Liest die
i18n.jsonDatei. - Findet die JSON-Dateien, die übersetzt werden müssen.
- Extrahiert den übersetzbaren Inhalt aus den Dateien.
- Verwendet das konfigurierte LLM, um den extrahierten Inhalt zu übersetzen.
- Schreibt den übersetzten Inhalt zurück in das Dateisystem.
Beim ersten Mal, wenn Übersetzungen generiert werden, wird eine i18n.lock Datei erstellt. Diese Datei verfolgt, welche Inhalte übersetzt wurden, und verhindert unnötige erneute Übersetzungen bei nachfolgenden Durchläufen.
Beispiel
Projektstruktur
handlebars-localization/
├── locales/
│ ├── en/
│ │ ├── common.json
│ │ └── store.json
│ └── es/
│ ├── common.json
│ └── store.json
├── templates/
│ └── product.handlebars
└── i18n.json
locales/en/common.json
{
"navigation": {
"home": "Home",
"products": "Products",
"about": "About",
"contact": "Contact"
},
"footer": {
"copyright": "All rights reserved",
"privacy": "Privacy Policy",
"terms": "Terms of Service"
}
}
locales/en/store.json
{
"product": {
"title": "Wireless Headphones",
"description": "Premium sound quality with active noise cancellation",
"price": "Price",
"inStock": "In Stock",
"outOfStock": "Out of Stock"
},
"cart": {
"add": "Add to Cart"
},
"actions": {
"buyNow": "Buy Now"
}
}
locales/es/common.json
{
"navigation": {
"home": "Inicio",
"products": "Productos",
"about": "Acerca de",
"contact": "Contacto"
},
"footer": {
"copyright": "Todos los derechos reservados",
"privacy": "Política de privacidad",
"terms": "Términos de servicio"
}
}
locales/es/store.json
{
"product": {
"title": "Auriculares inalámbricos",
"description": "Calidad de sonido premium con cancelación activa de ruido",
"price": "Precio",
"inStock": "En stock",
"outOfStock": "Agotado"
},
"cart": {
"add": "Añadir al carrito"
},
"actions": {
"buyNow": "Comprar ahora"
}
}
templates/product.handlebars
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{t "product.title"}}</title>
</head>
<body>
<nav>
<a href="/">{{t "navigation.home"}}</a>
<a href="/products">{{t "navigation.products"}}</a>
<a href="/about">{{t "navigation.about"}}</a>
<a href="/contact">{{t "navigation.contact"}}</a>
</nav>
<main>
<article>
<h1>{{t "product.title"}}</h1>
<p>{{t "product.description"}}</p>
<div class="price">
<span>{{t "product.price"}}:</span>
<span>$299.99</span>
</div>
<div class="stock">
{{#if inStock}}
<span class="available">{{t "product.inStock"}}</span>
{{else}}
<span class="unavailable">{{t "product.outOfStock"}}</span>
{{/if}}
</div>
<div class="actions">
<button class="primary">{{t "cart.add"}}</button>
<button class="secondary">{{t "actions.buyNow"}}</button>
</div>
</article>
</main>
<footer>
<p>{{t "footer.copyright"}}</p>
<a href="/privacy">{{t "footer.privacy"}}</a>
<a href="/terms">{{t "footer.terms"}}</a>
</footer>
</body>
</html>
i18n.json
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.10",
"locale": {
"source": "en",
"targets": ["es"]
},
"buckets": {
"json": {
"include": ["./locales/[locale]/*.json"]
}
}
}
i18n.lock
version: 1
checksums:
8a4f2c9e1d6b3a7f5e8c2d1b9a3f6e4c:
navigation.home: 7b2e4f9a1c8d3b6f5e2a9d1c8b4f7e3a
navigation.products: 3f8e2a9d1c6b4f7e5a2c9d1b8f4e7a3b
navigation.about: 9d1c8b4f7e3a2f9e1d6b3a7f5e8c2d1b
navigation.contact: 4f7e3a2c9d1b8f6e5a3f2d9c1b7e4a8f
footer.copyright: 2c9d1b8f4e7a3b6f5e2a9d1c8b4f7e3a
footer.privacy: 8b4f7e3a2c9d1b6f5e2a9d1c8f4e7a3b
footer.terms: 6f5e2a9d1c8b4f7e3a2c9d1b8f4e7a3b
3b6f5e2a9d1c8b4f7e3a2c9d1b8f4e7a:
product.title: 1c8b4f7e3a2c9d1b6f5e2a9d1c8f4e7a
product.description: 7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c9d
product.price: 9d1b6f5e2a9d1c8b4f7e3a2c9d1b8f4e
product.inStock: 4f7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c
product.outOfStock: 2c9d1b6f5e2a9d1c8b4f7e3a2c9d1b8f
cart.add: 8b4f7e3a2c9d1b6f5e2a9d1c8b4f7e3a
actions.buyNow: 7e3a2c9d1b6f5e2a9d1c8b4f7e3a2c9d