emdash-i18n-translations
v0.1.1
Published
Powerful internationalization (i18n) plugin for EmDash CMS. Manage unlimited translations across locales with a REST API and admin dashboard. Zero config, automatic caching, built-in coverage tracking.
Downloads
31
Maintainers
Readme
EmDash i18n
Internationalization plugin for EmDash CMS. Adds translation management to the CMS with a REST API, admin dashboard, CSV import/export, and MCP endpoints for AI-assisted workflows.
v0.1.1
Features
- REST API — fetch translations by key, locale, and namespace
- Admin dashboard — search, filter, and edit translations via Block Kit
- CSV import/export — bulk edit in Sheets, import back
- MCP endpoints — programmatic access for AI tools, including AI-assisted translation
- Locale routing — path (
/en), query (?lang=en), or both - Fallback chains —
esmissing? Returnsenautomatically - Coverage tracking — progress meters per locale
- Caching — KV with automatic invalidation
- Standard format — works trusted or sandboxed, marketplace-ready
Quick Start
1. Install
npm install emdash-i18n-translations2. Add to EmDash
// astro.config.mjs
import { i18nPlugin } from "emdash-i18n-translations";
export default defineConfig({
integrations: [
emdash({
plugins: [i18nPlugin()],
}),
],
});3. Configure (optional)
Defaults to en, es, fr, de.
i18nPlugin({
locales: ["en", "es", "fr", "ja"],
defaultLocale: "en",
fallbackChain: { es: "en", fr: "en", ja: "en" },
cacheTtl: 3600,
})4. Use
const API = "/_emdash/api/plugins/emdash-i18n";
// Single key
const res = await fetch(`${API}/get?locale=es&namespace=common&key=hero.title`);
const { value } = await res.json(); // "Bienvenido"
// All keys in a namespace
const res = await fetch(`${API}/getAll?locale=es&namespace=common`);
const { data } = await res.json(); // { "hero.title": "Bienvenido", ... }Helper:
// src/lib/i18n.ts
const API = "/_emdash/api/plugins/emdash-i18n";
export async function t(key: string, locale = "en", namespace = "common") {
const res = await fetch(`${API}/get?locale=${locale}&namespace=${namespace}&key=${key}`);
const { success, value } = await res.json();
return success ? value : key;
}5. Admin
Open Translations in the EmDash sidebar to search, edit, add, delete, and track coverage per locale. CSV import/export is available from the same page.
Locale Routing
Configurable in admin settings.
| Mode | Example | Description |
|------|---------|-------------|
| Path (default) | /en/about | Locale in URL path |
| Query | /about?lang=en | Locale as query param |
| Both | Either | Path takes precedence |
The plugin API always accepts ?locale=. Routing mode tells your frontend how to resolve the locale from URLs.
CSV
Export
curl /_emdash/api/plugins/emdash-i18n/exportkey,namespace,en,es,fr
hero.title,common,Welcome,Bienvenido,Bienvenue
hero.cta,common,Get Started,Comenzar,CommencerImport
curl -X POST /_emdash/api/plugins/emdash-i18n/import \
-H "Content-Type: application/json" \
-d '{ "csv": "key,namespace,en,es\nhero.title,common,Welcome,Bienvenido" }'Also available in the admin dashboard.
MCP Endpoints
For AI tools and external integrations. Under /_emdash/api/plugins/emdash-i18n/mcp/.
| Route | Method | Auth | Description |
|-------|--------|------|-------------|
| /mcp/translate | GET | Public | Get strings that need translation |
| /mcp/search | GET | Public | Search by query, locale, namespace |
| /mcp/bulk-set | POST | Admin | Bulk create/update |
| /mcp/bulk-delete | POST | Admin | Bulk delete |
| /mcp/export | GET | Public | Export as JSON or CSV |
| /mcp/namespaces | GET/POST | Mixed | List or register namespaces |
| /mcp/settings | GET/POST | Mixed | Read or update settings |
AI-assisted translation
The /mcp/translate endpoint returns source strings that are missing in a target locale. An AI tool reads them, translates, and writes the results back:
Step 1 — Get what needs translating:
curl "/_emdash/api/plugins/emdash-i18n/mcp/translate?targetLocale=es&sourceLocale=en"{
"count": 3,
"items": [
{ "key": "hero.title", "namespace": "pages", "sourceLocale": "en", "sourceValue": "Welcome to 5e Labs", "targetLocale": "es" },
{ "key": "hero.cta", "namespace": "pages", "sourceLocale": "en", "sourceValue": "Get Started", "targetLocale": "es" }
]
}Step 2 — Save the translations:
curl -X POST /_emdash/api/plugins/emdash-i18n/mcp/bulk-set \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "locale": "es", "namespace": "pages", "key": "hero.title", "value": "Bienvenido a 5e Labs" },
{ "locale": "es", "namespace": "pages", "key": "hero.cta", "value": "Comenzar" }
]
}'You can filter by namespace: ?targetLocale=es&namespace=blog
Export JSON
curl "/_emdash/api/plugins/emdash-i18n/mcp/export?format=json"{
"translations": {
"en": { "pages": { "hero.title": "Welcome" } },
"es": { "pages": { "hero.title": "Bienvenido" } }
}
}API Reference
All at /_emdash/api/plugins/emdash-i18n/<route>. JSON responses.
| Route | Method | Auth | Description |
|-------|--------|------|-------------|
| /get | GET | Public | Single translation |
| /getAll | GET | Public | All translations for locale + namespace |
| /set | POST | Admin | Create or update |
| /delete | POST | Admin | Delete |
| /stats | GET | Public | Coverage per locale |
| /export | GET | Public | CSV export |
| /import | POST | Admin | CSV import |
Fallback
When a key is missing and fallback is enabled:
{ "success": true, "value": "Welcome", "fallback": true, "fallbackLocale": "en" }Namespaces
Namespaces map to your site's content types. The plugin seeds defaults on install and auto-registers new namespaces when CMS content is saved — so if you create a Blog post, the blog namespace appears automatically.
Default namespaces: ui, pages, blog, projects
Example for a typical EmDash site:
| Namespace | Maps to |
|-----------|---------|
| ui | Shared interface — nav, buttons, footer |
| pages | CMS Pages collection |
| blog | Blog posts |
| projects | Portfolio / case studies |
| testimonials | Testimonials collection |
| brands | Brands / clients |
Register custom namespaces via MCP:
curl -X POST /_emdash/api/plugins/emdash-i18n/mcp/namespaces \
-H "Content-Type: application/json" \
-d '{ "namespaces": ["testimonials", "brands", "emails"] }'Keys use dot notation: hero.title, nav.about. Lowercase.
Architecture
src/
index.ts # Plugin descriptor (build time)
sandbox-entry.ts # Routes + hooks (request time)
api.ts # Core, CSV, MCP handlers
admin.ts # Block Kit admin UI
storage.ts # Database operations
cache.ts # KV caching
csv.ts # CSV parse/generate
validation.ts # Input validation
constants.ts # Config
types.ts # TypeScript interfacesStandard format plugin. Works trusted (in-process) or sandboxed (Cloudflare Workers). One translations collection with indexed fields. Settings and namespaces stored in KV. Auto-registers namespaces from CMS content via content:afterSave hook.
Development
git clone https://github.com/alfgago/emdash-i18n.git
cd emdash-i18n
npm install
npm run build
npm run dev # watch modeLink locally:
npm link
cd ../your-emdash-site
npm link emdash-i18n-translations
pnpm devRoadmap
v0.1 — Foundation (current)
- REST API (get, getAll, set, delete, stats)
- Block Kit admin dashboard with search/filter
- CSV import/export
- MCP endpoints (search, bulk ops, translate, namespaces)
- Fallback chains
- KV caching with auto-invalidation
- Locale routing options (path, query, both)
- Auto-register namespaces from CMS content types
v0.2 — Usability
- Pluralization support (
countparameter picks singular/plural form) - Interpolation (
Hello {{name}}→Hola {{name}}) - Translation context/notes (help translators understand usage)
- Admin: sort by missing, filter by completion status
- Admin: keyboard shortcuts for power users
v0.3 — Automation
- Google Translate / DeepL one-click auto-translate via
network:fetch - Translation change history (who changed what, when)
- Diff view: compare source vs translation side-by-side
- Webhook on translation update (notify external systems)
v0.4 — Workflow
- Roles: translator, reviewer, admin
- Review queue: approve/reject translations before publish
- Draft vs published translation states
- Email notifications for review requests
v1.0 — Stable
- Locked API (no breaking changes going forward)
- Full test suite (unit + integration)
- Published to EmDash marketplace
- Documentation site
License
MIT
Links
- GitHub · Issues · EmDash CMS · Contributing · Publishing
