Skip to content

feat(ui): add chinese localization#160

Open
Craun718 wants to merge 1 commit into
HydroRoll-Team:mainfrom
Craun718:feat/i18n
Open

feat(ui): add chinese localization#160
Craun718 wants to merge 1 commit into
HydroRoll-Team:mainfrom
Craun718:feat/i18n

Conversation

@Craun718

@Craun718 Craun718 commented Jun 10, 2026

Copy link
Copy Markdown

Summary by Sourcery

Introduce a localization system with English and Chinese support and apply it across key UI flows, including settings, instances, authentication, and instance editing.

New Features:

  • Add a client-side i18n framework with locale detection, storage, and translation helpers for English and Chinese message catalogs.
  • Add a language selection control in the appearance settings and wrap the app in a language provider to enable runtime locale switching.

Enhancements:

  • Replace hard-coded UI text, validation messages, toast notifications, and button labels with localized strings throughout settings, instances, home, login, bottom bar, sidebar, and instance editor flows.
  • Localize date formatting and certain instance name defaults to be locale-aware while keeping existing behavior for English users.

@vercel

vercel Bot commented Jun 10, 2026

Copy link
Copy Markdown

@Craun718 is attempting to deploy a commit to the retrofor Team on Vercel.

A member of the Team first needs to authorize it.

@sourcery-ai

sourcery-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds a full i18n system with English and Chinese message dictionaries, wires a global LanguageProvider into the app, and replaces hard-coded UI strings, validation messages, toast texts, and labels across settings, instances, login, editor, and navigation with locale-aware translations and language switching.

File-Level Changes

Change Details Files
Introduce a centralized i18n system with English/Chinese dictionaries and a React context, then wrap the app with a LanguageProvider so components can access translations and current locale.
  • Create enMessages and zhMessages dictionaries with all UI copy and interpolation tokens for common, settings, instances, create, login, editor, auth, store, home, sidebar, and bottom-bar domains.
  • Implement i18n.tsx with locale detection/storage, a translate() helper supporting parameter interpolation, a LanguageProvider React context that exposes { locale, setLocale, t }, and a useI18n hook that throws if used outside the provider.
  • Wrap RouterProvider and Toaster with LanguageProvider in main.tsx and set document.documentElement.lang whenever locale changes.
packages/ui/src/lib/locales/en.ts
packages/ui/src/lib/locales/zh.ts
packages/ui/src/lib/i18n.tsx
packages/ui/src/main.tsx
Localize the Settings UI and add a user-facing language selector that drives the i18n locale.
  • Extend SettingsTab union to include "java" and import/use useI18n in SettingsPage to obtain t, locale, and setLocale.
  • Replace all literal strings in settings (titles, legends, labels, descriptions, tab labels, button text, toast error messages) with t() calls using the new keys.
  • Add a language Select in the Appearance tab bound to locale with Chinese/English choices and update the locale via setLocale with validation of allowed values.
  • Ensure effects that used to depend only on stores now also depend on t where translated messages are used in callbacks.
packages/ui/src/pages/settings.tsx
Localize the instance creation flow (wizard, validation, toasts, loading states) and make validation error messages translation-aware.
  • Use translate() in zod schemas for version and instance fields so validation messages are localized, and import useI18n into VersionComponent, InstanceComponent, and CreateInstancePage to access t and locale.
  • Replace hard-coded UI copy in filters, placeholders, buttons, headings, and progress text with t() keys, including loading states for versions/Fabric/Forge and error toasts for failed fetches or invalid state (missing version, missing loader selection, unsupported mod loader).
  • Localize displayed date formatting based on locale (zh-CN vs en-US) when rendering version releaseTime and update hooks’ dependency arrays (e.g., loadVersions, loadForgeVersions, loadFabricVersions, create handler) to include t.
  • Localize stepper step titles using translate() and update CreateInstancePage/PageWrapper layout text (titles, subtitles, wizard navigation buttons, cancel dialog copy) to use t().
