Skip to content

feat(countries): localize country display names using active UI locale - #435

Merged
khaira777 merged 6 commits into
mainfrom
feat/issue-392-localized-country-names
Aug 21, 2026
Merged

feat(countries): localize country display names using active UI locale#435
khaira777 merged 6 commits into
mainfrom
feat/issue-392-localized-country-names

Conversation

@khaira777

Copy link
Copy Markdown
Contributor

Intent

Localize country names in the Setup and Settings selectors to the active UI locale using native Intl.DisplayNames, while keeping ISO country codes canonical, supporting localized sorting and search, and remaining fully offline without translation catalog bloat.

What Changed

  • Added getLocalizedCountryName, countryMatchesQuery, and sortCountriesByLocalizedName helpers in frontend/src/lib/countries.ts that use Intl.DisplayNames to resolve country names in the active UI locale, with cache and English fallback.
  • Updated the Setup and Settings country selectors to display localized country names, perform locale-aware search, and sort the dropdown list by localized name (with IN and AR pinned first).
  • Added a test:country-localization script and a new test file covering localized name resolution, multi-field search, and locale-aware sorting.

Risk Assessment

✅ Low: Change is well-bounded: new utility functions in countries.ts, two consumer pages updated, one test added. All assertions are behavioral. No security, error handling, or correctness issues found.

Testing

Ran the dedicated country-localization test, the run-test.sh wrapper, both frontend and backend builds, and a manual behavioral script that exercised localized name resolution (Intl.DisplayNames), multi-locale search matching (localized + English fallback + ISO code + currency + locale), localized sorting with pinned countries, and edge cases — all passed with no issues.

Evidence: Country localization test output
npm run test:country-localization
✅ Issue #392 country localization checks passed
Evidence: Manual behavioral evidence across 4 locales
=== Issue #392: Localized Country Names Evidence ===

--- 1. English localized names ---
DE (English): Germany
US (English): United States
JP (English): Japan

--- 2. Spanish localized names ---
DE (Spanish): Alemania
US (Spanish): Estados Unidos
JP (Spanish): Japón

--- 3. Portuguese (BR) localized names ---
DE (pt-BR): Alemanha
US (pt-BR): Estados Unidos
JP (pt-BR): Japão

--- 4. Farsi (fa-IR) localized names ---
DE (fa-IR): آلمان
US (fa-IR): ایالات متحده

--- 5. Search in localized context ---
Search "Alemania" (es): true
Search "Germany" (es): true
Search "DE" (es): true
Search "EUR" (es): true
Search "Brasil" (es): false

--- 6. Localized sorting (pinned IN, AR first) ---
Spanish sort: IN (India) -> AR (Argentina) -> DE (Alemania) -> US (Estados Unidos) -> JP (Japón)
Portuguese sort: IN (Índia) -> AR (Argentina) -> DE (Alemanha) -> US (Estados Unidos) -> JP (Japão)

--- 7. Edge cases ---
Empty code: ""
Unknown ZZ code: "Unknown Region"
Empty locale falls back to en: Germany

--- 8. Country list count (unchanged) ---
Total countries: 131

✅ All behavioral checks passed
Evidence: Evidence file
=== Issue #392: Localized Country Names Evidence ===

--- 1. English localized names ---
  DE (English): Germany
  US (English): United States
  JP (English): Japan

--- 2. Spanish localized names ---
  DE (Spanish): Alemania
  US (Spanish): Estados Unidos
  JP (Spanish): Japón

--- 3. Portuguese (BR) localized names ---
  DE (pt-BR): Alemanha
  US (pt-BR): Estados Unidos
  JP (pt-BR): Japão

--- 4. Farsi (fa-IR) localized names ---
  DE (fa-IR): آلمان
  US (fa-IR): ایالات متحده

--- 5. Search in localized context ---
  Search "Alemania" (es): true
  Search "Germany" (es): true
  Search "DE" (es): true
  Search "EUR" (es): true
  Search "Brasil" (es): false

