ci: gate against duplicate keys in l10n catalogs - #563
Merged
Conversation
Both JSON.parse and PHP's json_decode silently collapse duplicate object keys (last value wins), so a catalog can carry the same key twice and still parse as valid JSON. That is how the duplicate de/de_DE empty-state keys reached master and needed the follow-up in #562. Add tests/l10n/check-duplicate-keys.py, which parses every l10n/*.{js,json} catalog with an object_pairs_hook that inspects all key/value pairs before deduplication and fails on any repeated key (covering the nested translations object of the .json format and the OC.L10N.register wrapper of the .js format). Wire it up as a 'make test-l10n' target and a dedicated l10n-lint GitHub Actions workflow so it runs on every push and pull request. Verified the checker flags the exact duplicates from the pre-#562 tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
phil-davis
approved these changes
Jul 27, 2026
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.
Adds a CI gate that fails when any
l10n/*.{js,json}catalog contains a duplicate translation key — the class of defect that slipped through in #561 and needed the follow-up fix in #562.Why a dedicated checker
Both
JSON.parse(JS) and PHPjson_decodesilently collapse duplicate object keys (last value wins). So a catalog can carry the same key twice, still parse as "valid JSON", and quietly ship a last-wins translation. Plain JSON validation cannot catch this — the checker inspects all key/value pairs before deduplication viajson'sobject_pairs_hook.Changes
tests/l10n/check-duplicate-keys.py— scans every catalog and reports each duplicated key..json: parsed directly; the hook runs on the nestedtranslationsobject too..js: theOC.L10N.register("notes", { … }, "plural…")wrapper is stripped (brace-matching that respects string literals) and the inner object is parsed with the same hook.file: key; placed undertests/l10n/(notl10n/, which theappstorebuild copies wholesale into the package).Makefile—make test-l10ntarget, mirroring the existingtest-*targets, as the shared entrypoint for CI and local runs..github/workflows/l10n-lint.yml— dedicated workflow (push to master + PRs) runningmake test-l10n.actions/checkoutis SHA-pinned to v7.0.1; Python 3 comes preinstalled onubuntu-latest, so no extra action is needed.github-actionsDependabot coverage already exists to keep the pin current.Verification
make test-l10npasses on currentmaster(138 catalogs, clean post-fix(l10n): remove duplicate de/de_DE empty-state keys #562)..jsand into the nested object of a.jsoneach fail with the right file + key.bf8b73f8), the checker flags the exactde/de_DENo note selected/Create a note…duplicates — i.e. it would have blocked feat(l10n): backfill translations for all languages #561.🤖 Generated with Claude Code