packages/ui/src/pages/instances/create.tsx
Localize the instance editor modal, including file operations, error handling, dates, labels, and actions, and hook it into i18n.
  • Import and use useI18n in InstanceEditorModal to get t and locale and feed locale into toLocaleDateString for created/lastPlayed timestamps.
  • Replace confirm prompts, toasts for load/save/delete/open-explorer failures, success messages, error strings, aria-labels/titles, and all labels/descriptions (tabs, metadata, file list, memory/JVM settings, buttons) with t() calls and corresponding keys.
  • Update success/error messages that previously embedded English text to use interpolated localized strings, and extend effect/dependency arrays to include t where used inside callbacks.
packages/ui/src/components/instance-editor-modal.tsx
Localize the instances list page, including empty states, control buttons, error/info toasts, and dialog copy.
  • Import useI18n in InstancesPage and replace static titles, button labels (Import/Repair/Create Instance), empty state text, and no-version labels with t() keys.
  • Localize toasts for set active instance failures, game start failures, and missing prerequisites (no version installed, not logged in).
  • Localize delete and duplicate instance dialogs (titles, descriptions, cancel/confirm buttons, duplicate name placeholder) with parameterized strings for instance names.
packages/ui/src/pages/instances/index.tsx
Localize the login modal and auth model behavior, including Microsoft device-code instructions, offline login, and status/progress messages.
  • Import useI18n in LoginModal to localize dialog titles/descriptions, Microsoft/offline login button labels, field labels/descriptions, offline success toasts, copy-to-clipboard toast, instructions text (with interpolated URL/code/expiry seconds), and cancel/login buttons.
  • Update auth store to use translate() for statusMessage values, toast warnings/errors, and thrown error messages for empty username and offline/logout failures, including parameterized error messages for Microsoft login start/poll failures and general auth failures.
  • Ensure loginOnline/_pollLoginStatus use translation keys for "waiting", "slow down", "login successful/failed" variants and continue to propagate clear statusMessage for the UI.
packages/ui/src/components/login-modal.tsx
packages/ui/src/models/auth.ts
Localize global navigation, bottom bar, config editor, home, and settings store errors to ensure consistent language switching across the app shell.
  • In BottomBar, import useI18n and localize login/start/close button labels, no-instances/placeholder texts, no-version label, selection prompts, and toasts for missing instance and activate-instance failures, updating callbacks’ dependency arrays to include t.
  • In Sidebar, import useI18n and localize nav item labels (Overview/Instances/Settings), online/offline account status text, logout label, and dropdown trigger text via common.open.
  • In ConfigEditor, localize dialog title/description and footer buttons via t().
  • In HomePage, import useI18n and localize launcher status and "ready to launch" copy.
  • In settings store, replace the generic "Failed to load settings" toast with a translated message via translate().
packages/ui/src/components/bottom-bar.tsx
packages/ui/src/components/sidebar.tsx
packages/ui/src/components/config-editor.tsx
packages/ui/src/pages/home.tsx
packages/ui/src/models/settings.ts

Possibly linked issues

  • #多语言支持: PR adds full i18n (en/zh) and Chinese UI strings, directly satisfying the multi-language Chinese support request.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot 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.

Hey - I've found 2 issues, and left some high level feedback:

  • Several user-facing strings are still created outside the i18n hook via translate(...) at module initialization (e.g., zod schemas in create.tsx, stepper titles, and messages in the auth/instance/settings stores), so those messages won’t reflect runtime locale changes; consider moving them into components/hooks or passing a translated string from the caller so they react to language switches.
  • The duplicate-instance default name was changed to append the literal string Copy (in InstancesPage), which will remain English even in Chinese; consider using a localized template via t(...) (e.g., something like t("instances.copyName", { name: instance.name })).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Several user-facing strings are still created outside the i18n hook via `translate(...)` at module initialization (e.g., zod schemas in `create.tsx`, stepper titles, and messages in the auth/instance/settings stores), so those messages won’t reflect runtime locale changes; consider moving them into components/hooks or passing a translated string from the caller so they react to language switches.
- The duplicate-instance default name was changed to append the literal string `Copy` (in `InstancesPage`), which will remain English even in Chinese; consider using a localized template via `t(...)` (e.g., something like `t("instances.copyName", { name: instance.name })`).

## Individual Comments

### Comment 1
<location path="packages/ui/src/components/login-modal.tsx" line_range="72-81" />
<code_context>
-            Login to your Minecraft account or play offline
-          </DialogDescription>
+          <DialogTitle>{t("login.title")}</DialogTitle>
+          <DialogDescription>{t("login.desc")}</DialogDescription>
         </DialogHeader>
         <div className="p-4 w-full overflow-hidden">
</code_context>
<issue_to_address>
**issue:** Avoid duplicating URL/code text now that `login.instructions` includes them

`login.instructions` already interpolates `{url}`, `{code}`, and `{seconds}`, but the JSX still renders the link and code separately. This can lead to duplicated/awkward text and harder translations. Either let `login.instructions` provide the full sentence and remove the extra `url`/`code` rendering here, or make `login.instructions` only define the generic sentence structure and keep the explicit `<a>`/`<code>` elements in JSX. That way the wording is defined in exactly one place and translators have a clearer structure.
</issue_to_address>

### Comment 2
<location path="packages/ui/src/pages/instances/index.tsx" line_range="86" />
<code_context>
   const openDuplicate = (instance: Instance) => {
     setSelectedInstance(instance);
-    setDuplicateName(`${instance.name} (Copy)`);
+    setDuplicateName(`${instance.name} Copy`);
     setShowDuplicateModal(true);
   };
</code_context>
<issue_to_address>
**suggestion:** The default duplicate suffix is hardcoded in English; consider localizing it

Since the rest of this page is localized, it would be better to move this suffix into the i18n layer, e.g. via a key like `instances.copySuffix` or a template like `instances.copyNameTemplate` that takes the original name. That lets languages control both wording and word order.

Suggested implementation:

```typescript
  const openDuplicate = (instance: Instance) => {
    setSelectedInstance(instance);
    setDuplicateName(
      t("instances.copyNameTemplate", { name: instance.name })
    );
    setShowDuplicateModal(true);
  };

```

1. Add a new i18n key `instances.copyNameTemplate` in all locale files. For English, a suitable value would be `{{name}} Copy`.
2. Adjust the translation value per language to control both wording and word order as appropriate (e.g., `"Copy of {{name}}"`, `"Kopie von {{name}}"`, etc.).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +72 to 81
<DialogDescription>{t("login.desc")}</DialogDescription>
</DialogHeader>
<div className="p-4 w-full overflow-hidden">
{!authStore.loginMode && (
<div className="flex flex-col space-y-4">
<Button size="lg" onClick={handleMicrosoftLogin}>
<Mail />
Login with Microsoft
{t("login.microsoft")}
</Button>
<Button

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.

issue: Avoid duplicating URL/code text now that login.instructions includes them

login.instructions already interpolates {url}, {code}, and {seconds}, but the JSX still renders the link and code separately. This can lead to duplicated/awkward text and harder translations. Either let login.instructions provide the full sentence and remove the extra url/code rendering here, or make login.instructions only define the generic sentence structure and keep the explicit <a>/<code> elements in JSX. That way the wording is defined in exactly one place and translators have a clearer structure.

const openDuplicate = (instance: Instance) => {
setSelectedInstance(instance);
setDuplicateName(`${instance.name} (Copy)`);
setDuplicateName(`${instance.name} Copy`);

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.

suggestion: The default duplicate suffix is hardcoded in English; consider localizing it

Since the rest of this page is localized, it would be better to move this suffix into the i18n layer, e.g. via a key like instances.copySuffix or a template like instances.copyNameTemplate that takes the original name. That lets languages control both wording and word order.

Suggested implementation:

  const openDuplicate = (instance: Instance) => {
    setSelectedInstance(instance);
    setDuplicateName(
      t("instances.copyNameTemplate", { name: instance.name })
    );
    setShowDuplicateModal(true);
  };
  1. Add a new i18n key instances.copyNameTemplate in all locale files. For English, a suitable value would be {{name}} Copy.
  2. Adjust the translation value per language to control both wording and word order as appropriate (e.g., "Copy of {{name}}", "Kopie von {{name}}", etc.).

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.

1 participant