Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-email): sendTemplate binds renderOpts.locale to the resolved template row (#7801) - #8064
Merged
huangyiirene merged 1 commit intoAug 12, 2026
Conversation
…ed template row (#7801) A `sendTemplate` call that named no `locale` resolved a concrete template row (#7731) but left `renderOpts.locale` unset, so the locale-sensitive format filters fell through to `formatValue`'s own `?? 'en-US'` default instead of following the row they were rendering into. Per the maintainer's ruling on #7801 the template row is the SINGLE locale authority; mixed-locale output — a row's body text in one locale, its dates and numbers in another — is a defect, not a feature. The seam is `email-service.ts`'s `sendTemplate` renderOpts construction: it now binds `preferred || row.locale` rather than the raw `input.locale`. Note on the card's framing: it reported the filters rendering "under the RUNTIME locale". They never did — `formatValue` hard-defaults to en-US — which is why the split stayed invisible whenever the resolved row happened to BE en-US. The observable defect is the mirror image: a bundle with no en-US row resolves e.g. zh-CN and renders en-US dates inside zh-CN body text. The ruling is unaffected; only the direction of the symptom is. Binding to `preferred` (the trimmed spelling the locale ladder actually resolved on) also fixes a second, previously unreported defect: an `input.locale` carrying whitespace resolved its row and then threw `RangeError: Incorrect locale information provided` out of `Intl`, taking the whole send down. Pins in `template-locale-resolution.test.ts` cover both halves of the ruling — the resolved row drives the filters when the caller named none, and an explicit `input.locale` still wins, including when it falls back to the en-US row. Fixes#7801 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEZfvePJ4bpEBmvBEBEKpa
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
huangyiirene
marked this pull request as ready for review
August 12, 2026 15:36
This was referenced Aug 12, 2026
Uh oh!
There was an error while loading. Please reload this page.
huangyiirene
deleted the
claude/issue-7801-sendtemplate-resolved-locale
branch
August 12, 2026 16:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#7801
Implements the maintainer's ruling recorded in comment 5265942667 (Option A): a no-locale
sendTemplatebindsrenderOpts.localeto the resolved template row's locale. The row is the single locale authority; mixed-locale rendering is a defect, not a feature.The seam
packages/plugins/plugin-email/src/email-service.ts—sendTemplate, therenderOptsconstruction. The card's anchor (:1185) was accurate onmain; it did not mislead.preferredis the already-computed trimmed spelling the locale ladder resolved on, a few lines above.The issue says the filters render "under the runtime locale". They never did.
formatValue(packages/formula/src/template-engine.ts:155) hard-defaults toen-US:So the en-US/runtime mismatch the card describes is unreachable, and that is exactly why the split stayed invisible: whenever the resolved row was en-US, the row's locale and the filter default coincided. The defect is the mirror image — a bundle with no en-US row resolves e.g. zh-CN (the ladder's last rung) and renders en-US dates and numbers inside zh-CN body text.
The §5 STOP premise itself holds:
renderOpts.localeis the value the filters read (renderTemplate→formatValue→Intl.*), and the resolved row is in scope at the seam. The ruling is implemented as written; only the direction of the observable symptom differs from the card.Reverse verification
Pins live in the existing
template-locale-resolution.test.ts(no new test file, no new workspace dependency).main[zh-CN] 3/5/26, 2:30 PM[zh-CN] 2026/3/5 14:30input.localewins (row exists)input.localewins on the en-US fallback row' de-DE 'renders instead of throwingRangeErrorPin (b) passing on
mainis the expected reading — it guards existing-correct behaviour against the fix over-reaching into "the row always wins". No second defect there.An
input.localecarrying whitespace (' de-DE ') resolved thede-DErow via the ladder's trimming, then passed the untrimmed tag toIntl, which throwsRangeError: Incorrect locale information provided— taking the entire send down. Binding topreferredrather thaninput.localecloses it. Called out explicitly so it can be split out if the reviewer would rather it landed on its own.Gates
packages/plugins/plugin-email: 339/339 tests pass,tsc --noEmitclean, eslint clean.pnpm check:test-source-alias— OK, 72 packages scanned. (No new test file and no new cross-package import; the only added dependency is theIntlglobal.)pnpm check:type-check-debt— OK (self-test +--re-measurewith the full package closure built): 35 ledger entries re-measured, none above its recorded number. No ledger entry raised.check:engine-double-contract), ADR-0112 refusals,packages/spec/src/**(so nogen:schema/gen:docs),content/docs/releases/**.Changeset
.changeset/sendtemplate-resolved-row-locale.md—@objectstack/plugin-emailpatch.Generated by Claude Code