Skip to content

feat(studio): internationalize the app — string catalog, ICU formatting, locale switch #88

Description

@mroops0111

Studio currently has no internationalization: all ~350-450 user-facing strings are hardcoded English literals inline in JSX, dates use bare toLocaleString(), plurals are hand-rolled (${n} source${n === 1 ? '' : 's'}), and there is no way to switch language. This issue tracks making the app fully localizable.

Library

react-i18next + i18next-icu. It is the most widely used React i18n runtime, works cleanly with React 19 / Vite / Tauri, and i18next-icu gives us native ICU MessageFormat so plurals, selects, dates, and numbers live in the catalog rather than in JSX.

Scope

  • Add react-i18next + i18next-icu and a flat string catalog; mount an I18nProvider in main.tsx inside QueryClientProvider, above <App/>.
  • Ship en as the base catalog and zh-Hant (Traditional Chinese) as the first translated locale.
  • Extract all user-facing strings: JSX text, placeholder / title / aria-label attributes, empty-state copy, toast and error messages.
  • Use ICU MessageFormat for the ~10 pending-verb ternaries (Adding… / Add) and the hand-rolled plurals (${n} source${n === 1 ? '' : 's'}).
  • Add a centralized date / relative-time wrapper over Intl.DateTimeFormat and Intl.RelativeTimeFormat, replacing the ~8 toLocale* calls and the hand-rolled relative-time helper.
  • Add a language selector next to the existing Light/Dark control in the Appearance settings tab; persist the choice.
  • Drive <html lang> from the active locale; localize the static <title> in index.html and the window title in packages/desktop/src-tauri/tauri.conf.json.

Heaviest surfaces to prioritize

CreateWorkspaceWizard (~28 strings), WorkspaceDetailsSheet (~21), History (~19, plus all date formatting), Proposals and Clarification (~14 each, including their EMPTY_COPY maps), Batch (long explanatory paragraphs). Two existing EMPTY_COPY const maps can seed the catalog.

Out of scope

  • Native OS menus / dialogs: none exist today. If Rust-side native chrome is added later, it gets its own localization pass.
  • Additional target locales beyond en and zh-Hant: add as follow-ups once the extraction pipeline is in place.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions