Skip to content

fix: align numeric placeholder generation in <Plural> with babel#241

Open
mogelbrod wants to merge 2 commits into
lingui:mainfrom
mogelbrod:consistent-choice-numeric-indices
Open

fix: align numeric placeholder generation in <Plural> with babel#241
mogelbrod wants to merge 2 commits into
lingui:mainfrom
mogelbrod:consistent-choice-numeric-indices

Conversation

@mogelbrod

Copy link
Copy Markdown
Contributor

For <Plural> / <Select> / <SelectOrdinal>, the SWC plugin always allocated the value expression's index first, before processing the option attributes (one, other, …). While this is probably more intuitive, the JS implementation instead iterates attributes in source order and allocates the value's index at the position where the value attribute actually appears.

This only diverges when a non-identifier value is not the first attribute and an earlier option contains a numeric-indexed expression — but when it does, the numbers differ:

<Plural one={`${a.b} glass`} value={items.length} other="many" />
message
Before {0, plural, one {{1} glass} other {many}}
After / in JS {1, plural, one {{0} glass} other {many}}

Would it be worthwhile to update the JS implementation to match the SWC version instead?

With the conventional value-first ordering both implementations already agreed (value{0}), so existing snapshots were unaffected.

Fix

  • The token now records value_pos: the position of the value attribute among the cases in source order (0 for the plural(value, { … }) call form, where the value is always first).
  • push_icu allocates the value's index at value_pos while iterating the cases, so indices are consumed in source order. The value placeholder is still emitted first in the ICU string by rendering each case body into a buffer (via String::split_off) and assembling {value, format, …cases} at the end.
    Index allocation (numeric_index / values_indexed) persists across the split, so only the output position is decoupled from the allocation order.

@mogelbrod

mogelbrod commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

@timofei-iatsenko fix for second bug in #239 🙏

I agree that the babel behaviour which this PR mimics isn't ideal. Changing the babel version would be considered a breaking change since it would invalidate translations - which is why I opted to simply mirror it here. I'm open to both approaches though.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.82609% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 94.99%. Comparing base (27e38f2) to head (fcde304).

Files with missing lines Patch % Lines
crates/lingui_macro/src/builder.rs 96.55% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #241      +/-   ##
==========================================
+ Coverage   94.96%   94.99%   +0.02%     
==========================================
  Files          10       10              
  Lines        2603     2637      +34     
==========================================
+ Hits         2472     2505      +33     
- Misses        131      132       +1     
Flag Coverage Δ
unittests 94.99% <97.82%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
crates/lingui_macro/src/jsx_visitor.rs 89.09% <100.00%> (+0.65%) ⬆️
crates/lingui_macro/src/macro_utils.rs 89.26% <100.00%> (+0.05%) ⬆️
crates/lingui_macro/src/builder.rs 98.73% <96.55%> (-0.25%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timofei-iatsenko

Copy link
Copy Markdown
Collaborator

FYI, i'm working on my attempt on fixing this. I discovered that there is also another issue related to ph() in the <Plural> component. Working on both issues.

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.

2 participants