Skip to content

fix(translator): tier-C config guards (localization enqueue, field exclude, duplicate level) - #85

Merged
SearheiParkhamchuk merged 3 commits into
mainfrom
fix/translator-tier-c-config-guards
Jul 31, 2026
Merged

fix(translator): tier-C config guards (localization enqueue, field exclude, duplicate level)#85
SearheiParkhamchuk merged 3 commits into
mainfrom
fix/translator-tier-c-config-guards

Conversation

@SearheiParkhamchuk

Copy link
Copy Markdown
Contributor

Three independent correctness fixes for the translator plugin, all from the
config-combination-rules plan (docs/plans/2026-07-29-config-combination-rules.md,
tier "real defects" + duplicated-control). Each is a separate commit → three
distinct changelog entries under one patch release.

Fixes

1. Reject manual enqueue when localization is disabled (D2)

A manual POST /translate/enqueue with localization disabled or absent kept
every requested target locale and passed it to payload.update({ locale })
orphaning rows (Mongo/SQLite), erroring on a Postgres locale enum, or, with no
localization at all, overwriting the single unlocalized field and wiping the
source
. The handler now returns 400 before enqueuing anything, and
resolveTargetLocales no longer accepts a null locale set, so a
localization-less config is unrepresentable.

2. Honor field-level exclude on the single-field translation route (D1)

The /field route resolved a path by field type only, so a field opted out
via withFieldTranslation({ exclude }) could still be translated by naming its
path directly — bypassing the opt-out the whole-document path honors via
isTranslatableLeaf. resolveFieldSubtree now returns a distinct excluded
status for such a leaf (uniformly, including inside blocks) and the handler
no-ops it with a clear notice.

3. De-duplicate translation controls when a level is declared twice (X1)

A level listed twice (e.g. levels: [documentLevel(), documentLevel()])
attached its admin control to each managed collection twice, rendering a
duplicated button. Endpoints already dedup by (method, path);
attachCollectionComponents now mirrors that, deduping by (slot + component path) so a duplicate level renders one control silently.

Verification

  • Unit: 1175 tests pass (+8 new across the three fixes).
  • Integration: 9 files / 32 tests pass against the built dist.
  • Type-check (turbo) and lint clean; full tsc declaration build succeeds.

Notes / out of scope

  • The /field route also does not check localized (a non-localized field
    could be translated by naming its path). Same class as feature/payload plugin comments #2 but a separate
    concern — left as a follow-up, not folded in.
  • Unifying the three copies of the locale invariants (source-exclusion /
    unknown-drop / de-dup) into one shared unit shared by the auto-translate and
    manual paths is the planned next slice; kept out here to keep the diff tight.

A manual /enqueue with localization disabled or absent kept every requested
target locale and passed it to payload.update({ locale }) — orphaning rows
(Mongo/SQLite), erroring on a Postgres locale enum, or, with no localization
at all, overwriting the single unlocalized field and wiping the source.
Guard the handler to 400 before enqueuing, and drop the null branch from
resolveTargetLocales so a localization-less config is unrepresentable.
…ation route

The /field route resolved a path by field type only, so a field opted out via
withFieldTranslation({ exclude }) could still be translated by naming its path
directly — bypassing the opt-out the whole-document path honors via
isTranslatableLeaf. resolveFieldSubtree now returns a distinct `excluded`
status for such a leaf (uniformly, including inside blocks), and the handler
no-ops it with a clear notice instead of translating.
…clared twice

A level listed twice (e.g. levels: [documentLevel(), documentLevel()]) attached
its admin control to each managed collection twice, rendering a duplicated
button. Endpoints already dedup by (method, path); attachCollectionComponents
now mirrors that, deduping by (slot + component path) so a duplicate level
renders one control silently.
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
turbo-cms-kit-payload Ready Ready Preview, Comment Jul 29, 2026 3:25pm

Request Review

@SearheiParkhamchuk SearheiParkhamchuk self-assigned this Jul 31, 2026
@SearheiParkhamchuk
SearheiParkhamchuk merged commit 10a9da1 into main Jul 31, 2026
2 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.10.2 🎉

The release is available on npm package (@latest dist-tag)

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant