Skip to content

fix(i18n): remove duplicate locale keys and guard with a regression test#2789

Open
rsnetworkinginc wants to merge 1 commit into
we-promise:mainfrom
rsnetworkinginc:fix/i18n-duplicate-locale-keys
Open

fix(i18n): remove duplicate locale keys and guard with a regression test#2789
rsnetworkinginc wants to merge 1 commit into
we-promise:mainfrom
rsnetworkinginc:fix/i18n-duplicate-locale-keys

Conversation

@rsnetworkinginc

@rsnetworkinginc rsnetworkinginc commented Jul 25, 2026

Copy link
Copy Markdown

PR body — we-promise/sure — account: rsnetworkinginc

Branch: fix/i18n-duplicate-locale-keys (in WSL clone /root/sure, commit dfd95b55, based on main @ 40b18e84)
Title: fix(i18n): remove duplicate locale keys that shadow translations


Summary

Fixes #1506 (and its duplicate #1502).

YAML resolves duplicate keys by silently letting the last occurrence win, so every duplicated key in a locale file hides an earlier definition without any warning. A scan of config/locales/**/*.yml found 11 same-level duplicates across 7 files:

File Duplicate key
config/locales/views/transactions/{en,de,nl,hu}.yml transactions.merge_duplicate — a stale flat string ("Yes, merge them") next to the merge_duplicate.success/failure mapping the controllers actually read
config/locales/views/securities/fr.yml securities.providers.{tiingo,eodhd,alpha_vantage,mfapi,binance_public} each defined twice
config/locales/views/settings/api_keys/hu.yml settings.api_keys.created.usage_instructions_title defined twice
config/locales/views/imports/en.yml imports.create.ndjson_uploaded defined twice

What changed

  • Removed each shadowed duplicate, keeping the currently-winning value in every case, so rendered output is unchanged — the files now simply match what I18n already loads.
    • The flat transactions.merge_duplicate string is dead either way: the merge button reads transactions.show.merge_duplicate, and the controllers read transactions.merge_duplicate.success/.failure (transactions_controller.rb:199-209, pending_duplicate_merges_controller.rb:58).
  • Added a non-skipped I18nTest#test_no_duplicate_keys_within_locale_files that walks the raw Psych AST of every file under config/locales and fails on same-level duplicate keys, so shadowed translations can't sneak back in. (The existing i18n-tasks checks in that file are all skipped; this one is fast — pure parsing, ~0.2 s — and runs.)

Test plan

  • bin/rails test test/i18n_test.rb — new test passes on this branch; on main it correctly reports all 11 duplicates listed above.
  • bin/rails test — full unit/integration suite green.
  • bin/rubocop — clean.

Checklist for opening: base = main, allow edits from maintainers ON.

Summary by CodeRabbit

  • Bug Fixes

    • Improved localized messaging for document uploads and API key security notices.
    • Removed duplicate or inconsistent translation entries across supported languages.
    • Refined duplicate-transaction options in several translations.
  • Tests

    • Added validation to detect duplicate translation keys and report their locations clearly.

YAML resolves duplicate keys by silently letting the last occurrence
win, so every duplicated key hides an earlier definition without any
warning:

- transactions/{en,de,nl,hu}.yml defined `transactions.merge_duplicate`
  twice: once as a stale flat string ("Yes, merge them") and once as the
  `success`/`failure` mapping the controllers actually read. The flat
  string is dead either way (the show view reads
  `transactions.show.merge_duplicate`), so drop it.
- securities/fr.yml listed five providers (tiingo, eodhd, alpha_vantage,
  mfapi, binance_public) twice inside `securities.providers`.
- settings/api_keys/hu.yml defined
  `settings.api_keys.created.usage_instructions_title` twice.
- imports/en.yml defined `imports.create.ndjson_uploaded` twice.

All removals keep the currently-winning value, so rendered output is
unchanged; this only makes the files match what I18n already loads.

Add a non-skipped I18nTest case that walks the raw Psych AST of every
file under config/locales and fails on same-level duplicate keys, so
shadowed translations can't sneak back in.

Fixes we-promise#1506
Fixes we-promise#1502
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Locale translation entries were reordered, removed, or expanded across import, securities, API-key, and transaction views. A new i18n test recursively inspects YAML ASTs to detect duplicate keys and report their locations.

Changes

Locale maintenance

Layer / File(s) Summary
Transaction locale corrections
config/locales/views/transactions/{de,en,hu,nl}.yml
Affected merge_duplicate entries were removed or repositioned within transaction duplicate-handling translations.
Supporting locale updates
config/locales/views/imports/en.yml, config/locales/views/securities/fr.yml, config/locales/views/settings/api_keys/hu.yml
Import and securities keys were reordered, while Hungarian API-key creation translations add security-warning and continuation strings.
Duplicate-key validation
test/i18n_test.rb
Adds recursive YAML AST scanning that reports duplicate keys and both their first and repeated definition lines.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related issues

  • Issue 1502 — Addresses duplicate locale keys, matching the duplicate-key cleanup and validation added here.

Possibly related PRs

  • we-promise/sure#1922 — Also modifies French i18n locale YAML files, including securities provider ordering.

Suggested labels: contributor:verified, pr:verified

