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.
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, andi18next-icugives us native ICU MessageFormat so plurals, selects, dates, and numbers live in the catalog rather than in JSX.Scope
react-i18next+i18next-icuand a flat string catalog; mount anI18nProviderinmain.tsxinsideQueryClientProvider, above<App/>.enas the base catalog andzh-Hant(Traditional Chinese) as the first translated locale.placeholder/title/aria-labelattributes, empty-state copy, toast and error messages.Adding… / Add) and the hand-rolled plurals (${n} source${n === 1 ? '' : 's'}).Intl.DateTimeFormatandIntl.RelativeTimeFormat, replacing the ~8toLocale*calls and the hand-rolled relative-time helper.<html lang>from the active locale; localize the static<title>inindex.htmland the window title inpackages/desktop/src-tauri/tauri.conf.json.Heaviest surfaces to prioritize
CreateWorkspaceWizard(~28 strings),WorkspaceDetailsSheet(~21),History(~19, plus all date formatting),ProposalsandClarification(~14 each, including theirEMPTY_COPYmaps),Batch(long explanatory paragraphs). Two existingEMPTY_COPYconst maps can seed the catalog.Out of scope
enandzh-Hant: add as follow-ups once the extraction pipeline is in place.