feat: add korean localization toggle#561
feat: add korean localization toggle#561gracefully91 wants to merge 4 commits intorealproject7:mainfrom
Conversation
realproject7
left a comment
There was a problem hiding this comment.
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 ownSettingsPage.tsxalready 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!
|
Hi @realproject7! I've addressed all three points: Bug — Removed the duplicate for "Custom ports" in SetupWizard.tsx Ready for re-review! 🍊 |
realproject7
left a comment
There was a problem hiding this comment.
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)
-
SetupWizard.tsx — 13 inline ternaries
getInitialSteps()function has 12 ternaries for step labels and subtitles. Move all steplabelandsubtitlestrings 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)
-
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})``
-
BatchProgressPanel.tsx — 5 inline ternaries
- Batch number display, items count, tooltip text
-
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)
- ControlBar.tsx — 2 (tooltip help text for Keep Mac Awake and Notification Sound)
- AgentModelsWidget.tsx — 1-2
- AgentTerminalsGrid.tsx — 1-2
- DiscordBridgeWidget.tsx — 1-2
- TelegramBridgeWidget.tsx — 1-2
- LoopGuardWidget.tsx — 1-2
- OperatorFeaturesPanel.tsx — 1-2
- ProjectDashboard.tsx — 1-2
- ProjectHistoryWidget.tsx — 1-2
- 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
-
Remove unnecessary type casts in SetupWizard.tsx —
locale as "en" | "ko"is redundant sinceuseLocale()already returnsLocalewhich is"en" | "ko". Just useCOPY[locale]directly. -
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 buildpasses cleanly
|
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! |
|
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
|
|
Good Night @realproject7! I’ve updated the PR to address all your feedback:
Everything should be ready for review now. Thanks! 🙏 |
realproject7
left a comment
There was a problem hiding this comment.
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/andsrc/app/globals.css -
npm run buildpasses
Thanks for your patience — the translations themselves are excellent and we want to get this merged! The COPY dict pattern is the last gate.
…vert server changes
|
To. @realproject7! Thanks for the precise feedback. I’ve addressed everything:
Ready for review! Thank you for your feedback!! 🍊 |
한글화 해봤습니다~~
설정에 언어 선택 버튼도 넣었는데 확인해보세유~~