Skip to content

Commit e6b40a8

Browse files
author
testikun
committed
feat(i18n-ko): localize desktop slice 2 catalogs
1 parent ce10a0e commit e6b40a8

54 files changed

Lines changed: 7752 additions & 960 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import assert from 'node:assert/strict';
21+
import { test } from 'node:test';
22+
import { getArtifactCopy } from '../../renderer/locales/artifact-copy.js';
23+
import { getBrowserCopy } from '../../renderer/locales/browser-copy.js';
24+
import { getDesktopConversationCopy } from '../../renderer/locales/conversation-copy.js';
25+
import { getExternalSessionImportCopy } from '../../renderer/locales/external-session-import-copy.js';
26+
import { getMcpCopy } from '../../renderer/locales/mcp-copy.js';
27+
import { getPlanModeCopy } from '../../renderer/locales/plan-mode-copy.js';
28+
import { getBotSettingsCopy } from '../../renderer/locales/settings-bot-copy.js';
29+
import { getDailyReviewSettingsCopy } from '../../renderer/locales/settings-daily-review-copy.js';
30+
import { getDataSettingsCopy } from '../../renderer/locales/settings-data-copy.js';
31+
import { getHealthCenterCopy } from '../../renderer/locales/settings-health-copy.js';
32+
import type { HealthSignal } from '@maka/core/health';
33+
import { getMemorySettingsCopy } from '../../renderer/locales/settings-memory-copy.js';
34+
import { getSettingsNavigationCopy } from '../../renderer/locales/settings-navigation-copy.js';
35+
import { getSettingsProjectsCopy } from '../../renderer/locales/settings-projects-copy.js';
36+
import { getProviderSettingsCopy } from '../../renderer/features/connection-settings/index.js';
37+
import { getSettingsSharedCopy } from '../../renderer/locales/settings-shared-copy.js';
38+
import { getSubagentSettingsCopy } from '../../renderer/locales/settings-subagents-copy.js';
39+
import { getSettingsTasksCopy } from '../../renderer/locales/settings-tasks-copy.js';
40+
import { settingsTestResultMessage } from '../../renderer/locales/settings-test-result-copy.js';
41+
import type { SettingsTestResult } from '@maka/core/settings';
42+
import { getUsageSettingsCopy } from '../../renderer/locales/settings-usage-copy.js';
43+
import { getWebSearchSettingsCopy } from '../../renderer/locales/settings-web-search-copy.js';
44+
import { getSettingsPreferencesCopy } from '../../renderer/locales/settings-preferences-copy.js';
45+
46+
function collectStrings(value: unknown): string[] {
47+
if (typeof value === 'string') return [value];
48+
if (typeof value === 'function' || value === null || typeof value !== 'object') return [];
49+
return Object.values(value).flatMap(collectStrings);
50+
}
51+
52+
test('all Desktop slice-2 catalogs expose visibly Korean copy', () => {
53+
const values = [
54+
getArtifactCopy('ko').pane.copy,
55+
getBrowserCopy('ko').title,
56+
getDesktopConversationCopy('ko').actions.conversationErrorTitle,
57+
getExternalSessionImportCopy('ko').sourceLabel,
58+
getMcpCopy('ko').page.setupTitle,
59+
getPlanModeCopy('ko').proposal.execute,
60+
getBotSettingsCopy('ko').overview.reload,
61+
getDailyReviewSettingsCopy('ko').aria,
62+
getDataSettingsCopy('ko').backupTitle,
63+
getHealthCenterCopy('ko').title,
64+
getMemorySettingsCopy('ko').text.title,
65+
getSettingsNavigationCopy('ko').sections.general.label,
66+
getSettingsProjectsCopy('ko').runtimeHost.title,
67+
getProviderSettingsCopy('ko').detail.modelKey,
68+
getSettingsSharedCopy('ko').modalLabel,
69+
getSubagentSettingsCopy('ko').section.title,
70+
getSettingsTasksCopy('ko').listAria,
71+
getUsageSettingsCopy('ko').details,
72+
getWebSearchSettingsCopy('ko').search,
73+
];
74+
75+
for (const value of values) assert.match(value, /[-]/u);
76+
const proxyDisabled: SettingsTestResult = { ok: false, code: 'proxy_disabled', message: '' };
77+
assert.match(settingsTestResultMessage(proxyDisabled, 'ko'), /[-]/u);
78+
});
79+
80+
test('Korean catalog additions do not leak Korean into English or leave key dynamic copy in English', () => {
81+
const catalogs = [
82+
getArtifactCopy,
83+
getBrowserCopy,
84+
getDesktopConversationCopy,
85+
getExternalSessionImportCopy,
86+
getMcpCopy,
87+
getPlanModeCopy,
88+
getBotSettingsCopy,
89+
getDailyReviewSettingsCopy,
90+
getDataSettingsCopy,
91+
getHealthCenterCopy,
92+
getMemorySettingsCopy,
93+
getSettingsNavigationCopy,
94+
getSettingsProjectsCopy,
95+
getProviderSettingsCopy,
96+
getSettingsSharedCopy,
97+
getSubagentSettingsCopy,
98+
getSettingsTasksCopy,
99+
getUsageSettingsCopy,
100+
getWebSearchSettingsCopy,
101+
];
102+
for (const getCopy of catalogs) {
103+
assert.equal(collectStrings(getCopy('en')).some((value) => /[-]/u.test(value)), false);
104+
}
105+
106+
assert.match(getMemorySettingsCopy('ko').text.localFile, /[-]/u);
107+
assert.match(getProviderSettingsCopy('ko').panel.loadFailed, /[-]/u);
108+
assert.match(getProviderSettingsCopy('ko').oauthFlow.refreshFailed, /[-]/u);
109+
assert.match(getHealthCenterCopy('ko').signalMessage({
110+
id: 'connection:test:runtime',
111+
label: '테스트',
112+
scope: 'llm_connection',
113+
layer: 'runtime_probe',
114+
status: 'ok',
115+
source: 'runtime_probe',
116+
checkedAt: 0,
117+
message: '',
118+
} satisfies HealthSignal), /[-]/u);
119+
const inspector = getDesktopConversationCopy('ko').inspector;
120+
assert.equal(inspector.callKind('daily_review'), '일일 검토');
121+
assert.equal(inspector.permissionDecision('allow'), '허용됨');
122+
assert.equal(inspector.retries(2), '2회 재시도');
123+
assert.equal(getMcpCopy('ko').toast.importedDetail(2), '2 서버를 가져왔습니다.');
124+
assert.equal(getMcpCopy('ko').row.tools(2), '2개 도구');
125+
assert.equal(getArtifactCopy('ko').preview.externalLinks(2), '이 미리보기에서는 외부 링크가 비활성화되었습니다. · 외부 링크 2개');
126+
assert.equal(getUsageSettingsCopy('ko').recordCount(2), '2개 기록');
127+
assert.deepEqual(getSettingsPreferencesCopy('en').personalization.localeOptions.at(-1), ['ko', '한국어']);
128+
assert.deepEqual(getSettingsPreferencesCopy('zh').personalization.localeOptions.at(-1), ['ko', '한국어']);
129+
});
130+
131+
test('Korean representative surfaces preserve interpolation', () => {
132+
const plan = getPlanModeCopy('ko');
133+
const conversation = getDesktopConversationCopy('ko');
134+
135+
assert.equal(plan.abandonConfirmation.description('Release plan'), '“Release plan”의 실행 기록은 유지되지만 다시 시작할 수 없습니다.');
136+
assert.equal(plan.execution.stepCount(2, 3), '2/3단계');
137+
assert.equal(conversation.actions.branchCreatedDescription('Release branch'), '새 작업: Release branch');
138+
});

