Replies: 8 comments 1 reply
-
|
I would like to discuss how plugins might be able to ship translations, both for native and sandboxed plugins. I think there a few possible ways, but I'd be open to ideas. For templates, I think we should stick to Astro's i18n, but we could see about whether we should include it in the default templates |
Beta Was this translation helpful? Give feedback.
-
|
Since opening this discussion, I've implemented the plugin-owned translation approach in our AWCMS-Micro fork. It's working well with both native and sandboxed plugin boundaries. Here's what we built: 1. Manifest-based i18n catalogEach plugin ships its own translation catalog inline in the manifest: // runtime.ts
export const AWCMS_EXAMPLE_MANIFEST = {
id: "awcms-micro-example",
i18n: {
defaultLocale: "en",
supportedLocales: ["en", "id"],
messages: {
en: {
"awcms.nav.group.dashboard": "Dashboard",
"awcms.nav.overview": "Overview",
"awcms.nav.access": "Access Control",
},
id: {
"awcms.nav.group.dashboard": "Dasbor",
"awcms.nav.overview": "Ikhtisar",
"awcms.nav.access": "Kontrol Akses",
}
}
}
};2.
|
| Aspect | Result |
|---|---|
| Decoupling | Plugin translations ship with the plugin — no core catalog changes needed |
| Sandbox-compatible | resolveLabel is pure JS — works in native React pages and sandboxed routes |
| Multi-locale | English + Indonesian shipped; adding a third is just one more key in messages |
| No Lingui in sandbox | Sandboxed plugins use plain resolveLabel; native plugins can use Lingui macros |
What we'd do differently
- Larger plugins might benefit from shipping
.jsonfiles instead of inlinemessagesobjects. TheresolveLabelAPI stays the same. - We considered a
ctx.translate(key)API for sandboxed routes but haven't needed it — the manifest pattern covers all our use cases.
Templates
We stuck with Astro's i18n for templates. EmDash starter templates can follow Astro's routing + i18n patterns without needing a separate template translation layer.
TL;DR
Plugins should own their translation catalogs entirely. EmDash only needs to provide:
- The locale resolution context (which locale is active)
- A small lookup utility (
resolveLabel)
Everything else — catalog format, key naming, supported locales — stays with the plugin author.
Beta Was this translation helpful? Give feedback.
-
|
I don't think the manifest would be the right place for it. It should be .po files, probably compiled during publish. |
Beta Was this translation helpful? Give feedback.
-
|
@ascorbic Thanks, that makes sense. I’ll revise my previous plan and move to |
Beta Was this translation helpful? Give feedback.
-
|
As a follow-up, I have now written down the The intent there is to keep it aligned with EmDashs existing translation model and with the guidance in this discussion:
A few concrete examples from that standard, so the idea is understandable without opening the doc:
Im using that standard first in the standalone plugin work as an implementation example, so the approach can be tested in practice before proposing anything broader upstream. |
Beta Was this translation helpful? Give feedback.
-
|
@ascorbic One follow-up question: would you be open to this same Im asking because if the standalone plugin example proves out cleanly, it seems like it could also provide a consistent direction for first-party plugin UI strings and template copy, while still keeping templates aligned with Astro i18n where appropriate. |
Beta Was this translation helpful? Give feedback.
-
|
@ascorbic As a next step, would you be open to a PR proposal that aligns plugin and template i18n with the I would scope it as two related but separable tracks. Plugin i18nFor plugins, I would avoid manifest-inline translation objects and use plugin-owned The concrete work would be:
The first-party plugin surfaces I would expect to cover are:
For sandboxed plugins, the important part is that the runtime should not require Lingui macros to execute inside the sandbox. Native React admin pages can use Lingui directly, but sandboxed or non-React surfaces should be able to consume compiled catalog output through a small adapter. Built-in template i18nFor templates, I agree with the earlier direction that they should stay aligned with Astro i18n rather than inventing a separate EmDash-only template translation layer. The concrete work would be:
Existing reference implementationI have already been testing this direction in https://github.com/ahliweb/awcms-micro The more specific standard I wrote down there is: That implementation is useful as a proof-of-concept because it keeps translations inside the plugin/template package boundary, uses English Suggested PR strategyI would keep the upstream work atomic:
That should make the direction reviewable without coupling plugin i18n, template i18n, and all first-party migrations into one large change. |
Beta Was this translation helpful? Give feedback.
-
|
Looking forward to this! Let me know if you need a helping hand. :) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Problem
EmDash currently has no translation infrastructure for plugins or templates. The only i18n in the system is:
.pocatalogs inpackages/admin/src/locales/.pofiles, no translation API, no i18n hooks.astrofilesConcrete impact
Plugins — A plugin that adds a settings page, dashboard widget, or custom block type has no way to present translated UI. All strings are hardcoded English:
Templates — Starter templates (blog, portfolio, marketing) render labels like "Read more", "Published on", "Next post" in English only. There's no mechanism for site builders to translate template strings.
What plugins currently have access to
ctx.site.locale— read-only, always availablecontent.locale— per-content-item locale fieldContentListWhere.locale— query filterBut there's no way to serve translated plugin UI strings based on this locale.
Proposed discussion points
.pocatalogs? Or should the admin UI catalog absorb plugin strings?PluginContext.translate(key, locale)API)?ctx.site.localeis exposed.Related
@ascorbic — would appreciate your thoughts on whether this is on the roadmap or if there is a preferred approach.
Beta Was this translation helpful? Give feedback.
All reactions