Summary
With emdash:locale = "ja" set on a site that has otherwise switched to Japanese, the invite acceptance page and invite email template remain in English. Both surfaces bypass the lingui i18n machinery used elsewhere in the admin and auth packages.
Repro
- Set
emdash:locale = "ja" in the options table.
- Confirm
/_emdash/admin/... (settings, content list, etc.) renders in Japanese — locale is being picked up correctly.
- Invite a new user with
Send invite. The recipient gets an English email:
- Subject:
You've been invited to <siteName>
- Body:
You've been invited to join <siteName>. Click this link to create your account: <url>
- Open the invite link →
/admin/invite/accept?token=.... The page renders the following English strings:
You've been invited!
You'll be joining as <ROLE>
Email (label)
Your name (optional) (label)
Create your passkey (heading)
Passkeys are a secure, passwordless way to sign in using your device's biometrics, PIN, or security key.
Create Account (button)
Why
Two distinct hard-coded surfaces:
1. @emdash-cms/admin — InviteAcceptPage.tsx
Looking at the bundled dist/index.js (v0.9.0), the InviteAcceptPage RegisterStep component places the strings directly inside JSX children rather than wrapping them with the <Trans> macro / lingui catalog. The strings have no message id in locales/ja/messages.mjs (verified by greping for joining, invited, Your name, etc. — no matches for these specific phrases, while sibling passkey strings are translated).
2. @emdash-cms/auth — buildInviteEmail() in src/invite.ts
The function returns a hard-coded English subject + text + HTML body. It receives siteName only — no locale parameter — and therefore no way to render localized copy without a fork.
Additionally, the email pipeline's EmailPipeline.sendInner() skips email:beforeSend for source === "system" to protect auth tokens, so plugins cannot rewrite invite/magic-link bodies via hooks. This makes buildInviteEmail the only place where localization can happen.
Expected
InviteAcceptPage strings flow through the same <Trans> / lingui catalog that the rest of the admin uses, with corresponding entries in locales/<lang>/messages.mjs.
buildInviteEmail() (and any other system-email builders — magic-link, password recovery) accepts a locale argument or reads the active site locale and selects a template per language.
Workaround
None inside an EmDash project: plugin hooks can't rewrite system emails, and the admin SPA strings are baked into the published bundle. Sites either tolerate the mixed-language UX or fall back to the "copy invite link and share manually" flow.
Environment
emdash@0.9.0
@emdash-cms/admin@0.9.0
@emdash-cms/auth@0.9.0
@emdash-cms/cloudflare@0.9.0
- Astro 6 / Cloudflare Workers runtime
Summary
With
emdash:locale = "ja"set on a site that has otherwise switched to Japanese, the invite acceptance page and invite email template remain in English. Both surfaces bypass the lingui i18n machinery used elsewhere in the admin and auth packages.Repro
emdash:locale = "ja"in theoptionstable./_emdash/admin/...(settings, content list, etc.) renders in Japanese — locale is being picked up correctly.Send invite. The recipient gets an English email:You've been invited to <siteName>You've been invited to join <siteName>. Click this link to create your account: <url>/admin/invite/accept?token=.... The page renders the following English strings:You've been invited!You'll be joining as <ROLE>Email(label)Your name (optional)(label)Create your passkey(heading)Passkeys are a secure, passwordless way to sign in using your device's biometrics, PIN, or security key.Create Account(button)Why
Two distinct hard-coded surfaces:
1.
@emdash-cms/admin—InviteAcceptPage.tsxLooking at the bundled
dist/index.js(v0.9.0), theInviteAcceptPageRegisterStepcomponent places the strings directly inside JSXchildrenrather than wrapping them with the<Trans>macro / lingui catalog. The strings have no message id inlocales/ja/messages.mjs(verified by greping forjoining,invited,Your name, etc. — no matches for these specific phrases, while sibling passkey strings are translated).2.
@emdash-cms/auth—buildInviteEmail()insrc/invite.tsThe function returns a hard-coded English subject + text + HTML body. It receives
siteNameonly — no locale parameter — and therefore no way to render localized copy without a fork.Additionally, the email pipeline's
EmailPipeline.sendInner()skipsemail:beforeSendforsource === "system"to protect auth tokens, so plugins cannot rewrite invite/magic-link bodies via hooks. This makesbuildInviteEmailthe only place where localization can happen.Expected
InviteAcceptPagestrings flow through the same<Trans>/ lingui catalog that the rest of the admin uses, with corresponding entries inlocales/<lang>/messages.mjs.buildInviteEmail()(and any other system-email builders — magic-link, password recovery) accepts alocaleargument or reads the active site locale and selects a template per language.Workaround
None inside an EmDash project: plugin hooks can't rewrite system emails, and the admin SPA strings are baked into the published bundle. Sites either tolerate the mixed-language UX or fall back to the "copy invite link and share manually" flow.
Environment
emdash@0.9.0@emdash-cms/admin@0.9.0@emdash-cms/auth@0.9.0@emdash-cms/cloudflare@0.9.0