--- 6. Localized sorting (pinned IN, AR first) ---
  Spanish sort: IN (India) -> AR (Argentina) -> DE (Alemania) -> US (Estados Unidos) -> JP (Japón)
  Portuguese sort: IN (Índia) -> AR (Argentina) -> DE (Alemanha) -> US (Estados Unidos) -> JP (Japão)

--- 7. Edge cases ---
  Empty code: ""
  Unknown ZZ code: "Unknown Region"
  Empty locale falls back to en: Germany

--- 8. Country list count (unchanged) ---
  Total countries: 131

✅ All behavioral checks passed — country names localize via Intl.DisplayNames

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

🔧 **Rebase** - 2 issues found → auto-fixed ✅
  • ⚠️ frontend/src/app/setup/page.tsx - merge conflict rebasing onto origin/main
  • ⚠️ package.json - merge conflict rebasing onto origin/main

🔧 Fix applied.
✅ Re-checked - no issues remain.

⚠️ **Review** - 1 info
  • 🚨 package.json:36 - test:issue-389-timezone-override was accidentally dropped from the test script. The old test script ended with ...&& bash tests/run-test.sh npm run test:startup-cache && bash tests/run-test.sh npm run test:issue-389-timezone-override, but the new one ends at test:startup-cache. The test:country-localization test was added (after test:phone) but test:issue-389-timezone-override was simultaneously removed from the tail, keeping the total count at 99. The script definition still exists and should be restored to the test chain.
  • ⚠️ frontend/src/app/(dashboard)/settings/page.tsx:263 - sortCountriesByLocalizedName(COUNTRIES, locale) is called on every render without useMemo. Since COUNTRIES is static and locale changes rarely, this recomputes a sorted copy of ~100 countries (with Intl.DisplayNames.of() calls per comparison) on every render. Consider wrapping in useMemo with [locale] dependency. Same applies to setup page line 157.

🔧 Fix: Restore test:issue-389-timezone-override to end of test chain in package.json
1 info still open:

  • ℹ️ tests/country-localization.test.ts:68 - The pt-BR sort test (lines 68-72) uses the same 5-country subset as the Spanish test (lines 63-67) and produces the identical expected order ['IN', 'AR', 'DE', 'US', 'JP']. It exercises a different locale argument but does not verify a different sorting outcome or a different code path — the pinned-first logic and localeCompare branch are already exercised by the Spanish test. Consider either removing the duplicate or choosing countries whose pt-BR alphabetical order diverges from Spanish to actually test locale-specific sorting.
✅ **Test** - passed

✅ No issues found.

  • npm run test:country-localization
  • bash tests/run-test.sh npm run test:country-localization
  • npm run build:frontend
  • npm run build
  • manual behavioral verification script exercising getLocalizedCountryName, countryMatchesQuery, sortCountriesByLocalizedName across en/es/pt-BR/fa-IR locales
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown

Greptile Summary

The PR localizes country names according to the active UI locale while retaining canonical ISO codes.

  • Adds cached Intl.DisplayNames resolution with an English fallback.
  • Adds localized country searching and sorting with India and Argentina pinned first.
  • Updates the Setup and Settings country selectors and adds focused behavioral tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
frontend/src/lib/countries.ts Adds localized country-name resolution, multi-field search, and locale-aware sorting without an accepted correctness issue.
frontend/src/app/setup/page.tsx Uses the localization helpers for the country picker and fully removes the previously reported redundant query normalization.
frontend/src/app/(dashboard)/settings/page.tsx Displays and orders Settings country options using the active UI locale without an accepted correctness issue.
tests/country-localization.test.ts Adds behavioral coverage for localized names, search fields, fallback behavior, and sorting.
package.json Registers the focused country-localization test in the repository test commands.

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment thread frontend/src/app/setup/page.tsx Outdated
@khaira777
khaira777 enabled auto-merge (squash) August 21, 2026 00:26
@khaira777
khaira777 merged commit edb980a into main Aug 21, 2026
13 checks passed
@khaira777
khaira777 deleted the feat/issue-392-localized-country-names branch August 21, 2026 00:29
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.

1 participant