Skip to content

feat: add korean localization toggle#561

Open
gracefully91 wants to merge 4 commits intorealproject7:mainfrom
gracefully91:main
Open

feat: add korean localization toggle#561
gracefully91 wants to merge 4 commits intorealproject7:mainfrom
gracefully91:main

Conversation

@gracefully91
Copy link
Copy Markdown

한글화 해봤습니다~~

설정에 언어 선택 버튼도 넣었는데 확인해보세유~~

Copy link
Copy Markdown
Owner

@realproject7 realproject7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the Korean localization work @gracefully91 — the translations are natural and well done!

However, requesting changes before this can be merged:

Bug

  • Duplicate span in SetupWizard.tsx: The original English "Custom ports" <span> is left in alongside the new translated <span>, so both render side by side. The original should be replaced, not duplicated.

Code quality

  • Inline ternary pattern doesn't scale. Currently every string uses locale === "ko" ? "한글" : "English" directly in JSX — this is repeated hundreds of times across 18 files. Your own SettingsPage.tsx already uses a much cleaner dictionary (COPY) pattern. Could you refactor the other components to use the same approach? For example:
// Per-component or shared dictionary
const COPY = {
  en: { title: "Settings", save: "Save" },
  ko: { title: "설정", save: "저장" },
};
const t = COPY[locale];

// Then in JSX:
<h1>{t.title}</h1>

This keeps components readable and makes adding a third language trivial.

Minor

  • \n- in the welcome message headline ("QuadWork에 오신 걸 환영합니다\n- 첫 AI 개발 팀을 설정해볼까요") looks like a formatting artifact.

Happy to merge once these are addressed!

@gracefully91
Copy link
Copy Markdown
Author

Hi @realproject7! I've addressed all three points:

Bug — Removed the duplicate for "Custom ports" in SetupWizard.tsx
Code quality — Refactored all 16 components to use the per-component COPY dictionary pattern (matching SettingsPage.tsx)
Minor — Fixed the \n- artifact → restored as \n— to preserve the intended line break

Ready for re-review! 🍊

Copy link
Copy Markdown
Owner

@realproject7 realproject7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the duplicate span and the \n- artifact — both are fixed!

The COPY dictionary refactor is partially done but 49 inline locale === "ko" ternaries still remain in JSX across 17 files. These need to be moved into the COPY dictionaries for consistency and maintainability.


What needs to change

Rule: Every user-visible string must live in the COPY dictionary

No inline ternaries in JSX. Every locale === "ko" ? "한글" : "English" in rendering code should be replaced by a COPY key. The only place locale should appear in a component is:

const { locale } = useLocale();
const t = COPY[locale];

After that, JSX should only reference t.someKey — never locale directly.

How to handle strings with interpolation

Some inline ternaries were left because the string contains dynamic values like ${count}. Use a function in the COPY dictionary:

// ❌ Current (inline ternary with interpolation)
<span>{locale === "ko" ? `${count}개 항목` : `${count} items`}</span>

// ✅ Correct (function in COPY)
const COPY = {
  en: {
    itemCount: (n: number) => `${n} items`,
  },
  ko: {
    itemCount: (n: number) => `${n}개 항목`,
  },
};

// In JSX:
<span>{t.itemCount(count)}</span>

How to handle JSX elements inside translated strings

For strings that contain inline <code>, <strong>, etc., split the COPY entry into parts:

// ❌ Current (fragile string split)
t.cleanupIntro.split("~/.quadwork/{id}/agentchattr")

// ✅ Correct (structured COPY entries)
const COPY = {
  en: {
    cleanupBefore: "Per-project clones are necessary so multiple projects can run AgentChattr simultaneously without port conflicts. Existing v1 users are auto-migrated to per-project clones on the next ",
    cleanupCode: "~/.quadwork/{id}/agentchattr",
    cleanupAfter: "; once every project has a working clone, the legacy shared install can be removed safely via ",
  },
  ko: {
    cleanupBefore: "프로젝트별 클론은 ...",
    cleanupCode: "~/.quadwork/{id}/agentchattr",
    cleanupAfter: "; 모든 프로젝트에 ...",
  },
};

// In JSX:
<p>{t.cleanupBefore}<code>{t.cleanupCode}</code>{t.cleanupAfter}</p>

Files with remaining inline ternaries (all must be fixed)

