Fix duplicate react-intl message ids breaking yarn build-locales - #7318
Open
sumitdahal7 wants to merge 4 commits into
Open
Fix duplicate react-intl message ids breaking yarn build-locales#7318sumitdahal7 wants to merge 4 commits into
sumitdahal7 wants to merge 4 commits into
Conversation
for more information, see https://pre-commit.ci
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What type of PR is this? (check all applicable)
Related Issue
Fixes #7284
Describe this PR
yarn build-localeshas been failing ondevelopsince 23 June 2025:combine-messagesrefuses to run when twomessages.jsfiles declare the same id, even when thedefaultMessageis identical. Because that command is the only thing that generatesfrontend/src/locales/en.json, the catalog has been frozen for over a year. Nothing caught it and CI never ranbuild-locales, and react-intl silently falls back to thedefaultMessagein code when a key is missing from the catalog, so nothing looked broken in English.The visible cost: 142 strings added since June 2025 never reached Transifex, so no translator has ever seen them. They render as English in all 27 non-English locales, permanently and silently.
The reported id is only the first one the tool hits. A full audit found 13 duplicated ids, in two categories:
Nine identical duplicates.
badges/messages.jsandlevels/messages.jsre-declared ids thatteamsAndOrgs/messages.jshas owned since 2019 —management.button.cancel,.save,management.fields.name,.description,.managers.add,.organisation.image,management.link.manage,management.badges,management.levels. They now import and re-export the canonical descriptors. Same ids, same rendered text, no component changes, existing translations in all 28 locale files untouched.Four conflicting duplicates, where one id mapped to two different English strings and whichever won depended on extraction order:
management.projects.create.review.database+.osm+.sandbox— projectCreate says "Where should edits be saved?" / "OpenStreetMap (Live)" / "Training Sandbox (Practice)"; projectEdit says "Database" / "OSM" / "Sandbox". projectEdit's now usemanagement.projects.edit.database*.project.detail.sandbox— declared three times.header/messages.js's copy is unused (the badge moved to the project detail header in Reposition sandbox mode badge from main header #7278) and is deleted. projectDetail keeps the id; taskSelection's InfoBox becomesproject.detail.sandbox.info, pairing with its existingproject.detail.sandbox.tooltipsibling.None of the renamed ids had ever reached Transifex, so no translations are lost.
Regenerated
en.jsonwith 148 additions covering a year of accumulated strings, 4 removals for messages actually deleted from source. The catalog now round-trips exactly: 1554 ids declared in code, 1554 keys in the file, zero drift in either direction.CI guard in
pr_test_frontend.yml. It regenerates the catalog and diffs it, so it fails both on a duplicate id (build-localesexits non-zero) and on a stale committed catalog, the second case being the one that actually caused this, since it's easy to add a string and forget to regenerate.docs/developers/translations.mdis updated to match: the old wording said runningbuild-localeswas "the ideal", which is precisely why it got skipped.Screenshots
N/A
Alternative Approaches Considered
Renaming the shared ids instead of re-exporting them. This would have created nine new Transifex keys and thrown away translations that already exist in all 28 locale files. Re-exporting keeps the ids stable, which is what preserves the translations.
A pre-commit hook that regenerates automatically. Better developer experience, but it needs
frontend/node_modules, which pre-commit.ci's container doesn't have, so it would need aci: skipblock and would still fail for anyone who hasn't installed frontend deps. The CI check alone fully closes the correctness gap. Worth revisiting as its own PR if the CI check proves annoying in practice.Review Guide
Locally: 279 tests passed across 57 suites;
eslint --max-warnings 0clean on the changed files;CI=true yarn buildclean.Two things to know about the CI step:
yarn test, so a stale catalog fails fast. Happy to move it after if you'd rather always get test results.combine-messageswrites none; pre-commit'send-of-file-fixeradds one to the committed file. Without that line the check would fail on every single run.After merge, someone with Transifex access needs to run
./scripts/transifex/tx-docker.sh push -sfrom the repo root. Regeneratingen.jsononly gets the strings into the source catalog and it doesn't notify translators. Without that step this PR only solves half of #7284. This is the stepdocs/developers/translations.mddescribes.AI Disclosure
Claude assisted with the duplicate-id audit across all
messages.jsfiles, tracing the git history behind the conflicting ids, and drafting this description. I made the calls on how to resolve each conflict, verified every claim against the repo, and ran the full test and build suite locally. Theen.jsondiff is entirely generator output with no hand edits.