Auto‑Translate Ghost Blog Posts into 8 Languages for SEO
Published on 2026‑09‑25 • 8‑minute read
Why multilingual Ghost posts?
Ghost is a popular, headless CMS for publishing. By default it serves content in a single language, which limits organic traffic from non‑English markets. Translating each article manually is time‑consuming and error‑prone. With SiteLocaleAI you can:
- Translate on the fly using your own LLM API key (Claude, GPT‑4o‑mini, etc.).
- Localize prices with psychological rounding per currency.
- Pre‑render translated pages so Google and Bing index the full HTML, boosting international SEO.
- Stay self‑hosted, keeping data and keys under your control.
Below is a step‑by‑step technical guide to turn a standard Ghost installation into a multilingual, SEO‑ready publishing engine.
Prerequisites
| Item | Minimum version |
|---|---|
| Ghost | 5.0+ (self‑hosted or Ghost(Pro) with custom theme) |
| Node.js | 18.x |
| npm / yarn | latest |
| LLM API key | Claude, GPT‑4o‑mini, or any OpenAI‑compatible endpoint |
| SiteLocaleAI package | @sitelocaleai/translate (npm) |
1. Install the SiteLocaleAI JS library
From your Ghost theme directory (e.g., content/themes/my‑theme), run:
npm install @sitelocaleai/translate
The library is framework‑agnostic, so you can import it in any front‑end script.
2. Create a tiny translation helper
Add a new file src/translate.js (or any location you prefer) with the following code:
// src/translate.js
import { LocaleAI } from '@sitelocaleai/translate';
// Pull your LLM API key from an environment variable (never hard‑code!).
const localeAI = new LocaleAI({
apiKey: process.env.SITELOCALEAI_API_KEY,
provider: 'openai', // or 'anthropic' for Claude
model: 'gpt-4o-mini', // adjust as needed
});
/**
* Translate raw HTML content into the target language.
* @param {string} html The original Ghost post HTML.
* @param {string} lang ISO‑639‑1 language code (e.g., 'de', 'fr').
* @returns {Promise<string>} Translated HTML.
*/
export async function translatePost(html, lang) {
// Preserve HTML tags while translating the textual nodes.
const translated = await localeAI.translateHTML(html, {
targetLang: lang,
// Enable price localisation – the library will detect $/£/€ etc.
priceLocalization: true,
// Psychological rounding (e.g., $9.99 → $9.95)
rounding: true,
});
return translated;
}
This helper will be called from a Ghost webhook (next section).
3. Set up a Ghost webhook to trigger translation
In the Ghost Admin panel, go to Integrations → Webhooks → Add webhook.
- Event:
post.published - URL:
https://your‑domain.com/api/translate - Method:
POST
Create a lightweight Express endpoint (or any serverless function) that receives the post payload, runs the translation, and stores the results back into Ghost via its Content API.
// server/translate-webhook.js
import express from 'express';
import bodyParser from 'body-parser';
import { translatePost } from '../src/translate.js';
import GhostContentAPI from '@tryghost/content-api';
const app = express();
app.use(bodyParser.json());
const ghost = new GhostContentAPI({
url: process.env.GHOST_URL,
key: process.env.GHOST_ADMIN_KEY,
version: 'v5.0',
});
// Target languages – eight of them
const LANGUAGES = ['de', 'fr', 'es', 'ja', 'zh', 'pt', 'it', 'nl'];
app.post('/api/translate', async (req, res) => {
const { post } = req.body;
const originalHtml = post.html;
const slug = post.slug;
// Translate in parallel
const translations = await Promise.all(
LANGUAGES.map(async (lang) => {
const translatedHtml = await translatePost(originalHtml, lang);
// Create a new Ghost post for the language version
const newPost = await ghost.posts.add({
title: `${post.title} (${lang.toUpperCase()})`,
html: translatedHtml,
status: 'published',
// Use a language‑specific slug for SEO
slug: `${slug}-${lang}`,
// Add a custom tag so we can filter later
tags: [{ name: `lang:${lang}` }],
});
return newPost;
})
);
console.log(`✅ Translated post ${slug} into ${LANGUAGES.length} languages`);
res.status(200).json({ success: true, translations });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`🚀 Translation webhook listening on ${PORT}`));
Tip: Deploy this endpoint on the same host as your Ghost installation or on a cheap VPS. Because the library is self‑hosted, you only pay for the LLM calls.
4. Pre‑render translated pages for SEO
Search engines struggle with client‑side translations. SiteLocaleAI ships a CLI that crawls your site, fetches each language version, and writes static HTML files that can be served directly.
# Install the CLI globally (optional)
npm i -g @sitelocaleai/cli
# Run the pre‑render for the eight languages
sitelocaleai prerender \
--site https://your‑domain.com \
--langs de,fr,es,ja,zh,pt,it,nl \
--output ./static-multilingual
The CLI performs the following:
1. Requests each /slug‑lang page.
2. Executes the same LLM translation pipeline on the server side (ensuring the same price localisation).
3. Saves the fully rendered HTML to ./static-multilingual/<lang>/<slug>.html.
You can now configure your web server (NGINX, Apache, or a CDN) to serve these static files to crawlers based on the Accept‑Language header or a URL prefix (/de/, /fr/, …). This gives you full SEO indexing without sacrificing the dynamic nature of Ghost for human visitors.
5. Verify multilingual SEO
Use Google Search Console → URL Inspection to fetch each language URL. You should see the translated <title> and <meta description> tags.
<title>Cómo preparar café perfecto – Ghost Blog</title>
<meta name="description" content="Aprende a preparar café de calidad profesional con estos pasos sencillos.">
Make sure the hreflang tags are present in the <head> of every page. You can inject them via a Ghost helper:
{{!-- in your default.hbs layout --}}
{{#foreach languages}}
<link rel="alternate" hreflang="{{this}}" href="{{siteUrl}}/{{this}}/{{slug}}" />
{{/foreach}}
The languages array can be populated from the LANGUAGES constant you used earlier.
6. Optional: WordPress‑style plugin for non‑technical editors
If your editorial team prefers a UI, SiteLocaleAI also offers a WordPress‑style plugin that runs entirely in the browser—no Node.js required. You can embed the same translatePost function into a Ghost admin custom integration, exposing a “Translate” button that triggers the same workflow.
For details, see the official docs: https://sitelocaleai.com/docs/plugin‑integration
7. Monitoring costs and performance
Because you provide the LLM API key, you control the cost per token. A typical 800‑word blog post translates to ~1200 tokens per language. With GPT‑4o‑mini at $0.0005 per 1k tokens, the cost for eight languages is roughly $0.0048 per post—well under a cent.
You can log token usage via the localeAI.on('usage', ...) event and feed it into your analytics dashboard.
8. Wrap‑up
With just a few lines of JavaScript, a webhook, and a one‑time CLI run, your Ghost blog now:
- Serves eight fully translated, SEO‑friendly pages.
- Localizes prices with psychological rounding for each market.
- Pre‑renders static HTML that search engines love.
- Keeps data private by using your own LLM API keys.
Ready to boost your international traffic? Try SiteLocaleAI today and watch your Ghost blog go global.
🚀 Try SiteLocaleAI now – head over to https://sitelocaleai.com/docs to get started and see the full documentation.