High priority (many ternaries)

  1. SetupWizard.tsx — 13 inline ternaries

    • getInitialSteps() function has 12 ternaries for step labels and subtitles. Move all step label and subtitle strings into COPY:
      // ❌ Current
      { label: locale === "ko" ? "필수 도구" : "Prerequisites", subtitle: locale === "ko" ? "필수 도구 확인" : "Check required tools" }
      
      // ✅ Move to COPY
      const COPY = {
        en: {
          stepPrereqLabel: "Prerequisites",
          stepPrereqSubtitle: "Check required tools",
          // ... all other steps
        },
        ko: {
          stepPrereqLabel: "필수 도구",
          stepPrereqSubtitle: "필수 도구 확인",
        },
      };
      
      // Then:
      { label: t.stepPrereqLabel, subtitle: t.stepPrereqSubtitle }
    • Also fix the remaining JSX ternaries ("auto-detected", "no local clone found", branch protection text)
  2. GitHubPanel.tsx — 7 inline ternaries

    • Rate limit messages, Issues/PRs headers with counts, tooltip bodies
    • Use function pattern for count interpolations: issuesHeader: (n: number) => \ISSUES (${n})``
  3. BatchProgressPanel.tsx — 5 inline ternaries

    • Batch number display, items count, tooltip text
  4. HomeDashboard.tsx — 5 inline ternaries

    • Project count display
    • timeAgo() function has 4 ternaries for time units — move all into COPY as functions: minutesAgo: (n: number) => \${n}분 전``

Medium priority (1-2 ternaries each)

  1. ControlBar.tsx — 2 (tooltip help text for Keep Mac Awake and Notification Sound)
  2. AgentModelsWidget.tsx — 1-2
  3. AgentTerminalsGrid.tsx — 1-2
  4. DiscordBridgeWidget.tsx — 1-2
  5. TelegramBridgeWidget.tsx — 1-2
  6. LoopGuardWidget.tsx — 1-2
  7. OperatorFeaturesPanel.tsx — 1-2
  8. ProjectDashboard.tsx — 1-2
  9. ProjectHistoryWidget.tsx — 1-2
  10. ScheduledTriggerWidget.tsx — 1-2

For all of these: move the remaining tooltip bodies and dynamic labels into each file's COPY dictionary.


Other fixes needed

  1. Remove unnecessary type casts in SetupWizard.tsxlocale as "en" | "ko" is redundant since useLocale() already returns Locale which is "en" | "ko". Just use COPY[locale] directly.

  2. SettingsPage.tsx cleanup text — replace the fragile .split("~/.quadwork/{id}/agentchattr") approach with structured COPY entries (see example above).


Checklist before re-requesting review

  • Zero locale === "ko" ternaries remain in any JSX/rendering code
  • All user-visible strings live in COPY dictionaries
  • Strings with dynamic values use function entries in COPY
  • Strings with JSX elements use structured COPY entries (before/after pattern)
  • No as "en" | "ko" type casts
  • npm run build passes cleanly

@gracefully91
Copy link
Copy Markdown
Author

All 49 inline locale === "ko" ternaries have been moved into COPY dictionaries across all 17 files.

Removed the as "en" | "ko" type casts and replaced the .split() pattern in SettingsPage with structured before/code/after entries.

Thanks for the detailed breakdown!

@realproject7
Copy link
Copy Markdown
Owner

Hi @gracefully91! The localization work looks great — translations are natural and the COPY dictionary refactor is clean. Two things needed before we can merge:


1. Rebase on current main (critical)

Your fork is based on an older main. Since you opened this PR, we've merged 10+ PRs (security fixes, AC crash recovery, init/launch separation, etc.). Your branch currently carries reverse diffs to server files (server/index.js, bin/quadwork.js, server/routes.js, etc.) that would revert critical fixes if merged.

Git shows no merge conflicts, but that makes it worse — the reverts would happen silently.

Please rebase your branch on the latest main:

# Add the upstream remote (if not already)
git remote add upstream https://github.com/realproject7/quadwork.git

# Fetch latest
git fetch upstream main

# Rebase your branch
git rebase upstream/main

# Force-push to update the PR
git push --force-with-lease origin main

After rebasing, the diff should only show changes in src/, src/lib/locale.ts, and src/app/globals.css — no changes to server/, bin/, scripts/, or package.json.

2. Remove unused COPY keys in SettingsPage.tsx

These 4 keys are defined but never used in JSX (the function versions onlyInstalledMsg / installOtherMsg replaced them):

onlyInstalledPrefix
onlyInstalledSuffix
installOther
forMoreBackendOptions

Remove them from both the en and ko objects in SettingsPage.tsx's COPY dictionary.

3. Verify build

After rebasing, please confirm npm run build passes cleanly.


