Skip to content

Fix layers going blank when linked to a plural message, link review gaps, drop unused manifest domain - #78

Merged
samuelstroschein merged 2 commits into
devfrom
fix/plural-link-and-manifest
Oct 13, 2026
Merged

samuelstroschein merged 2 commits into
devfrom
fix/plural-link-and-manifest

Conversation

@samuelstroschein

@samuelstroschein samuelstroschein commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

What this fixes

1. A layer linked to a plural message went blank

Linking a text layer to a plural message (e.g. checkout.items, forms one / other, variable count) left the layer empty, showed "Revert" / "Update message" and made editing the layer text in the Layers tab throw.

Root cause: every layer lookup asked the message for the form with a match of [], which only finds an all catch-all form. Files imported with the Inlang message format or i18next store other as a literal match (countPlural=other), so there was no such form, the lookup returned undefined and toSandboxUpdate wrote ?? "" to the canvas. The count value of the layer could not be edited anywhere (the parameter editor of the Layers row has been a TODO since the selector rewrite), and Update message / the language switch looked for / wrote forms with the same [] match.

What a designer sees now:

  • The layer shows the form that its own stored values choose (plugin data pv, like every other variable): a plural count picks the plural category of the frame language (1 -> one, 5 -> other, Russian 2 -> few), exact numbers (ICU =0) win, a select (gender) picks its value, and without a value the layer shows the catch-all (other) form. A message without any text for the layer leaves the layer's text alone instead of blanking it.
  • Linking keeps what the layer shows: a layer with "7 items" linked to {count} items becomes count = 7 and keeps "7 items"; "1 item" keeps its form. A layer whose text is no form gets an example count ("2 items") instead of "count items".
  • The count is editable in the Layers row: a small count [ 2 ] field under the layer's text (a select shows e.g. gender [ female ], empty = "other" form). Editing it is one undo step, writes only the layer (not the message) and the layer follows in every language it is switched to.
  • "Update message" writes the layer text into the form its count chooses (not into a variant without selectors).
  • The editor chip bug seen on the way: a placeholder at the very start of a text with a single style ({count} items) was listed by the sandbox as an extra overlapping range, so the editor showed "2 items" plus a stray count chip and the layer looked modified. toQuillTextOperations now cuts the placeholder out of the style range (pure UI-side change, the sandbox bundle is unchanged).

New module src/lib/message/LayerVariant.ts (form choice, example/inferred values), used by htmlForLayer, getState, the language switch, Update message and toSandboxUpdate.

2. Link review depended on other languages being complete

After importing a French file that lacks checkout.free_delivery, the review "Link layers to the imported messages?" no longer offered the layer with the English reference text of that message (reproduced live). Two causes:

  • the post-import review limited every layer to the keys of the imported file, including layers in reference-language frames, whose match cannot depend on a translation file. Now only layers of other languages are limited; reference-language layers are matched against every message after a translation import.
  • the text index of a language skipped messages that have no text in it, so a layer in a French frame that still shows the English fallback text of a message that is not translated yet was never matched (also made "Generate keys" propose a duplicate message). Such messages are now indexed by their reference text for that language (a translated message still only matches its own translation).

3. Manifest

https://s3-alpha.figma.com (Figma profile pictures) is removed from allowedDomains and the reasoning text in manifest.json and manifest.figma.ts. Its only consumer is <img src={user.photoUrl}> in Usermanagement.tsx, which is only rendered for appScreen === "users"; the tab is commented out since the commit that added it (2023), so no code path can set it (not even a stored lastView). A test pins it.

Verification

  • Unit tests (fail on origin/dev, pass here): LayerVariant.test.ts (imports through the real plugins: Inlang message format incl. the count=one/other form, i18next, ICU, next-intl), LocalizedLabelManagerUI.test.ts, UILocalizedLabel.test.ts, LinkSuggestions.test.ts, RichTextFormatting.test.ts, manifest.test.ts.
  • pnpm tsc && pnpm lint && pnpm test && pnpm build and the sandbox build pass (the sandbox bundle is byte-identical in size to origin/dev).
  • Live in Figma Desktop with a mini checkout design (two frames, plural + select + plain messages, English and an incomplete French file): blank layer reproduced before the change; after it the layer shows "2 items" / keeps "7 items" and "1 item", the count field switches the form, undo/redo restore text and pv together, French shows "5 articles", select values switch forms, "Update message" writes only the other form, the French import review now offers the free-delivery layer, a layer in a French frame is found, the Layers row aligns with the text.

Not changed / notes

  • Layers left blank by the old bug (message linked, text empty) are not repaired automatically; "Revert" in the row now restores their text.

  • Editing the count chip inside the layer text only changes the value shown, not the form; use the count field.

  • The count field is read-only while the layer text is modified (a new value would replace the edited text): use "Update message" or "Revert" first.

  • After a translation import the review also offers unlinked reference-language layers that match any existing message (not only keys of the file). Layers the designer declined at an earlier import can show up again; this is deliberate (what is offered no longer depends on how complete the file is).

Review

A read-only review sub-agent went through the diff; confirmed findings were fixed in a7ab810 (inferred "One item" count, stable example counts across languages, type=$pluralType ordinals, strict form lookup with reference fallback, formatting of reference-text links, in-place mutation of the cached label values, un-awaited "Update message", markup captured as a value). Tests were added for each.

🤖 Generated with Claude Code

samuelstroschein and others added 2 commits October 13, 2026 11:46
…aps, drop unused manifest domain

- A layer linked to a message with forms (plural, select) looked its text up with a match of [],
  which only finds an all-catch-all form. Files that import "other" as a literal match (Inlang
  message format, i18next) have none, so the layer went blank, showed "Revert / Update message"
  and "Update message" would have written into no form; editing its text in the Layers tab threw.
  A layer now shows the form its own stored variable values choose (plugin data pv): a count
  picks the plural category of the language, a select picks its value, the catch-all form is the
  default and a layer never ends up without text. A plural starts with an example count (or the
  number its text shows when it is linked) and the count can be edited under the layer's text.
- The link review after importing a translation depended on which keys the file had: layers in
  reference-language frames are now matched against every message, and a message that is not
  translated to a frame's language is found by its reference text (also for "Generate keys").
- A placeholder at the very start of a layer text was cut out of the styled text range by nobody:
  the editor showed the whole text plus the placeholder after it and the layer looked modified.
- Remove https://s3-alpha.figma.com from the network access: only the hidden Users view used it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… plural types, formatting of reference-text links

- A form without the number in its text ("One item") kept its inferred count only on paper: the
  default filler replaced it with the example count. The guessed count is now a real value.
- The example count no longer changes when a layer is switched to another language (a number stays,
  the plural rules of the language choose the form); examples are whole numbers and skip exact
  numbers (=2).
- i18next plurals with `type=$pluralType` (ordinal and cardinal forms) read the type from the layer.
- No form that fits a language gives no variant (not the first one): the layer falls back to the
  reference text of the same count, and to any text of the message as the last resort.
- Layers linked through the reference-text fallback keep their formatting (planLinks) and never
  rewrite the message; markup around a number is no value; mixed exact-number / category selectors
  are plurals.
- toSandboxUpdate no longer changes the cached label's values in place; "Update message" is awaited so
  a message that needs the Messages tab reports its error; the count field is read-only while the layer
  text is modified (a new value would replace the text).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@samuelstroschein
samuelstroschein merged commit f5009c6 into dev Oct 13, 2026
1 check passed
@samuelstroschein
samuelstroschein deleted the fix/plural-link-and-manifest branch October 13, 2026 16:11
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.

1 participant