Skip to content

feat(i18n): localize hardcoded strings across components - #83

Merged
GOODBOY008 merged 3 commits into
GOODBOY008:mainfrom
sunxiaobin89:feat/i18n-hardcoded-strings
Aug 12, 2026
Merged

feat(i18n): localize hardcoded strings across components#83
GOODBOY008 merged 3 commits into
GOODBOY008:mainfrom
sunxiaobin89:feat/i18n-hardcoded-strings

Conversation

@sunxiaobin89

Copy link
Copy Markdown
Contributor

Summary

Users running R-Shell with "follow system" language on a Chinese system saw English text in several places — most notably the update-check flow (toasts + dialog). The i18n mechanism itself was intact: the AUTO preference correctly resolves to zh-CN via get_system_locale, and both locale files had full, aligned keys. The problem was purely hardcoded English strings — components written/rewritten without routing user-visible text through t().

Root cause

Several components (update-checker, sync-dialog, integrated-file-browser, error-boundary, settings-modal, App.tsx, plus two unused ones) emitted raw English literals for toasts, titles, buttons, table headers, and error fallbacks instead of using the t('key') helper.

Changes

Localized 8 components — before → after on a Chinese system:

Component Before (hardcoded) After
update-checker.tsx Checking for updates…, You are up to date., Download update, Restart now, Later, Update ready to install … (18 strings) 正在检查更新... / 已是最新版本! / 下载更新 / 立即重启 / 稍后 / 更新已就绪,可安装
sync-dialog.tsx Directory Synchronization, Local Directory, Compare by, Select all, Sync (N items), Path/Action table headers, toasts … (33 strings) 目录同步 / 本地目录 / 比较方式 / 全选 / 同步(N 个项目)/ 路径/操作/本地/远程
integrated-file-browser.tsx Drop files or folders to upload, Open, Edit, Open Folder, item(s), file-info toast (7 strings) 拖放文件或文件夹以上传 / 打开 / 编辑 / 打开文件夹 / 个项目
settings-modal.tsx 2 spaces/4 spaces/8 spaces, Scroll left/right aria-labels 2 个空格 / 4 个空格 / 8 个空格
error-boundary.tsx Something went wrong, An unexpected error occurred, Retry 出错了 / 发生了意外错误 / 重试
App.tsx Connection Not Found, Already Connected, Switched to existing X connection 未找到连接 / 已连接 / 已切换到现有的 X 连接
connection-tabs.tsx, network-monitor.tsx hardcoded English localized — note: these two components are currently not mounted in the UI; localized for i18n completeness
  • Added 84 new en/zh key pairs; en.json and zh-CN.json stay exactly in parity (1044 keys each).
  • update-checker now reuses the pre-existing updateChecker.* dictionary keys the component previously ignored.
  • error-boundary (a class component) uses the i18n singleton (i18n.t) to avoid changing its named export.

Testing

  • 566 Vitest tests pass — includes 1 new test: an i18n completeness test asserting every t() key used in source resolves in the locale files (plural/context variants included) and that en/zh stay in parity.
  • pnpm i18n:check passes (key parity).
  • npx tsc --noEmit passes.
  • Manually verified on a Chinese macOS system: update-check flow, sync dialog, file-browser drag overlay, and settings tab-size options all render in Chinese.

- update-checker: full update flow (toast, dialog, buttons, error mapping) now uses t()
- sync-dialog: 33 hardcoded strings localized (title, labels, dropdowns, badges, table headers, toasts)
- integrated-file-browser: drag-overlay, context menu, paste count, file-info toast localized
- error-boundary: fallback error card localized via i18n singleton (class component)
- settings-modal: editor tab-size options and scroll aria-labels localized
- App.tsx: connection toasts and ErrorBoundary labels localized
- connection-tabs / network-monitor: localize unused components for i18n completeness
- locales: add 84 en/zh key pairs, parity maintained (1044 keys each)

Test: 566 tests pass, 1 new test covers i18n key completeness and locale parity
The follow/Home-navigation test waits for the breadcrumb to render '/home'
with findByTitle, whose default 1000ms timeout is occasionally exceeded on
slow CI runners (Windows), producing a pre-existing flake unrelated to the
i18n change. Bump the wait to 5000ms in the affected tests.

Test: 566 tests pass, 0 new tests

Copilot AI 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.

Pull request overview

This PR routes user-visible strings through the i18n translation layer across several UI components (notably the update-check flow), adds new locale keys while keeping en/zh parity, and updates/extends tests to validate i18n coverage.