apps/desktop/src/main/computer-use/status-item.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ const COPY: UiCatalog<StatusItemCopy> = {
142142
stopUnnamed: 'Stop Computer Use',
143143
empty: 'No Active Sessions',
144144
},
145+
ko: {
146+
stopUsing: (appName) => `${appName} 사용 중지`,
147+
stopUnnamed: 'Computer Use 중지',
148+
empty: '활성 세션 없음',
149+
},
145150
};
146151

147152
function defaultResolveLocale(): UiLocale {

apps/desktop/src/main/native-diagnostic-dialog-copy.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,52 @@ const COPY = {
167167
exit: '退出',
168168
},
169169
},
170+
ko: {
171+
dialog: {
172+
copy: '진단 정보 복사',
173+
copyAgain: '다시 복사',
174+
copied: '진단 정보가 복사되었습니다. 문제 보고서에 붙여넣을 수 있습니다.',
175+
copyFailed: '진단 정보를 복사할 수 없습니다.',
176+
},
177+
fatalStartup: {
178+
title: 'Maka를 시작하지 못했습니다',
179+
message: 'Maka가 시작을 완료하지 못했습니다.',
180+
detail: '시작 중 예기치 않은 오류가 발생했습니다. 진단 정보를 복사하면 자세한 내용을 확인할 수 있습니다.',
181+
exit: '종료',
182+
},
183+
rendererGone: {
184+
title: 'Maka 복구 필요',
185+
message: 'Maka 인터페이스가 예기치 않게 중지되었습니다.',
186+
detail: '인터페이스만 복구하며 Maka는 다시 시작하지 않습니다. Runtime Host와 실행 중인 작업은 유지됩니다.',
187+
recover: '인터페이스 복구',
188+
exit: '종료',
189+
},
190+
runtimeHostRecovery: {
191+
title: 'Maka Runtime Host 수정 필요',
192+
message: '이 작업 공간을 관리하는 Runtime Host를 시작할 수 없습니다.',
193+
detail: 'Maka는 이 Desktop에서 선택한 Runtime Host를 수정할 수 있습니다. 작업 공간, Host ID, 자격 증명 및 설정은 유지됩니다.',
194+
activeTasks: 'Host에서 실행 중인 작업이 있을 수 있습니다. 계속하면 먼저 중단한 후 Host를 다시 시작합니다.',
195+
repairFailed: '이전 수정이 완료되지 않았습니다. 진단 정보를 복사하면 자세한 내용을 확인할 수 있습니다.',
196+
repair: 'Runtime Host 수정',
197+
repairAndRestart: '수정 후 Host 다시 시작',
198+
exit: '종료',
199+
},
200+
defaultRuntimeHostRecovery: {
201+
title: '기본 Runtime Host에 연결할 수 없습니다',
202+
connectFailed: (profileName) => `${profileName}에 연결할 수 없습니다`,
203+
detail: '다시 시도하거나 Local을 기본 Host로 사용하거나 현재 선택을 유지하고 나중에 설정에서 처리할 수 있습니다.',
204+
retry: '다시 시도',
205+
useLocal: 'Local 사용',
206+
keepOffline: '오프라인 유지',
207+
},
208+
storageRootRepair: {
209+
title: 'Maka 작업 공간 수정 필요',
210+
message: 'Maka가 이 작업 공간을 확인할 수 없습니다.',
211+
detail: (workspaceRoot) => `시스템의 디스크 ID가 변경되었을 수 있습니다. 복사된 작업 공간이 아닌 이 컴퓨터의 원래 Maka 작업 공간인 경우에만 수정하세요.\n\n${workspaceRoot}`,
212+
repair: '작업 공간 수정',
213+
exit: '종료',
214+
},
215+
},
170216
} satisfies UiCatalog<NativeDiagnosticDialogCopy>;
171217

