Skip to content

Conversation

@garikkh
Copy link
Contributor

@garikkh garikkh commented Oct 14, 2025

Description

Fixes #2346

When using po-gettext formatter, plural calls with identical strings but different variables:

<div>
  {plural(count, {
    one: "one book",
    other: "many books",
  })}
</div>
<div>
  {plural(anotherCount, {
    one: "one book",
    other: "many books",
  })}
</div>

generated duplicate msgid entries in PO files, which violates PO format rules.

#. js-lingui:icu=%7BanotherCount%2C+plural%2C+one+%7Bone+book%7D+other+%7Bmany+books%7D%7D&pluralize_on=anotherCount
#: src/App.tsx:68
msgid "one book"
msgid_plural "many books"
msgstr[0] "one book"
msgstr[1] "many books"

#. js-lingui:icu=%7Bcount%2C+plural%2C+one+%7Bone+book%7D+other+%7Bmany+books%7D%7D&pluralize_on=count
#: src/App.tsx:61
msgid "one book"
msgid_plural "many books"
msgstr[0] "one book"
msgstr[1] "many books"

Added pre-processing step that merges duplicate plural catalog entries before serialization.

  1. Groups catalog entries by their plural case content (ignoring variable names)
  2. Merges entries with identical plural strings into a single catalog entry
  3. Combines all source location references from merged entries
  4. Prevents duplicate msgid/msgid_plural entries in generated PO files

With this change the PO now looks like:

#. js-lingui:icu=%7BanotherCount%2C+plural%2C+one+%7Bone+book%7D+other+%7Bmany+books%7D%7D&pluralize_on=anotherCount
#: src/App.tsx:61
#: src/App.tsx:67
msgid "one book"
msgid_plural "many books"
msgstr[0] "one book"
msgstr[1] "many books"

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Examples update

Fixes #2346

Checklist

  • I have read the CONTRIBUTING and CODE_OF_CONDUCT docs
  • I have added tests that prove my fix is effective or that my feature works
  • I have added the necessary documentation (if appropriate) No relevant docs

@vercel
Copy link

vercel bot commented Oct 14, 2025

@garikkh is attempting to deploy a commit to the Crowdin Team on Vercel.

A member of the Team first needs to authorize it.

@garikkh garikkh changed the title bugfix: Gettext formatter merges duplicate plural entries fix: Gettext formatter merges duplicate plural entries Oct 14, 2025
@garikkh garikkh marked this pull request as draft October 14, 2025 23:58
@codecov
Copy link

codecov bot commented Oct 14, 2025

Codecov Report

❌ Patch coverage is 91.76471% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.72%. Comparing base (6bb8983) to head (d46d3a1).
⚠️ Report is 228 commits behind head on main.

Files with missing lines Patch % Lines
packages/format-po-gettext/src/po-gettext.ts 91.76% 4 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2347      +/-   ##
==========================================
- Coverage   77.05%   76.72%   -0.33%     
==========================================
  Files          84       99      +15     
  Lines        2157     2733     +576     
  Branches      555      707     +152     
==========================================
+ Hits         1662     2097     +435     
- Misses        382      509     +127     
- Partials      113      127      +14     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@garikkh
Copy link
Contributor Author

garikkh commented Oct 15, 2025

Ah, didn't work properly, need to continue working on it

@garikkh garikkh marked this pull request as ready for review October 15, 2025 23:22
@timofei-iatsenko
Copy link
Collaborator

timofei-iatsenko commented Oct 16, 2025

I think implementation is suboptimal, instead of introducing another type of comment, simply print the same comments many times

#. js-lingui:icu=%7BanotherCount%2C+plural%2C+one+%7Bone+book%7D+other+%7Bmany+books%7D%7D&pluralize_on=anotherCount
#. js-lingui:icu=%7Bcount%2C+plural%2C+one+%7Bone+book%7D+other+%7Bmany+books%7D%7D&pluralize_on=count
#: src/App.tsx:61
msgid "one book"
msgid_plural "many books"
msgstr[0] "one book"
msgstr[1] "many books"

When deserializing just take to consideration that there could be multiple comments, flat map 1 message + 1 comment and use existing methods to process that.

@garikkh
Copy link
Contributor Author

garikkh commented Oct 16, 2025

I considered that approach, but it seemed messier to me when you have many duplicates. In our codebase, we've only been using lingui a few months, but already have cases with ~7 duplicates. So now you'd have a PO entry with 7 ICU comments instead of 1 really long comment.

@garikkh
Copy link
Contributor Author

garikkh commented Oct 16, 2025

instead of introducing another type of comment

Also wanted to note, this isn't introducing another comment - it's just using the icu comment. the ICU comment is a URLSearchParams, so all I did is add another key here.

  const contextComment = item.extractedComments
    .find((comment) => comment.startsWith(ctxPrefix))
    ?.substring(ctxPrefix.length)
  const ctx = new URLSearchParams(contextComment)

This solution is a little more complex, but IMO is more elegant/consistent

@garikkh
Copy link
Contributor Author

garikkh commented Nov 10, 2025

bump @timofei-iatsenko

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.

Duplicate PO entries when using gettext and plurals

2 participants