Changes:

  • Replaced hardcoded UI/toast strings with t('...') / i18n.t('...') across multiple components (update checker, sync dialog, file browser, error boundary, etc.).
  • Expanded en.json and zh-CN.json with new key pairs to support the newly localized strings (maintaining parity).
  • Updated and added tests, including a new test intended to assert translation-key completeness across the source tree.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/locales/zh-CN.json Adds new zh-CN translations for newly localized UI strings; keeps parity with en.json.
src/locales/en.json Adds new English translations / keys used by updated components and tests.
src/components/update-checker.tsx Localizes update-check toasts/dialog text and error mappings via t().
src/components/sync-dialog.tsx Localizes sync dialog UI strings and toasts via t().
src/components/settings-modal.tsx Localizes scroll button aria-labels and tab-size options.
src/components/network-monitor.tsx Localizes currently-disabled network monitor placeholder copy.
src/components/integrated-file-browser.tsx Localizes drag overlay, context menu labels, and file-info toast formatting.
src/components/error-boundary.tsx Localizes error boundary fallback UI using the i18n singleton.
src/components/connection-tabs.tsx Localizes context menu items in connection tabs.
src/App.tsx Localizes connection-related toasts and error boundary labels.
src/tests/update-checker.test.tsx Updates assertions to match i18n-backed strings for update-check flow.
src/tests/integrated-file-browser-keyboard.test.tsx Increases timeouts to reduce CI flakiness.
src/tests/i18n.test.ts Adds a new locale parity / “all used keys exist” completeness test.
Suppressed comments (1)

src/tests/i18n.test.ts:42

  • require() and __dirname are not available in ESM modules (this repo is "type": "module"), so this new completeness test will throw at runtime. Use the ESM imports above and derive the src root from process.cwd() (or import.meta.url) instead.
    const fs = require('node:fs');
    const path = require('node:path');
    const srcDir = path.resolve(__dirname, '..');

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 1 to +5
import i18n from '../lib/i18n';
import { changeLanguage, applyLanguageFromPreference, getLanguagePreference, AUTO } from '../lib/i18n';
import { describe, it, expect, beforeEach } from 'vitest';
import en from '../locales/en.json';
import zhCN from '../locales/zh-CN.json';
<ContextMenuItem onClick={handlePasteFiles}>
<ClipboardPaste className="mr-2 h-4 w-4" />
{t('fileBrowser.contextMenu.paste')} {clipboard.files.length} item(s)
{t('fileBrowser.contextMenu.paste')} {t('fileBrowser.contextMenu.pasteCount', { count: clipboard.files.length })}
- i18n.test.ts: replace CJS require()/__dirname with ESM imports and
  process.cwd() to avoid ESM-incompatible globals in a "type": "module" repo
- integrated-file-browser: replace space-joined paste translation with a
  single plural key (pasteWithCount) so each locale controls word order

Test: 566 tests pass, 0 new tests

Copilot AI 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.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/locales/en.json:763

  • These new messages preserve the (s) hack and also render 1 items in singular cases. Define plural variants and pass the relevant value as i18next's count (the error summary may need separate pluralized fragments because it contains two counts). Nearby badge* keys demonstrate the established _one/_other pattern.
    "toastComplete": "Sync complete: {{count}} item(s) synchronized",
    "toastFinishedWithErrors": "Sync finished with {{errorCount}} error(s) out of {{processedItems}} items",

src/locales/en.json:760

  • This count-aware label renders Sync (1 items). Use i18next _one/_other variants in both locale files, as the badge keys below already do, so singular counts are grammatical.

This issue also appears on line 762 of the same file.

    "syncItems": "Sync ({{count}} items)",

src/components/sync-dialog.tsx:354

  • The toast title is localized, but its description still receives the frontend fallbacks "Upload failed" and "Download failed" from lines 323 and 345. When the backend returns success: false without an error, Chinese users therefore still see English in this sync toast. Add translated fallback keys while continuing to display backend-provided error text verbatim.
        toast.error(t('syncDialog.toastFailed', { path: entry.relativePath }), {
          description: err instanceof Error ? err.message : String(err),

@GOODBOY008
GOODBOY008 merged commit cb46764 into GOODBOY008:main Aug 12, 2026
4 checks passed
sunxiaobin89 added a commit to sunxiaobin89/r-shell that referenced this pull request Aug 12, 2026
Resolve conflict in integrated-file-browser-keyboard.test.tsx: keep the
upstream findByTitle 5s timeout (already merged in GOODBOY008#83) plus our test-level
15s budget for the terminal-follow test.
@sunxiaobin89
sunxiaobin89 deleted the feat/i18n-hardcoded-strings branch August 14, 2026 04:56
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.

3 participants