Suggested reviewers: jjmata

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR removes duplicate transaction locale keys and adds a regression test, but it does not rename the key, update the view, or add ca/es/pl labels. Rename merge_duplicate to merge_duplicate_confirm in all locales, update app/views/transactions/show.html.erb, and add the missing labels in ca/es/pl.
Out of Scope Changes check ⚠️ Warning Changes in imports, securities, settings, and broad locale reordering go beyond the transaction locale fix requested in #1506. Limit the PR to the transaction locale duplicate-key fix and its regression test, or split unrelated locale cleanup into separate changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: duplicate locale keys are removed and a regression test is added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/i18n_test.rb`:
- Around line 63-90: Dedent the private helper method duplicate_key_offenses and
its entire body by two spaces so its indentation matches the surrounding class
and follows the project’s two-space Ruby style.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6c22e89e-4272-4990-a539-162ccecb4fe9

📥 Commits

Reviewing files that changed from the base of the PR and between 40b18e8 and dfd95b5.

📒 Files selected for processing (8)
  • config/locales/views/imports/en.yml
  • config/locales/views/securities/fr.yml
  • config/locales/views/settings/api_keys/hu.yml
  • config/locales/views/transactions/de.yml
  • config/locales/views/transactions/en.yml
  • config/locales/views/transactions/hu.yml
  • config/locales/views/transactions/nl.yml
  • test/i18n_test.rb
💤 Files with no reviewable changes (7)
  • config/locales/views/transactions/de.yml
  • config/locales/views/transactions/nl.yml
  • config/locales/views/settings/api_keys/hu.yml
  • config/locales/views/transactions/en.yml
  • config/locales/views/securities/fr.yml
  • config/locales/views/transactions/hu.yml
  • config/locales/views/imports/en.yml

Comment thread test/i18n_test.rb
Comment on lines +63 to +90
def duplicate_key_offenses(node, path, file)
offenses = []

case node
when Psych::Nodes::Mapping
first_definition_lines = {}

node.children.each_slice(2) do |key_node, value_node|
if key_node.is_a?(Psych::Nodes::Scalar)
key_path = path + [ key_node.value ]

if (first_line = first_definition_lines[key_node.value])
offenses << "#{file}:#{key_node.start_line + 1} duplicate key `#{key_path.join(".")}` (first defined on line #{first_line})"
else
first_definition_lines[key_node.value] = key_node.start_line + 1
end

offenses.concat(duplicate_key_offenses(value_node, key_path, file))
else
offenses.concat(duplicate_key_offenses(value_node, path, file))
end
end
when Psych::Nodes::Sequence
node.children.each { |child| offenses.concat(duplicate_key_offenses(child, path, file)) }
end

offenses
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use two-space indentation for the private helper.

duplicate_key_offenses and its body are indented one level too far; dedent this block by two spaces to match the rest of the class. As per coding guidelines, Ruby code should use 2-space indent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/i18n_test.rb` around lines 63 - 90, Dedent the private helper method
duplicate_key_offenses and its entire body by two spaces so its indentation
matches the surrounding class and follows the project’s two-space Ruby style.

Source: Coding guidelines

jjmata commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Reviewed the diff and verified the fix empirically (checked out both the base commit and the PR head into a scratch worktree and ran the new duplicate-key scan against each).

Removed duplicates — all verified as true, value-identical duplicates:

  • config/locales/views/imports/en.yml: create.ndjson_uploaded was defined twice (lines 411 and 421 pre-fix) with the identical string. Safe.
  • config/locales/views/securities/fr.yml: providers.{tiingo,eodhd,alpha_vantage,mfapi,binance_public} were verbatim re-declarations of the same five keys a few lines above (same values). moex_public — the only genuinely new key in that block — is correctly retained.
  • config/locales/views/settings/api_keys/hu.yml: created.usage_instructions_title was duplicated (lines 106/113 pre-fix, identical text). Fine.
  • config/locales/views/transactions/{de,en,hu,nl}.yml: the removed flat transactions.merge_duplicate string collided with the transactions.merge_duplicate: {success, failure} mapping declared later in each file. I grepped app/ and confirmed the codebase only ever reads transactions.merge_duplicate.success / .failure (in TransactionsController/PendingDuplicateMergesController) and the separate, untouched transactions.show.merge_duplicate (used in app/views/transactions/show.html.erb). Since YAML's last-key-wins and the mapping was declared after the flat string in every affected file, the flat string was already dead/shadowed before this PR — removing it is a no-op behaviorally, not a lost translation.

Regression test:

  • Ran the test's duplicate-detection logic against the pre-fix commit (40b18e8) and got exactly 11 offenses, matching 1:1 with every key/line this PR removes — confirming the test does fail without the fix.
  • Ran it against the PR head (dfd95b5) and got 0 offenses across the entire config/locales/**/*.yml tree (1852 files) — confirming it passes after the fix and that no other pre-existing duplicate slipped through.
  • The Dir[...config/locales/**/*.yml] glob is recursive, so it covers every locale file/language in the repo, not just en.yml.

Minor nit (non-blocking, already flagged by CodeRabbit): the duplicate_key_offenses private helper in test/i18n_test.rb is indented two spaces deeper than the rest of the class body — purely cosmetic.

No functional issues found. The scope is a bit broader than the linked issue (touches imports/securities/api_keys locales in addition to the transactions duplicate), but each change is independently a genuine duplicate-key fix, so I don't see a correctness concern with bundling them.


Generated by Claude Code

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.

Fix duplicate YAML key 'merge_duplicate' in transactions locale files

2 participants