#21619: fix(i18n): load saved locale translations on page refresh
app: web-ui
size: S
experienced-contributor
Cluster:
Multilingual Support Enhancements
## Summary
Dashboard language setting doesn't persist after page refresh. The dropdown shows the correct locale (e.g. 简体中文), but all content renders in English.
## Root Cause
`I18nManager.loadLocale()` reads the saved locale from localStorage and sets `this.locale`, but never loads the corresponding translation file. Only English translations are available at construction time (`{ en }`). So `t()` always falls back to English for non-English locales on page load.
## Fix
- Extract translation loading into a shared `loadTranslations()` method
- Call it eagerly from `loadLocale()` when a non-English locale is detected
- `setLocale()` now reuses the same method (deduplicates the import logic)
- `notify()` is called after eager load so Lit controllers re-render with the correct locale
## Testing
All 4 existing i18n tests pass:
```
✓ chromium src/i18n/test/translate.test.ts (4 tests) 19ms
```
Fixes #21567
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Refactored i18n initialization to eagerly load saved locale translations on page refresh. Previously, `loadLocale()` read the saved locale from localStorage but never loaded the corresponding translation files, causing `t()` to always fall back to English. The fix extracts translation loading into a shared `loadTranslations()` method that is called both during initialization (for non-English locales) and when changing locales via `setLocale()`. The async loading pattern with `notify()` ensures Lit controllers re-render when translations finish loading.
- Extracted duplicate import logic into `loadTranslations()` method
- Added eager loading in `loadLocale()` for non-English locales
- Maintained backward compatibility with existing test suite
- Used fire-and-forget pattern (`void`) for async initialization, relying on reactive `notify()` to trigger re-renders when ready
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- Clean refactoring that extracts duplicate code, preserves existing test coverage (all 4 tests pass), and follows established patterns. The async loading approach with reactive notifications is appropriate for the Lit-based UI. No breaking changes or security concerns.
- No files require special attention
<sub>Last reviewed commit: e3d6fc0</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#23792: fix(i18n): trigger UI re-render on page load by calling notify() in...
by oom2018 · 2026-02-22
82.3%
#22165: feat(i18n): translate hardcoded button labels to all 4 locales
by NikolaVujovic1988 · 2026-02-20
79.1%
#13622: feat(i18n): add complete multi-language support (EN, TR, FR, DE)
by vaur94 · 2026-02-10
76.9%
#10657: feat(ui): add i18n support with English, Chinese, and Portuguese
by SalimBinYousuf1 · 2026-02-06
76.8%
#10586: feat: Add Chinese (zh-CN) localization support
by Maxsong-0 · 2026-02-06
73.5%
#23813: Fix UI locale persistence
by kamal-ayman · 2026-02-22
72.8%
#22332: i18n: add Korean (ko-KR) locale support
by arusia88 · 2026-02-21
72.6%
#22570: feat(i18n): add Korean (ko) locale to Control UI
by hoonsikim · 2026-02-21
71.8%
#21617: feat(i18n): added korean locale
by Jaejuna · 2026-02-20
71.0%
#9490: Add Internationalization (i18n) Support
by luuman · 2026-02-05
70.7%