That's it! Once rebased and cleaned up, we're ready to merge. Thanks for the thorough work on this 🙏

@gracefully91
Copy link
Copy Markdown
Author

gracefully91 commented Apr 27, 2026

Good Night @realproject7!

I’ve updated the PR to address all your feedback:

  1. Rebase complete: I've rebased the branch onto the latest upstream/main.
    The diff now correctly shows changes only in src/,
    src/lib/locale.ts, and src/app/globals.css. All reverse diffs to the server and bin files have been cleared.

  2. Cleanup: Removed the 4 unused COPY keys (onlyInstalledPrefix, onlyInstalledSuffix, installOther,
    forMoreBackendOptions) from SettingsPage.tsx.
    I also refactored the CLI installation message to use the oneCliInstalled key and a cleaner localization logic.

  3. Refined Translations: Polished several Korean strings (especially the @Head instructions in the help modal)
    to make them more natural.

  4. Verified Build: Confirmed that npm run build passes cleanly without any type errors.

Everything should be ready for review now. Thanks! 🙏

Copy link
Copy Markdown
Owner

@realproject7 realproject7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gracefully91! Thank you for rebasing onto the latest main — the server/bin/scripts reverse diffs are gone, which was the critical blocker. Appreciate the effort on that!

However, it looks like the rebase may have lost the COPY dictionary refactor commits. The PR now has 160 inline locale === "ko" ternaries spread across 16 components — this is the same pattern from the first revision that we asked to be refactored in the second review.

Only 2 files (SettingsPage and HowToWorkModal) retained their COPY dictionaries. The other 14 components went back to inline ternaries.

What happened

Your pre-rebase branch had the COPY refactor done across all 17 files. During the rebase, those commits appear to have been lost or conflicted away, reverting most files back to the inline ternary approach.

Inline ternary count per file (all need COPY dicts)

File Inline ternaries
SetupWizard.tsx 67
HomeDashboard.tsx 17
GitHubPanel.tsx 14
ControlBar.tsx 10
HomeEmptyState.tsx 9
BatchProgressPanel.tsx 9
ProjectDashboard.tsx 7
ScheduledTriggerWidget.tsx 5
HowToWorkModal.tsx 5
AgentModelsWidget.tsx 4
AgentTerminalsGrid.tsx 3
TelegramBridgeWidget.tsx 2
ProjectHistoryWidget.tsx 2
OperatorFeaturesPanel.tsx 2
LoopGuardWidget.tsx 2
DiscordBridgeWidget.tsx 2

What needs to happen

Every locale === "ko" ? "한글" : "English" in JSX should be moved into a per-component COPY dictionary, exactly like your SettingsPage.tsx already does. Quick recap of the pattern:

// 1. Define COPY at module level
const COPY = {
  en: {
    title: "Agent Terminals",
    tooltipBold: "Do not type here directly",
    itemCount: (n: number) => `${n} items`,  // for interpolation
  },
  ko: {
    title: "에이전트 터미널",
    tooltipBold: "여기에 직접 입력하지 마세요",
    itemCount: (n: number) => `${n}개 항목`,
  },
} as const;

// 2. In the component
const { locale } = useLocale();
const t = COPY[locale];

// 3. In JSX — only reference t.*, never locale directly
<span>{t.title}</span>
<span>{t.itemCount(count)}</span>

Your pre-rebase branch already had this done perfectly. If you still have that branch locally (before the force push), you could cherry-pick just the COPY refactor commits on top of the current rebased branch. That would be the fastest path.

One more thing — server/index.js change

The PR currently includes a change to server/index.js (restart endpoint SIGKILL fallback + logging). This looks like a fix for #582, which is great, but it should go in a separate PR — this PR should only touch src/ and CSS. Please revert the server/index.js change from this branch.

Checklist before re-requesting review

  • Zero locale === "ko" ternaries in JSX (all moved to COPY dicts)
  • No changes outside src/ and src/app/globals.css
  • npm run build passes

Thanks for your patience — the translations themselves are excellent and we want to get this merged! The COPY dict pattern is the last gate.

@gracefully91
Copy link
Copy Markdown
Author

To. @realproject7!

Thanks for the precise feedback. I’ve addressed everything:

  1. COPY Refactor: Completed the COPY dictionary refactor across all 16 components.
    There are now zero inline locale === "ko" ternaries in the JSX.
  2. Server Revert: Reverted the accidental changes to server/index.js. The PR now strictly touches src/ and CSS.
  3. Final Build: Confirmed npm run build passes cleanly.

Ready for review! Thank you for your feedback!! 🍊

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.

2 participants