Skip to content

feat(frontend): localize UI into Chinese and default to English#841

Closed
Junt184 wants to merge 1 commit into
kenn-io:mainfrom
Junt184:feat/i18n-chinese
Closed

feat(frontend): localize UI into Chinese and default to English#841
Junt184 wants to merge 1 commit into
kenn-io:mainfrom
Junt184:feat/i18n-chinese

Conversation

@Junt184

@Junt184 Junt184 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Title:
feat(frontend): localize UI into Chinese and default to English

Description:
Adds full Simplified Chinese (zh-CN) localization for the SPA and makes
English the default interface language.

What changed

  • Wires ~80 Svelte components and App.svelte through svelte-i18n
    ($_), replacing hard-coded English strings across the
    header/navigation, sidebar and session list, message/tool/thinking
    content, the session analysis panel, analytics dashboards (heatmaps,
    velocity, tool/skill usage), usage, trends, insights, activity, all
    modals, filters, and every settings section.
  • Expands en.json and zh-CN.json to 869 keys each with full parity.
    Counts use ICU plurals and dynamic sentences use parameterized
    messages rather than concatenated fragments. Technical identifiers
    (agent/model names, CLI snippets, file paths, API paths) are left
    untranslated.
  • Defaults the interface to English: chooseInitialLocale now honors
    only an explicit stored preference instead of auto-detecting the
    browser language, so the UI stays English until the user opts into
    another locale via Settings → Language.

Fixes

  • The language-switcher dropdown was clipped by the section box.
    SettingsSection gains an opt-in allowOverflow prop so a
    typeahead popover can escape the rounded container; the header keeps
    its own corner clipping.

Notes

  • initI18n() is now called in the vitest setup so component tests can
    format messages; tests resolve to the en locale, so existing
    English-facing assertions are unaffected.
  • Shared controls (e.g. OptionTypeahead) continue to receive
    translated labels/placeholders from their callers rather than holding
    copy internally.

Where to look

  • frontend/src/lib/i18n/index.ts — locale selection / default.
  • frontend/src/lib/i18n/locales/{en,zh-CN}.json — dictionaries.
  • frontend/src/lib/components/settings/SettingsSection.svelte
    allowOverflow.

Wire ~80 Svelte components and App.svelte through svelte-i18n ($_),
replacing hard-coded English strings across the header/navigation,
sidebar and session list, message/tool/thinking content, the session
analysis panel, analytics dashboards (heatmaps, velocity, tools,
skills), usage, trends, insights, activity, all modals, filters, and
every settings section.

Expand en.json and zh-CN.json to 869 keys each with full parity. Use
ICU plurals for counts and parameterized messages for dynamic
sentences; leave technical identifiers (agent/model names, CLI
snippets, paths) untranslated.

Default the interface to English: chooseInitialLocale now honors only
an explicit stored preference instead of auto-detecting the browser
language, so the UI stays English until the user opts into another
locale.

Fix the language-switcher dropdown being clipped by adding an
allowOverflow option to SettingsSection. Initialize i18n in the vitest
setup so component tests can format messages.
@roborev-ci

roborev-ci Bot commented Jun 24, 2026

Copy link
Copy Markdown

roborev: Combined Review (8a39dc7)

Medium-risk XSS finding needs fixing before merge.

Medium

  • frontend/src/lib/components/modals/ConfirmDeleteModal.svelte:83, frontend/src/lib/components/modals/UpdateModal.svelte:50
    Dynamic values are interpolated into localized HTML strings rendered with {@html}. sessionName is derived from session metadata/content, so a crafted synced or imported session title such as <img src=x onerror=...> could execute when the delete modal opens. In authenticated remote mode, that script would run in the agentsview origin and could read stored auth data from localStorage or call API endpoints as the user. sync.latestVersion is also dynamic update metadata and is no longer escaped before insertion.

    Fix by avoiding {@html} for dynamic text. Split localized copy around real Svelte bindings such as <strong>{sessionName}</strong>, or HTML-escape dynamic values before interpolation and keep raw HTML limited to trusted static markup.


Panel: ci_default_security | Synthesis: codex, 8s | Members: codex_default (codex/default, done, 5m25s), codex_security (codex/security, done, 3m11s) | Total: 8m44s

@mariusvniekerk

Copy link
Copy Markdown
Collaborator

we've decided to not use svelte-i18n.

@Junt184 Junt184 closed this Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants