Skip to content

fix(content): write a media or relation value to every locale at once - #227

Merged
ABB65 merged 2 commits into
mainfrom
fix/locale-agnostic-fields-fanout
Sep 2, 2026
Merged

fix(content): write a media or relation value to every locale at once#227
ABB65 merged 2 commits into
mainfrom
fix/locale-agnostic-fields-fanout

Conversation

@ABB65

@ABB65 ABB65 commented Sep 2, 2026

Copy link
Copy Markdown
Member

Summary

Closes #207.

On an i18n: true model, an image (or relation) save wrote only the editor's active locale; the other locales kept the old value and nothing said so. A hero image swapped in en left the tr site unchanged.

This is the issue's option (3) as an inferred default: the schema has no localized flag yet, so the field type decides. image / video / file / relation / relations are locale-agnostic (shared/utils/locale-agnostic-fields.ts), and their values are written to every locale of the model in the same commit.

  • Engine (content-engine/locale-fanout.ts, wired into saveContent and saveDocument). Extra entries for the other locales go into the same planContentSave call, so one branch, one commit, one merge. Only entries that already exist in the other locale are written (a one-image partial entry would fail that locale's required fields, and the gap is a coverage problem this save was not asked to fix); a locale that already holds the value is skipped, so the byte-identical no-op short-circuit still fires. Studio's meta override (status kept, updated_by/updated_at stamped) runs for each locale written. Documents keep each locale's own body. The commit message notes Shared across locales (tr): cover.
  • Result. WriteResult.sharedAcrossLocales = { fields, locales }, passed through to the agent's tool result (so it reports it rather than offering to repeat the save for tr) and to the content route.
  • Editor. The edit form marks these fields "Applies to every locale — this value carries no language" on i18n models with more than one locale; the save toast adds "Also applied to tr: guides_band_background".
  • Media usage is recorded for each locale written.

When @contentrain/types grows a per-field localized flag, it should replace the type list rather than sit beside it (noted in CLAUDE.md). Until then there is no per-project opt-out; per-locale images were not a case anyone had, and the silent divergence was.

Test plan

  • tests/unit/content-engine.test.ts — the reported case (image swapped in en lands in tr, Turkish prose intact, tr meta status kept + author stamped); prose-only save leaves tr alone; already-equal value leaves tr alone; relation on a collection carried only into entries that exist in tr; non-i18n model unchanged; document cover carried with the Turkish body kept
  • tests/unit/locale-agnostic-fields.test.ts, use-content-editor.nuxt.test.ts (toast)
  • lint, nuxt typecheck; unit + integration green; the nuxt project passes file-by-file (three unrelated files time out locally when the whole project runs right after nuxt typecheck — CI is the arbiter)
  • Staging: on Lanista site-settings with en selected, swap guides_band_background, save; confirm the toast names tr, the branch touches both locale files, and the tr site shows the new asset

🤖 Generated with Claude Code

https://claude.ai/code/session_01Chid3TnLdPHjsKip4n63Ky

Contentrain added 2 commits September 2, 2026 10:24
On an i18n model, saving an image field wrote only the locale selected
in the editor. The other locales kept the previous asset and nothing
said so. A non-technical editor swapped a hero image with `en`
selected, the site rendered `tr`, and nothing changed; someone with
repo access had to diff the locale files to find out why. A delivery
URL and an entry ref carry no language, but the editor scoped them per
locale like prose.

The schema has no `localized` flag yet, so the field type decides:
image, video, file, relation and relations are locale-agnostic
(shared/utils/locale-agnostic-fields.ts). The content engine carries
their values into the model's other locales in the same commit
(content-engine/locale-fanout.ts) — only into entries that already
exist there, and only where the value differs, so a no-op save stays a
no-op. Studio's meta semantics apply to each locale written. Documents
get the same treatment, each locale keeping its own body.

The save result names the fields and locales; the editor toast repeats
it, the edit form marks these fields as applying to every locale, the
agent's tool result carries it so it never offers to "do the same for
tr", and media usage is recorded per locale written.

Closes #207
@ABB65
ABB65 merged commit c28c6b5 into main Sep 2, 2026
2 checks passed
@ABB65
ABB65 deleted the fix/locale-agnostic-fields-fanout branch September 2, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Media field on an i18n model saves to the active locale only, so a locale-agnostic asset silently diverges

1 participant