TL;DR: Mit einem n8n-Workflow, Ghost-Webhooks und einer Übersetzungs-API (DeepL oder OpenAI) kannst du jeden neuen Blog-Artikel automatisch übersetzen und als verknüpftes DE/EN-Paar veröffentlichen. Kein manuelles Copy-Paste mehr – einmal publizieren, automatisch cross-posten.

🌍 Einleitung: Warum zweisprachig bloggen so aufwendig ist

Wenn du einen Blog in zwei Sprachen betreibst, kennst du das Problem: Jeder Artikel muss übersetzt, formatiert und als eigenständiger Post veröffentlicht werden. Links, Bilder, Tags – alles muss stimmen. Das kostet Zeit und ist fehleranfällig.

Die gute Nachricht: Mit n8n und der Ghost Admin API lässt sich dieser Prozess vollständig automatisieren. In diesem Artikel zeige ich dir, wie du einen Workflow baust, der bei jeder Veröffentlichung automatisch eine übersetzte Version erstellt.

Ghost: Das bessere WordPress
Warum Ghost die bessere Blogging-Plattform ist

🎯 Die Herausforderung: DE/EN-Paare konsistent halten

Ein zweisprachiger Blog stellt dich vor mehrere Herausforderungen:

  • Synchronisation: Jeder Artikel braucht ein Gegenstück in der anderen Sprache
  • Verlinkung: Die Sprachversionen müssen miteinander verknüpft sein
  • Formatierung: HTML-Struktur, Bilder und Code-Blöcke dürfen nicht kaputtgehen
  • Updates: Wird der Originalartikel aktualisiert, sollte die Übersetzung folgen

Manuell ist das bei wachsender Artikelanzahl kaum zu bewältigen. Automatisierung ist der Schlüssel.

🏗️ Architektur: So funktioniert der Workflow

Die Architektur ist im Kern einfach:

  1. Ghost Webhook feuert bei post.published
  2. n8n Webhook-Node empfängt das Event
  3. Ghost Admin API liefert den vollständigen Post-Inhalt
  4. Übersetzungs-API (DeepL oder OpenAI) übersetzt den HTML-Content
  5. Ghost Admin API erstellt den übersetzten Post mit Relation-Tags

Das Zusammenspiel von Ghost und n8n macht diese Pipeline besonders elegant – beide Tools sind API-first gebaut und lassen sich hervorragend kombinieren.

n8n Unleashed: Ultimative Workflow-Automatisierung

⚡ Ghost Webhook einrichten: Trigger auf post.published