172218
export function getNativeDiagnosticDialogCopy(locale: UiLocale): NativeDiagnosticDialogCopy {

apps/desktop/src/main/permission-overlay/permission-overlay-copy.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,25 @@ const COPY: Catalog = {
8888
noBundle: 'Not running from a .app bundle, so there is nothing to drag. Add it manually in System Settings.',
8989
},
9090
},
91+
ko: {
92+
accessibility: {
93+
headline: (appName) => `${appName}을(를) 위 목록으로 드래그하여 손쉬운 사용을 허용하세요`,
94+
fallback: '또는 시스템 설정에서 +를 클릭하고 응용 프로그램에서 앱을 선택하세요.',
95+
granted: '손쉬운 사용 활성화됨',
96+
dismiss: '닫기',
97+
dragHint: '여기로 드래그',
98+
noBundle: '.app 번들에서 실행되지 않아 드래그할 수 없습니다. 시스템 설정에서 수동으로 추가하세요.',
99+
},
100+
screen_recording: {
101+
headline: (appName) => `${appName}을(를) 위 목록으로 드래그하여 화면 기록을 허용하세요`,
102+
fallback: '또는 시스템 설정에서 +를 클릭하고 응용 프로그램에서 앱을 선택하세요.',
103+
granted: '화면 기록 활성화됨',
104+
dismiss: '닫기',
105+
dragHint: '여기로 드래그',
106+
restartHint: '여전히 거부됨으로 표시되면 앱을 다시 시작하세요. macOS가 이전 거부 결과를 캐시합니다.',
107+
noBundle: '.app 번들에서 실행되지 않아 드래그할 수 없습니다. 시스템 설정에서 수동으로 추가하세요.',
108+
},
109+
},
91110
};
92111

