Symptom
With an i18n bundle present as rows, calling sendTemplate with no locale rendered the zh-CN row — on two consecutive fresh boots — instead of the documented en-US default. Explicit locales resolve correctly (zh-CN exact; fr-FR and en-GB fall back to en-US); a language-only zh does not prefix-match.
Root cause
Two seams in packages/plugins/plugin-email/src:
email-plugin.ts (~line 548) — templateLoader.load(name, locale) builds const where = { name } and only adds where.locale when locale is truthy, then queries with limit: 1 and no ordering. With locale undefined it returns whichever row the driver yields first — arbitrary and boot-dependent.
email-service.ts (~line 1121) — const preferred = input.locale && String(input.locale).trim(); let row = await loader.load(input.template, preferred || undefined); if (!row && preferred && preferred !== 'en-US') { row = await loader.load(input.template, 'en-US'); }. The en-US fallback runs only when preferred was set, so a no-locale send never falls back to en-US — it takes the arbitrary first row from load.
Stale-premise check: identical in src, dist, and on origin/main (zero diff vs the 92f26f75 pin) — not fixed upstream.
Reproduction
- Author an
email_template i18n bundle with en-US and zh-CN rows for one name.
- Call
sendTemplate for that name with locale omitted, on a fresh boot.
Expected: the en-US default renders. Actual: an arbitrary locale (zh-CN observed on two boots) renders; no en-US fallback is applied.
Source
Extracted from the QA run #7690 (framework 92f26f7, console 09987b680).
Symptom
With an i18n bundle present as rows, calling
sendTemplatewith nolocalerendered the zh-CN row — on two consecutive fresh boots — instead of the documented en-US default. Explicit locales resolve correctly (zh-CNexact;fr-FRanden-GBfall back to en-US); a language-onlyzhdoes not prefix-match.Root cause
Two seams in
packages/plugins/plugin-email/src:email-plugin.ts(~line 548) —templateLoader.load(name, locale)buildsconst where = { name }and only addswhere.localewhenlocaleis truthy, then queries withlimit: 1and no ordering. With locale undefined it returns whichever row the driver yields first — arbitrary and boot-dependent.email-service.ts(~line 1121) —const preferred = input.locale && String(input.locale).trim(); let row = await loader.load(input.template, preferred || undefined); if (!row && preferred && preferred !== 'en-US') { row = await loader.load(input.template, 'en-US'); }. The en-US fallback runs only whenpreferredwas set, so a no-locale send never falls back to en-US — it takes the arbitrary first row fromload.Stale-premise check: identical in
src,dist, and onorigin/main(zero diff vs the92f26f75pin) — not fixed upstream.Reproduction
email_templatei18n bundle withen-USandzh-CNrows for one name.sendTemplatefor that name withlocaleomitted, on a fresh boot.Expected: the en-US default renders. Actual: an arbitrary locale (zh-CN observed on two boots) renders; no en-US fallback is applied.
Source
Extracted from the QA run #7690 (framework 92f26f7, console 09987b680).