Skip to content

ci: gate against duplicate keys in l10n catalogs - #563

Merged
phil-davis merged 1 commit into
masterfrom
ci/l10n-duplicate-key-gate
Jul 27, 2026
Merged

ci: gate against duplicate keys in l10n catalogs#563
phil-davis merged 1 commit into
masterfrom
ci/l10n-duplicate-key-gate

Conversation

@DeepDiver1975

Copy link
Copy Markdown
Member

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 PHP json_decode silently 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 via json's object_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 nested translations object too.
    • .js: the OC.L10N.register("notes", { … }, "plural…") wrapper is stripped (brace-matching that respects string literals) and the inner object is parsed with the same hook.
    • Exits non-zero listing every offending file: key; placed under tests/l10n/ (not l10n/, which the appstore build copies wholesale into the package).
  • Makefilemake test-l10n target, mirroring the existing test-* targets, as the shared entrypoint for CI and local runs.
  • .github/workflows/l10n-lint.yml — dedicated workflow (push to master + PRs) running make test-l10n. actions/checkout is SHA-pinned to v7.0.1; Python 3 comes preinstalled on ubuntu-latest, so no extra action is needed. github-actions Dependabot coverage already exists to keep the pin current.

Verification

🤖 Generated with Claude Code

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>
@DeepDiver1975
DeepDiver1975 requested a review from a team as a code owner July 27, 2026 11:02
@phil-davis
phil-davis merged commit 1efd2a3 into master Jul 27, 2026
13 checks passed
@phil-davis
phil-davis deleted the ci/l10n-duplicate-key-gate branch July 27, 2026 11:08
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