93112
export function getPermissionOverlayCopy(

apps/desktop/src/main/runtime-host-quit-copy.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,13 @@ const COPY = {
7272
cause: '原因',
7373
button: '好',
7474
},
75+
ko: {
76+
title: 'Maka를 안전하게 종료할 수 없습니다',
77+
message: '로컬 Runtime Host를 안전하게 중지하지 못했습니다. Maka는 계속 실행 중입니다.',
78+
detail: '종료가 취소되었습니다. 다시 시도하거나 문제가 계속되면 진단 정보를 확인하세요.',
79+
process: (pid: number) => `Runtime Host 프로세스 PID: ${pid}`,
80+
manual: '다시 시도해도 실패하면 보존해야 할 실행이 없는지 확인한 후 운영 체제의 프로세스 관리 도구로 이 PID를 중지하세요.',
81+
cause: '원인',
82+
button: '확인',
83+
},
7584
} as const;

apps/desktop/src/main/runtime-host-upgrade-copy.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,26 @@ const UPGRADE_COPY = {
184184
resource: 'Runtime 资源', graph: 'Agent Graph', other: '其他后台活动',
185185
},
186186
},
187+
ko: {
188+
title: '이전 Runtime Host가 실행 중입니다',
189+
message: '다른 Runtime Host 프로세스가 이 작업 공간을 사용하고 있습니다.',
190+
restart: 'Runtime Host 다시 시작',
191+
replace: 'Host 중지 후 계속',
192+
wait: '대기',
193+
cancel: '시작 취소',
194+
uptime: (n: number) => `약 ${n}분 동안 실행됨`,
195+
connections: (n: number) => `${n}개의 다른 클라이언트가 아직 연결되어 있습니다`,
196+
operations: (n: number) => `${n}개의 작업이 실행 중입니다`,
197+
idleNotVerified: '안전한 교체 확인 중 Host가 유휴 상태인지 확인할 수 없습니다.',
198+
unknownActivity: '이 Host 버전은 백그라운드 활동을 보고할 수 없습니다.',
199+
processId: (pid: number) => `프로세스 ID(PID): ${pid}`,
200+
restartWarning: '다시 시작하면 영구 상태는 유지되지만 진행 중인 외부 작업이 중단될 수 있습니다.',
201+
replaceWarning: '중지하면 영구 상태는 유지되지만 진행 중인 외부 작업이 중단될 수 있습니다.',
202+
replaceExplanation: 'Maka가 이 Host를 중지하고 안전하게 교체한 후 시작을 계속합니다.',
203+
exitOwner: (pid: number) => `이 Host를 안전하게 교체하려면 시스템 프로세스 관리자에서 프로세스 ${pid}를 종료하세요.`,
204+
waitExplanation: '기다리면 이 Host가 종료된 후 Maka가 자동으로 계속합니다.',
205+
activity: {
206+
goal: '목표', scheduledTask: '예약된 작업', dailyReview: '일일 검토', execution: '활성 실행', resource: '런타임 리소스', graph: '에이전트 그래프', other: '기타 백그라운드 활동',
207+
},
208+
},
187209
} as const;

0 commit comments

Comments
 (0)