In Ghost richtest du unter Settings → Integrations → Custom Integration einen Webhook ein:

  • Event: post.published
  • Target URL: Die URL deines n8n-Webhook-Nodes (z.B. https://n8n.example.com/webhook/translate-post)

Ghost sendet bei jeder Veröffentlichung ein JSON-Payload mit der Post-ID und grundlegenden Metadaten. Den vollständigen Content holen wir uns anschließend über die Admin API.

{
  "post": {
    "current": {
      "id": "63a1b2c3d4e5f6...",
      "title": "Mein neuer Artikel",
      "slug": "mein-neuer-artikel",
      "status": "published"
    }
  }
}

🔧 n8n Workflow Design: Schritt für Schritt

Der Workflow in n8n besteht aus fünf Hauptnodes:

1. Webhook Trigger Node

Erstelle einen Webhook-Node als Trigger. Wähle POST als HTTP-Methode. Der Node empfängt das Ghost-Webhook-Payload und startet den Workflow.

Wichtig: Füge eine Bedingung hinzu, die prüft, ob der Post bereits ein übersetzter Post ist (z.B. durch Prüfung der Tags). Sonst entsteht eine Endlosschleife!

2. HTTP Request: Post-Content abrufen

Mit der Post-ID aus dem Webhook holst du dir den vollständigen Artikel über die Ghost Admin API:

GET /ghost/api/admin/posts/{{postId}}/?formats=html,mobiledoc

Du brauchst das html-Format für die Übersetzung und die Metadaten für Tags, Feature-Image und Excerpt.

3. Translation Node: DeepL oder OpenAI

Für die eigentliche Übersetzung hast du zwei gute Optionen:

Option A – DeepL API:

// n8n Function Node – DeepL Request vorbereiten
const html = $input.item.json.posts[0].html;
const title = $input.item.json.posts[0].title;

return {
  json: {
    text: [html, title],
    source_lang: "DE",
    target_lang: "EN",
    tag_handling: "html"
  }
};

DeepL hat den Vorteil, dass es HTML-Tags nativ versteht und die Struktur beibehält (tag_handling: "html").

Option B – OpenAI API:

// n8n Function Node – OpenAI Prompt
const html = $input.item.json.posts[0].html;

return {
  json: {
    model: "gpt-4o",
    messages: [
      {
        role: "system",
        content: "Translate the following HTML blog post from German to English. Keep ALL HTML tags intact. Do not translate code blocks. Return only the translated HTML."
      },
      {
        role: "user",
        content: html
      }
    ]
  }
};

OpenAI ist flexibler bei Kontext und Stil, braucht aber ein präzises Prompt, um die HTML-Struktur nicht zu verändern.

4. HTTP Request: Übersetzten Post erstellen

Der übersetzte Content wird als neuer Post via Ghost Admin API erstellt:

// n8n Function Node – Post-Daten vorbereiten
const original = $input.item.json.posts[0];
const translatedHtml = $input.item.json.translated_html;
const translatedTitle = $input.item.json.translated_title;

return {
  json: {
    posts: [{
      title: translatedTitle,
      html: translatedHtml,
      status: "draft", // Erst als Draft, zur Kontrolle
      feature_image: original.feature_image,
      feature_image_alt: original.feature_image_alt,
      feature_image_caption: original.feature_image_caption,
      custom_excerpt: translatedExcerpt,
      tags: [
        {name: "#en"},
        {name: "#crosspost"},
        {name: `#rel-en-${original.id}`}
      ]
    }]
  }
};

5. Relation-Tags setzen

Die Verknüpfung zwischen Original und Übersetzung funktioniert über interne Tags:

  • Originalartikel bekommt: #rel-de-{id}
  • Übersetzter Artikel bekommt: #rel-en-{id}

In Ghost sind Tags mit #-Prefix intern und für Leser nicht sichtbar. Du kannst sie aber in Templates und der API nutzen, um Sprachpaare zu finden.

🖼️ Bilder und Feature Images: URLs einfach übernehmen

Das Schöne an Ghost: Bilder werden über URLs referenziert. Du musst sie nicht kopieren oder neu hochladen – die gleichen URLs funktionieren in beiden Sprachversionen.

Übernimm einfach folgende Felder 1:1 vom Original:

  • feature_image – Das Hauptbild des Artikels
  • feature_image_alt – Alt-Text (ggf. übersetzen!)
  • feature_image_caption – Bildunterschrift (übersetzen!)
  • Alle <img>-Tags im HTML – URLs bleiben gleich

Tipp: Alt-Texte und Captions solltest du mitübersetzen lassen – das ist gut für SEO und Accessibility.

🔑 Ghost JWT Auth in n8n: Code-Snippet für den Function Node

Ghost verwendet JWT-Tokens für die Admin API-Authentifizierung. In n8n kannst du das Token im Function Node generieren:

// n8n Function Node – Ghost JWT Token generieren
const crypto = require('crypto');

const adminKey = $env.GHOST_ADMIN_API_KEY; // Format: "id:secret"
const [id, secret] = adminKey.split(':');

// Header
const header = Buffer.from(JSON.stringify({
  alg: 'HS256',
  kid: id,
  typ: 'JWT'
})).toString('base64url');

// Payload
const now = Math.floor(Date.now() / 1000);
const payload = Buffer.from(JSON.stringify({
  iat: now,
  exp: now + 5 * 60, // 5 Minuten gültig
  aud: '/admin/'
})).toString('base64url');

// Signature
const signingInput = `${header}.${payload}`;
const signature = crypto
  .createHmac('sha256', Buffer.from(secret, 'hex'))
  .update(signingInput)
  .digest('base64url');

const token = `${signingInput}.${signature}`;

return {
  json: {
    token,
    ghostUrl: $env.GHOST_API_URL
  }
};

Dieses Token setzt du dann im HTTP Request Node als Authorization: Ghost {token} Header.

⚠️ Edge Cases: Updates und Endlosschleifen vermeiden

Ein paar Fallstricke, die du beachten solltest:

Endlosschleife verhindern

Wenn der übersetzte Post veröffentlicht wird, feuert der Webhook erneut. Ohne Schutz übersetzt n8n die Übersetzung zurück – endlos.

Lösung: Prüfe im Workflow, ob der Post einen #crosspost-Tag hat. Wenn ja → Workflow abbrechen.

// n8n IF-Node Bedingung
const tags = $input.item.json.post.current.tags || [];
const isCrosspost = tags.some(t => t.name === '#crosspost');

// Wenn isCrosspost === true → Stop
return !isCrosspost;

Bestehende Übersetzungen aktualisieren

Wird der Originalartikel aktualisiert, willst du nicht einen neuen übersetzten Post, sondern den bestehenden aktualisieren.

Lösung: Suche vor dem Erstellen nach einem Post mit dem passenden Relation-Tag:

// Prüfe, ob bereits eine Übersetzung existiert
const originalId = $input.item.json.post.current.id;
const relTag = `#rel-en-${originalId}`;

// Ghost API: Posts nach internem Tag filtern
// GET /ghost/api/admin/posts/?filter=tag:hash-rel-en-{id}
// Wenn Ergebnis: PUT (update), sonst: POST (create)

Weitere Edge Cases

  • Code-Blöcke nicht übersetzen: DeepL mit tag_handling: "html" erkennt <pre>/<code> nicht immer. Schließe sie ggf. manuell aus.
  • Slug generieren: Lass Ghost den Slug automatisch aus dem übersetzten Titel generieren – nicht manuell setzen.
  • Rate Limits: DeepL Free erlaubt 500.000 Zeichen/Monat. Bei vielen Posts reicht das schnell nicht.

🎬 Fazit

Mit n8n, Ghost Webhooks und einer Übersetzungs-API kannst du deinen zweisprachigen Blog vollständig automatisieren. Der initiale Setup-Aufwand lohnt sich schnell: Statt bei jedem Artikel manuell zu übersetzen, publizierst du einfach in deiner Hauptsprache – der Rest passiert automatisch.

Die Kombination aus Ghost und n8n ist dabei besonders stark, weil beide Tools API-first denken und sich nahtlos integrieren lassen. Und mit den Relation-Tags hast du eine saubere Methode, um Sprachpaare programmatisch zu verknüpfen.

Nächste Schritte für dich:

  • n8n-Instanz aufsetzen (Self-Hosted oder Cloud)
  • Ghost Custom Integration + Webhook erstellen
  • DeepL oder OpenAI API-Key besorgen
  • Workflow importieren und testen

Viel Spaß beim Automatisieren! 🚀

Artikel teilen:Share article: