Răsfoiți Sursa

feat(app): korean translations

Adam 1 lună în urmă
părinte
comite
e6438aa3f6

+ 13 - 4
packages/app/src/context/language.tsx

@@ -5,15 +5,17 @@ import { createSimpleContext } from "@opencode-ai/ui/context"
 import { Persist, persisted } from "@/utils/persist"
 import { dict as en } from "@/i18n/en"
 import { dict as zh } from "@/i18n/zh"
+import { dict as ko } from "@/i18n/ko"
 import { dict as uiEn } from "@opencode-ai/ui/i18n/en"
 import { dict as uiZh } from "@opencode-ai/ui/i18n/zh"
+import { dict as uiKo } from "@opencode-ai/ui/i18n/ko"
 
-export type Locale = "en" | "zh"
+export type Locale = "en" | "zh" | "ko"
 
 type RawDictionary = typeof en & typeof uiEn
 type Dictionary = i18n.Flatten<RawDictionary>
 
-const LOCALES: readonly Locale[] = ["en", "zh"]
+const LOCALES: readonly Locale[] = ["en", "zh", "ko"]
 
 function detectLocale(): Locale {
   if (typeof navigator !== "object") return "en"
@@ -22,6 +24,7 @@ function detectLocale(): Locale {
   for (const language of languages) {
     if (!language) continue
     if (language.toLowerCase().startsWith("zh")) return "zh"
+    if (language.toLowerCase().startsWith("ko")) return "ko"
   }
 
   return "en"
@@ -37,7 +40,11 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
       }),
     )
 
-    const locale = createMemo<Locale>(() => (store.locale === "zh" ? "zh" : "en"))
+    const locale = createMemo<Locale>(() => {
+      if (store.locale === "zh") return "zh"
+      if (store.locale === "ko") return "ko"
+      return "en"
+    })
 
     createEffect(() => {
       const current = locale()
@@ -48,7 +55,8 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
     const base = i18n.flatten({ ...en, ...uiEn })
     const dict = createMemo<Dictionary>(() => {
       if (locale() === "en") return base
-      return { ...base, ...i18n.flatten({ ...zh, ...uiZh }) }
+      if (locale() === "zh") return { ...base, ...i18n.flatten({ ...zh, ...uiZh }) }
+      return { ...base, ...i18n.flatten({ ...ko, ...uiKo }) }
     })
 
     const t = i18n.translator(dict, i18n.resolveTemplate)
@@ -56,6 +64,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
     const labelKey: Record<Locale, keyof Dictionary> = {
       en: "language.en",
       zh: "language.zh",
+      ko: "language.ko",
     }
 
     const label = (value: Locale) => t(labelKey[value])

+ 1 - 0
packages/app/src/i18n/en.ts

@@ -268,6 +268,7 @@ export const dict = {
 
   "language.en": "English",
   "language.zh": "Chinese",
+  "language.ko": "Korean",
 
   "toast.language.title": "Language",
   "toast.language.description": "Switched to {{language}}",

+ 547 - 0
packages/app/src/i18n/ko.ts

@@ -0,0 +1,547 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+  "command.category.suggested": "추천",
+  "command.category.view": "보기",
+  "command.category.project": "프로젝트",
+  "command.category.provider": "공급자",
+  "command.category.server": "서버",
+  "command.category.session": "세션",
+  "command.category.theme": "테마",
+  "command.category.language": "언어",
+  "command.category.file": "파일",
+  "command.category.terminal": "터미널",
+  "command.category.model": "모델",
+  "command.category.mcp": "MCP",
+  "command.category.agent": "에이전트",
+  "command.category.permissions": "권한",
+
+  "theme.scheme.system": "시스템",
+  "theme.scheme.light": "라이트",
+  "theme.scheme.dark": "다크",
+
+  "command.sidebar.toggle": "사이드바 토글",
+  "command.project.open": "프로젝트 열기",
+  "command.provider.connect": "공급자 연결",
+  "command.server.switch": "서버 전환",
+  "command.session.previous": "이전 세션",
+  "command.session.next": "다음 세션",
+  "command.session.archive": "세션 보관",
+
+  "command.palette": "명령 팔레트",
+
+  "command.theme.cycle": "테마 순환",
+  "command.theme.set": "테마 사용: {{theme}}",
+  "command.theme.scheme.cycle": "색상 테마 순환",
+  "command.theme.scheme.set": "색상 테마 사용: {{scheme}}",
+
+  "command.language.cycle": "언어 순환",
+  "command.language.set": "언어 사용: {{language}}",
+
+  "command.session.new": "새 세션",
+  "command.file.open": "파일 열기",
+  "command.file.open.description": "파일 및 명령어 검색",
+  "command.terminal.toggle": "터미널 토글",
+  "command.review.toggle": "검토 토글",
+  "command.terminal.new": "새 터미널",
+  "command.terminal.new.description": "새 터미널 탭 생성",
+  "command.steps.toggle": "단계 토글",
+  "command.steps.toggle.description": "현재 메시지의 단계 표시/숨기기",
+  "command.message.previous": "이전 메시지",
+  "command.message.previous.description": "이전 사용자 메시지로 이동",
+  "command.message.next": "다음 메시지",
+  "command.message.next.description": "다음 사용자 메시지로 이동",
+  "command.model.choose": "모델 선택",
+  "command.model.choose.description": "다른 모델 선택",
+  "command.mcp.toggle": "MCP 토글",
+  "command.mcp.toggle.description": "MCP 토글",
+  "command.agent.cycle": "에이전트 순환",
+  "command.agent.cycle.description": "다음 에이전트로 전환",
+  "command.agent.cycle.reverse": "에이전트 역순환",
+  "command.agent.cycle.reverse.description": "이전 에이전트로 전환",
+  "command.model.variant.cycle": "생각 수준 순환",
+  "command.model.variant.cycle.description": "다음 생각 수준으로 전환",
+  "command.permissions.autoaccept.enable": "편집 자동 수락",
+  "command.permissions.autoaccept.disable": "편집 자동 수락 중지",
+  "command.session.undo": "실행 취소",
+  "command.session.undo.description": "마지막 메시지 실행 취소",
+  "command.session.redo": "다시 실행",
+  "command.session.redo.description": "마지막 실행 취소된 메시지 다시 실행",
+  "command.session.compact": "세션 압축",
+  "command.session.compact.description": "컨텍스트 크기를 줄이기 위해 세션 요약",
+  "command.session.fork": "메시지에서 분기",
+  "command.session.fork.description": "이전 메시지에서 새 세션 생성",
+  "command.session.share": "세션 공유",
+  "command.session.share.description": "이 세션을 공유하고 URL을 클립보드에 복사",
+  "command.session.unshare": "세션 공유 중지",
+  "command.session.unshare.description": "이 세션 공유 중지",
+
+  "palette.search.placeholder": "파일 및 명령어 검색",
+  "palette.empty": "결과 없음",
+  "palette.group.commands": "명령어",
+  "palette.group.files": "파일",
+
+  "dialog.provider.search.placeholder": "공급자 검색",
+  "dialog.provider.empty": "공급자 없음",
+  "dialog.provider.group.popular": "인기",
+  "dialog.provider.group.other": "기타",
+  "dialog.provider.tag.recommended": "추천",
+  "dialog.provider.anthropic.note": "Claude Pro/Max 또는 API 키로 연결",
+
+  "dialog.model.select.title": "모델 선택",
+  "dialog.model.search.placeholder": "모델 검색",
+  "dialog.model.empty": "모델 결과 없음",
+  "dialog.model.manage": "모델 관리",
+  "dialog.model.manage.description": "모델 선택기에 표시할 모델 사용자 지정",
+
+  "dialog.model.unpaid.freeModels.title": "OpenCode에서 제공하는 무료 모델",
+  "dialog.model.unpaid.addMore.title": "인기 공급자의 모델 추가",
+
+  "dialog.provider.viewAll": "모든 공급자 보기",
+
+  "provider.connect.title": "{{provider}} 연결",
+  "provider.connect.title.anthropicProMax": "Claude Pro/Max로 로그인",
+  "provider.connect.selectMethod": "{{provider}} 로그인 방법 선택",
+  "provider.connect.method.apiKey": "API 키",
+  "provider.connect.status.inProgress": "인증 진행 중...",
+  "provider.connect.status.waiting": "인증 대기 중...",
+  "provider.connect.status.failed": "인증 실패: {{error}}",
+  "provider.connect.apiKey.description":
+    "{{provider}} API 키를 입력하여 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.",
+  "provider.connect.apiKey.label": "{{provider}} API 키",
+  "provider.connect.apiKey.placeholder": "API 키",
+  "provider.connect.apiKey.required": "API 키가 필요합니다",
+  "provider.connect.opencodeZen.line1":
+    "OpenCode Zen은 코딩 에이전트를 위해 최적화된 신뢰할 수 있는 엄선된 모델에 대한 액세스를 제공합니다.",
+  "provider.connect.opencodeZen.line2": "단일 API 키로 Claude, GPT, Gemini, GLM 등 다양한 모델에 액세스할 수 있습니다.",
+  "provider.connect.opencodeZen.visit.prefix": "",
+  "provider.connect.opencodeZen.visit.suffix": "를 방문하여 API 키를 받으세요.",
+  "provider.connect.oauth.code.visit.prefix": "",
+  "provider.connect.oauth.code.visit.link": "이 링크",
+  "provider.connect.oauth.code.visit.suffix":
+    "를 방문하여 인증 코드를 받아 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.",
+  "provider.connect.oauth.code.label": "{{method}} 인증 코드",
+  "provider.connect.oauth.code.placeholder": "인증 코드",
+  "provider.connect.oauth.code.required": "인증 코드가 필요합니다",
+  "provider.connect.oauth.code.invalid": "유효하지 않은 인증 코드",
+  "provider.connect.oauth.auto.visit.prefix": "",
+  "provider.connect.oauth.auto.visit.link": "이 링크",
+  "provider.connect.oauth.auto.visit.suffix":
+    "를 방문하고 아래 코드를 입력하여 계정을 연결하고 OpenCode에서 {{provider}} 모델을 사용하세요.",
+  "provider.connect.oauth.auto.confirmationCode": "확인 코드",
+  "provider.connect.toast.connected.title": "{{provider}} 연결됨",
+  "provider.connect.toast.connected.description": "이제 {{provider}} 모델을 사용할 수 있습니다.",
+
+  "model.tag.free": "무료",
+  "model.tag.latest": "최신",
+
+  "common.search.placeholder": "검색",
+  "common.loading": "로딩 중",
+  "common.cancel": "취소",
+  "common.submit": "제출",
+  "common.save": "저장",
+  "common.saving": "저장 중...",
+  "common.default": "기본값",
+  "common.attachment": "첨부 파일",
+
+  "prompt.placeholder.shell": "셸 명령어 입력...",
+  "prompt.placeholder.normal": '무엇이든 물어보세요... "{{example}}"',
+  "prompt.mode.shell": "셸",
+  "prompt.mode.shell.exit": "종료하려면 esc",
+
+  "prompt.example.1": "코드베이스의 TODO 수정",
+  "prompt.example.2": "이 프로젝트의 기술 스택이 무엇인가요?",
+  "prompt.example.3": "고장 난 테스트 수정",
+  "prompt.example.4": "인증 작동 방식 설명",
+  "prompt.example.5": "보안 취약점 찾기 및 수정",
+  "prompt.example.6": "사용자 서비스에 단위 테스트 추가",
+  "prompt.example.7": "이 함수를 더 읽기 쉽게 리팩터링",
+  "prompt.example.8": "이 오류는 무엇을 의미하나요?",
+  "prompt.example.9": "이 문제 디버깅 도와줘",
+  "prompt.example.10": "API 문서 생성",
+  "prompt.example.11": "데이터베이스 쿼리 최적화",
+  "prompt.example.12": "입력 유효성 검사 추가",
+  "prompt.example.13": "...를 위한 새 컴포넌트 생성",
+  "prompt.example.14": "이 프로젝트를 어떻게 배포하나요?",
+  "prompt.example.15": "모범 사례를 기준으로 내 코드 검토",
+  "prompt.example.16": "이 함수에 오류 처리 추가",
+  "prompt.example.17": "이 정규식 패턴 설명",
+  "prompt.example.18": "이것을 TypeScript로 변환",
+  "prompt.example.19": "코드베이스 전체에 로깅 추가",
+  "prompt.example.20": "오래된 종속성은 무엇인가요?",
+  "prompt.example.21": "마이그레이션 스크립트 작성 도와줘",
+  "prompt.example.22": "이 엔드포인트에 캐싱 구현",
+  "prompt.example.23": "이 목록에 페이지네이션 추가",
+  "prompt.example.24": "...를 위한 CLI 명령어 생성",
+  "prompt.example.25": "여기서 환경 변수는 어떻게 작동하나요?",
+
+  "prompt.popover.emptyResults": "일치하는 결과 없음",
+  "prompt.popover.emptyCommands": "일치하는 명령어 없음",
+  "prompt.dropzone.label": "이미지나 PDF를 여기에 드롭하세요",
+  "prompt.slash.badge.custom": "사용자 지정",
+  "prompt.context.active": "활성",
+  "prompt.context.includeActiveFile": "활성 파일 포함",
+  "prompt.action.attachFile": "파일 첨부",
+  "prompt.action.send": "전송",
+  "prompt.action.stop": "중지",
+
+  "prompt.toast.pasteUnsupported.title": "지원되지 않는 붙여넣기",
+  "prompt.toast.pasteUnsupported.description": "이미지나 PDF만 붙여넣을 수 있습니다.",
+  "prompt.toast.modelAgentRequired.title": "에이전트 및 모델 선택",
+  "prompt.toast.modelAgentRequired.description": "프롬프트를 보내기 전에 에이전트와 모델을 선택하세요.",
+  "prompt.toast.worktreeCreateFailed.title": "작업 트리 생성 실패",
+  "prompt.toast.sessionCreateFailed.title": "세션 생성 실패",
+  "prompt.toast.shellSendFailed.title": "셸 명령 전송 실패",
+  "prompt.toast.commandSendFailed.title": "명령 전송 실패",
+  "prompt.toast.promptSendFailed.title": "프롬프트 전송 실패",
+
+  "dialog.mcp.title": "MCP",
+  "dialog.mcp.description": "{{total}}개 중 {{enabled}}개 활성화됨",
+  "dialog.mcp.empty": "구성된 MCP 없음",
+
+  "mcp.status.connected": "연결됨",
+  "mcp.status.failed": "실패",
+  "mcp.status.needs_auth": "인증 필요",
+  "mcp.status.disabled": "비활성화됨",
+
+  "dialog.fork.empty": "분기할 메시지 없음",
+
+  "dialog.directory.search.placeholder": "폴더 검색",
+  "dialog.directory.empty": "폴더 없음",
+
+  "dialog.server.title": "서버",
+  "dialog.server.description": "이 앱이 연결할 OpenCode 서버를 전환합니다.",
+  "dialog.server.search.placeholder": "서버 검색",
+  "dialog.server.empty": "서버 없음",
+  "dialog.server.add.title": "서버 추가",
+  "dialog.server.add.url": "서버 URL",
+  "dialog.server.add.placeholder": "http://localhost:4096",
+  "dialog.server.add.error": "서버에 연결할 수 없습니다",
+  "dialog.server.add.checking": "확인 중...",
+  "dialog.server.add.button": "추가",
+  "dialog.server.default.title": "기본 서버",
+  "dialog.server.default.description":
+    "로컬 서버를 시작하는 대신 앱 실행 시 이 서버에 연결합니다. 다시 시작해야 합니다.",
+  "dialog.server.default.none": "선택된 서버 없음",
+  "dialog.server.default.set": "현재 서버를 기본값으로 설정",
+  "dialog.server.default.clear": "지우기",
+
+  "dialog.project.edit.title": "프로젝트 편집",
+  "dialog.project.edit.name": "이름",
+  "dialog.project.edit.icon": "아이콘",
+  "dialog.project.edit.icon.alt": "프로젝트 아이콘",
+  "dialog.project.edit.icon.hint": "이미지를 클릭하거나 드래그하세요",
+  "dialog.project.edit.icon.recommended": "권장: 128x128px",
+  "dialog.project.edit.color": "색상",
+
+  "context.breakdown.title": "컨텍스트 분석",
+  "context.breakdown.note": '입력 토큰의 대략적인 분석입니다. "기타"에는 도구 정의 및 오버헤드가 포함됩니다.',
+  "context.breakdown.system": "시스템",
+  "context.breakdown.user": "사용자",
+  "context.breakdown.assistant": "어시스턴트",
+  "context.breakdown.tool": "도구 호출",
+  "context.breakdown.other": "기타",
+
+  "context.systemPrompt.title": "시스템 프롬프트",
+  "context.rawMessages.title": "원시 메시지",
+
+  "context.stats.session": "세션",
+  "context.stats.messages": "메시지",
+  "context.stats.provider": "공급자",
+  "context.stats.model": "모델",
+  "context.stats.limit": "컨텍스트 제한",
+  "context.stats.totalTokens": "총 토큰",
+  "context.stats.usage": "사용량",
+  "context.stats.inputTokens": "입력 토큰",
+  "context.stats.outputTokens": "출력 토큰",
+  "context.stats.reasoningTokens": "추론 토큰",
+  "context.stats.cacheTokens": "캐시 토큰 (읽기/쓰기)",
+  "context.stats.userMessages": "사용자 메시지",
+  "context.stats.assistantMessages": "어시스턴트 메시지",
+  "context.stats.totalCost": "총 비용",
+  "context.stats.sessionCreated": "세션 생성됨",
+  "context.stats.lastActivity": "최근 활동",
+
+  "context.usage.tokens": "토큰",
+  "context.usage.usage": "사용량",
+  "context.usage.cost": "비용",
+  "context.usage.clickToView": "컨텍스트를 보려면 클릭",
+
+  "language.en": "영어",
+  "language.zh": "중국어",
+  "language.ko": "한국어",
+
+  "toast.language.title": "언어",
+  "toast.language.description": "{{language}}(으)로 전환됨",
+
+  "toast.theme.title": "테마 전환됨",
+  "toast.scheme.title": "색상 테마",
+
+  "toast.permissions.autoaccept.on.title": "편집 자동 수락 중",
+  "toast.permissions.autoaccept.on.description": "편집 및 쓰기 권한이 자동으로 승인됩니다",
+  "toast.permissions.autoaccept.off.title": "편집 자동 수락 중지됨",
+  "toast.permissions.autoaccept.off.description": "편집 및 쓰기 권한 승인이 필요합니다",
+
+  "toast.model.none.title": "선택된 모델 없음",
+  "toast.model.none.description": "이 세션을 요약하려면 공급자를 연결하세요",
+
+  "toast.file.loadFailed.title": "파일 로드 실패",
+
+  "toast.session.share.copyFailed.title": "URL 클립보드 복사 실패",
+  "toast.session.share.success.title": "세션 공유됨",
+  "toast.session.share.success.description": "공유 URL이 클립보드에 복사되었습니다!",
+  "toast.session.share.failed.title": "세션 공유 실패",
+  "toast.session.share.failed.description": "세션을 공유하는 동안 오류가 발생했습니다",
+
+  "toast.session.unshare.success.title": "세션 공유 해제됨",
+  "toast.session.unshare.success.description": "세션 공유가 성공적으로 해제되었습니다!",
+  "toast.session.unshare.failed.title": "세션 공유 해제 실패",
+  "toast.session.unshare.failed.description": "세션 공유를 해제하는 동안 오류가 발생했습니다",
+
+  "toast.session.listFailed.title": "{{project}}에 대한 세션을 로드하지 못했습니다",
+
+  "toast.update.title": "업데이트 가능",
+  "toast.update.description": "OpenCode의 새 버전({{version}})을 설치할 수 있습니다.",
+  "toast.update.action.installRestart": "설치 및 다시 시작",
+  "toast.update.action.notYet": "나중에",
+
+  "error.page.title": "문제가 발생했습니다",
+  "error.page.description": "애플리케이션을 로드하는 동안 오류가 발생했습니다.",
+  "error.page.details.label": "오류 세부 정보",
+  "error.page.action.restart": "다시 시작",
+  "error.page.action.checking": "확인 중...",
+  "error.page.action.checkUpdates": "업데이트 확인",
+  "error.page.action.updateTo": "{{version}} 버전으로 업데이트",
+  "error.page.report.prefix": "이 오류를 OpenCode 팀에 제보해 주세요: ",
+  "error.page.report.discord": "Discord",
+  "error.page.version": "버전: {{version}}",
+
+  "error.dev.rootNotFound":
+    "루트 요소를 찾을 수 없습니다. index.html에 추가하는 것을 잊으셨나요? 또는 id 속성의 철자가 틀렸을 수 있습니다.",
+
+  "error.globalSync.connectFailed": "서버에 연결할 수 없습니다. `{{url}}`에서 서버가 실행 중인가요?",
+
+  "error.chain.unknown": "알 수 없는 오류",
+  "error.chain.causedBy": "원인:",
+  "error.chain.apiError": "API 오류",
+  "error.chain.status": "상태: {{status}}",
+  "error.chain.retryable": "재시도 가능: {{retryable}}",
+  "error.chain.responseBody": "응답 본문:\n{{body}}",
+  "error.chain.didYouMean": "혹시 {{suggestions}}을(를) 의미하셨나요?",
+  "error.chain.modelNotFound": "모델을 찾을 수 없음: {{provider}}/{{model}}",
+  "error.chain.checkConfig": "구성(opencode.json)의 공급자/모델 이름을 확인하세요",
+  "error.chain.mcpFailed": 'MCP 서버 "{{name}}" 실패. 참고: OpenCode는 아직 MCP 인증을 지원하지 않습니다.',
+  "error.chain.providerAuthFailed": "공급자 인증 실패 ({{provider}}): {{message}}",
+  "error.chain.providerInitFailed": '공급자 "{{provider}}" 초기화 실패. 자격 증명과 구성을 확인하세요.',
+  "error.chain.configJsonInvalid": "{{path}}의 구성 파일이 유효한 JSON(C)가 아닙니다",
+  "error.chain.configJsonInvalidWithMessage": "{{path}}의 구성 파일이 유효한 JSON(C)가 아닙니다: {{message}}",
+  "error.chain.configDirectoryTypo":
+    '{{path}}의 "{{dir}}" 디렉터리가 유효하지 않습니다. 디렉터리 이름을 "{{suggestion}}"으로 변경하거나 제거하세요. 이는 흔한 오타입니다.',
+  "error.chain.configFrontmatterError": "{{path}}의 frontmatter 파싱 실패:\n{{message}}",
+  "error.chain.configInvalid": "{{path}}의 구성 파일이 유효하지 않습니다",
+  "error.chain.configInvalidWithMessage": "{{path}}의 구성 파일이 유효하지 않습니다: {{message}}",
+
+  "notification.permission.title": "권한 필요",
+  "notification.permission.description": "{{projectName}}의 {{sessionTitle}}에서 권한이 필요합니다",
+  "notification.question.title": "질문",
+  "notification.question.description": "{{projectName}}의 {{sessionTitle}}에서 질문이 있습니다",
+  "notification.action.goToSession": "세션으로 이동",
+
+  "notification.session.responseReady.title": "응답 준비됨",
+  "notification.session.error.title": "세션 오류",
+  "notification.session.error.fallbackDescription": "오류가 발생했습니다",
+
+  "home.recentProjects": "최근 프로젝트",
+  "home.empty.title": "최근 프로젝트 없음",
+  "home.empty.description": "로컬 프로젝트를 열어 시작하세요",
+
+  "session.tab.session": "세션",
+  "session.tab.review": "검토",
+  "session.tab.context": "컨텍스트",
+  "session.review.filesChanged": "{{count}}개 파일 변경됨",
+  "session.review.loadingChanges": "변경 사항 로드 중...",
+  "session.review.empty": "이 세션에 변경 사항이 아직 없습니다",
+  "session.messages.renderEarlier": "이전 메시지 렌더링",
+  "session.messages.loadingEarlier": "이전 메시지 로드 중...",
+  "session.messages.loadEarlier": "이전 메시지 로드",
+  "session.messages.loading": "메시지 로드 중...",
+
+  "session.context.addToContext": "컨텍스트에 {{selection}} 추가",
+
+  "session.new.worktree.main": "메인 브랜치",
+  "session.new.worktree.mainWithBranch": "메인 브랜치 ({{branch}})",
+  "session.new.worktree.create": "새 작업 트리 생성",
+  "session.new.lastModified": "최근 수정",
+
+  "session.header.search.placeholder": "{{project}} 검색",
+
+  "session.share.popover.title": "웹에 게시",
+  "session.share.popover.description.shared": "이 세션은 웹에 공개되었습니다. 링크가 있는 누구나 액세스할 수 있습니다.",
+  "session.share.popover.description.unshared":
+    "세션을 웹에 공개적으로 공유합니다. 링크가 있는 누구나 액세스할 수 있습니다.",
+  "session.share.action.share": "공유",
+  "session.share.action.publish": "게시",
+  "session.share.action.publishing": "게시 중...",
+  "session.share.action.unpublish": "게시 취소",
+  "session.share.action.unpublishing": "게시 취소 중...",
+  "session.share.action.view": "보기",
+  "session.share.copy.copied": "복사됨",
+  "session.share.copy.copyLink": "링크 복사",
+
+  "lsp.tooltip.none": "LSP 서버 없음",
+  "lsp.label.connected": "{{count}} LSP",
+
+  "prompt.loading": "프롬프트 로드 중...",
+  "terminal.loading": "터미널 로드 중...",
+  "terminal.title": "터미널",
+  "terminal.title.numbered": "터미널 {{number}}",
+
+  "common.closeTab": "탭 닫기",
+  "common.dismiss": "닫기",
+  "common.requestFailed": "요청 실패",
+  "common.moreOptions": "더 많은 옵션",
+  "common.learnMore": "더 알아보기",
+  "common.rename": "이름 바꾸기",
+  "common.reset": "초기화",
+  "common.delete": "삭제",
+  "common.close": "닫기",
+  "common.edit": "편집",
+  "common.loadMore": "더 불러오기",
+
+  "sidebar.settings": "설정",
+  "sidebar.help": "도움말",
+  "sidebar.workspaces.enable": "작업 공간 활성화",
+  "sidebar.workspaces.disable": "작업 공간 비활성화",
+  "sidebar.gettingStarted.title": "시작하기",
+  "sidebar.gettingStarted.line1": "OpenCode에는 무료 모델이 포함되어 있어 즉시 시작할 수 있습니다.",
+  "sidebar.gettingStarted.line2": "Claude, GPT, Gemini 등을 포함한 모델을 사용하려면 공급자를 연결하세요.",
+  "sidebar.project.recentSessions": "최근 세션",
+  "sidebar.project.viewAllSessions": "모든 세션 보기",
+
+  "settings.section.desktop": "데스크톱",
+  "settings.tab.general": "일반",
+  "settings.tab.shortcuts": "단축키",
+
+  "settings.general.section.appearance": "모양",
+  "settings.general.section.notifications": "시스템 알림",
+  "settings.general.section.sounds": "효과음",
+
+  "settings.general.row.language.title": "언어",
+  "settings.general.row.language.description": "OpenCode 표시 언어 변경",
+  "settings.general.row.appearance.title": "모양",
+  "settings.general.row.appearance.description": "기기에서 OpenCode가 보이는 방식 사용자 지정",
+  "settings.general.row.theme.title": "테마",
+  "settings.general.row.theme.description": "OpenCode 테마 사용자 지정",
+  "settings.general.row.font.title": "글꼴",
+  "settings.general.row.font.description": "코드 블록에 사용되는 고정폭 글꼴 사용자 지정",
+
+  "settings.general.notifications.agent.title": "에이전트",
+  "settings.general.notifications.agent.description": "에이전트가 완료되거나 주의가 필요할 때 시스템 알림 표시",
+  "settings.general.notifications.permissions.title": "권한",
+  "settings.general.notifications.permissions.description": "권한이 필요할 때 시스템 알림 표시",
+  "settings.general.notifications.errors.title": "오류",
+  "settings.general.notifications.errors.description": "오류가 발생했을 때 시스템 알림 표시",
+
+  "settings.general.sounds.agent.title": "에이전트",
+  "settings.general.sounds.agent.description": "에이전트가 완료되거나 주의가 필요할 때 소리 재생",
+  "settings.general.sounds.permissions.title": "권한",
+  "settings.general.sounds.permissions.description": "권한이 필요할 때 소리 재생",
+  "settings.general.sounds.errors.title": "오류",
+  "settings.general.sounds.errors.description": "오류가 발생했을 때 소리 재생",
+
+  "settings.shortcuts.title": "키보드 단축키",
+  "settings.shortcuts.reset.button": "기본값으로 초기화",
+  "settings.shortcuts.reset.toast.title": "단축키 초기화됨",
+  "settings.shortcuts.reset.toast.description": "키보드 단축키가 기본값으로 초기화되었습니다.",
+  "settings.shortcuts.conflict.title": "단축키가 이미 사용 중임",
+  "settings.shortcuts.conflict.description": "{{keybind}}은(는) 이미 {{titles}}에 할당되어 있습니다.",
+  "settings.shortcuts.unassigned": "할당되지 않음",
+  "settings.shortcuts.pressKeys": "키 누르기",
+
+  "settings.shortcuts.group.general": "일반",
+  "settings.shortcuts.group.session": "세션",
+  "settings.shortcuts.group.navigation": "탐색",
+  "settings.shortcuts.group.modelAndAgent": "모델 및 에이전트",
+  "settings.shortcuts.group.terminal": "터미널",
+  "settings.shortcuts.group.prompt": "프롬프트",
+
+  "settings.providers.title": "공급자",
+  "settings.providers.description": "공급자 설정은 여기서 구성할 수 있습니다.",
+  "settings.models.title": "모델",
+  "settings.models.description": "모델 설정은 여기서 구성할 수 있습니다.",
+  "settings.agents.title": "에이전트",
+  "settings.agents.description": "에이전트 설정은 여기서 구성할 수 있습니다.",
+  "settings.commands.title": "명령어",
+  "settings.commands.description": "명령어 설정은 여기서 구성할 수 있습니다.",
+  "settings.mcp.title": "MCP",
+  "settings.mcp.description": "MCP 설정은 여기서 구성할 수 있습니다.",
+
+  "settings.permissions.title": "권한",
+  "settings.permissions.description": "서버가 기본적으로 사용할 수 있는 도구를 제어합니다.",
+  "settings.permissions.section.tools": "도구",
+  "settings.permissions.toast.updateFailed.title": "권한 업데이트 실패",
+
+  "settings.permissions.action.allow": "허용",
+  "settings.permissions.action.ask": "묻기",
+  "settings.permissions.action.deny": "거부",
+
+  "settings.permissions.tool.read.title": "읽기",
+  "settings.permissions.tool.read.description": "파일 읽기 (파일 경로와 일치)",
+  "settings.permissions.tool.edit.title": "편집",
+  "settings.permissions.tool.edit.description": "파일 수정 (편집, 쓰기, 패치 및 다중 편집 포함)",
+  "settings.permissions.tool.glob.title": "Glob",
+  "settings.permissions.tool.glob.description": "glob 패턴을 사용하여 파일 일치",
+  "settings.permissions.tool.grep.title": "Grep",
+  "settings.permissions.tool.grep.description": "정규식을 사용하여 파일 내용 검색",
+  "settings.permissions.tool.list.title": "목록",
+  "settings.permissions.tool.list.description": "디렉터리 내 파일 나열",
+  "settings.permissions.tool.bash.title": "Bash",
+  "settings.permissions.tool.bash.description": "셸 명령어 실행",
+  "settings.permissions.tool.task.title": "작업",
+  "settings.permissions.tool.task.description": "하위 에이전트 실행",
+  "settings.permissions.tool.skill.title": "기술",
+  "settings.permissions.tool.skill.description": "이름으로 기술 로드",
+  "settings.permissions.tool.lsp.title": "LSP",
+  "settings.permissions.tool.lsp.description": "언어 서버 쿼리 실행",
+  "settings.permissions.tool.todoread.title": "할 일 읽기",
+  "settings.permissions.tool.todoread.description": "할 일 목록 읽기",
+  "settings.permissions.tool.todowrite.title": "할 일 쓰기",
+  "settings.permissions.tool.todowrite.description": "할 일 목록 업데이트",
+  "settings.permissions.tool.webfetch.title": "웹 가져오기",
+  "settings.permissions.tool.webfetch.description": "URL에서 콘텐츠 가져오기",
+  "settings.permissions.tool.websearch.title": "웹 검색",
+  "settings.permissions.tool.websearch.description": "웹 검색",
+  "settings.permissions.tool.codesearch.title": "코드 검색",
+  "settings.permissions.tool.codesearch.description": "웹에서 코드 검색",
+  "settings.permissions.tool.external_directory.title": "외부 디렉터리",
+  "settings.permissions.tool.external_directory.description": "프로젝트 디렉터리 외부의 파일에 액세스",
+  "settings.permissions.tool.doom_loop.title": "무한 반복",
+  "settings.permissions.tool.doom_loop.description": "동일한 입력으로 반복되는 도구 호출 감지",
+
+  "workspace.new": "새 작업 공간",
+  "workspace.type.local": "로컬",
+  "workspace.type.sandbox": "샌드박스",
+  "workspace.create.failed.title": "작업 공간 생성 실패",
+  "workspace.delete.failed.title": "작업 공간 삭제 실패",
+  "workspace.resetting.title": "작업 공간 재설정 중",
+  "workspace.resetting.description": "잠시 시간이 걸릴 수 있습니다.",
+  "workspace.reset.failed.title": "작업 공간 재설정 실패",
+  "workspace.reset.success.title": "작업 공간 재설정됨",
+  "workspace.reset.success.description": "작업 공간이 이제 기본 브랜치와 일치합니다.",
+  "workspace.status.checking": "병합되지 않은 변경 사항 확인 중...",
+  "workspace.status.error": "Git 상태를 확인할 수 없습니다.",
+  "workspace.status.clean": "병합되지 않은 변경 사항이 감지되지 않았습니다.",
+  "workspace.status.dirty": "이 작업 공간에서 병합되지 않은 변경 사항이 감지되었습니다.",
+  "workspace.delete.title": "작업 공간 삭제",
+  "workspace.delete.confirm": '"{{name}}" 작업 공간을 삭제하시겠습니까?',
+  "workspace.delete.button": "작업 공간 삭제",
+  "workspace.reset.title": "작업 공간 재설정",
+  "workspace.reset.confirm": '"{{name}}" 작업 공간을 재설정하시겠습니까?',
+  "workspace.reset.button": "작업 공간 재설정",
+  "workspace.reset.archived.none": "활성 세션이 보관되지 않습니다.",
+  "workspace.reset.archived.one": "1개의 세션이 보관됩니다.",
+  "workspace.reset.archived.many": "{{count}}개의 세션이 보관됩니다.",
+  "workspace.reset.note": "이 작업은 작업 공간을 기본 브랜치와 일치하도록 재설정합니다.",
+}

+ 1 - 0
packages/app/src/i18n/zh.ts

@@ -267,6 +267,7 @@ export const dict = {
 
   "language.en": "英语",
   "language.zh": "中文",
+  "language.ko": "韩语",
 
   "toast.language.title": "语言",
   "toast.language.description": "已切换到{{language}}",

+ 90 - 0
packages/ui/src/i18n/ko.ts

@@ -0,0 +1,90 @@
+export const dict = {
+  "ui.sessionReview.title": "세션 변경 사항",
+  "ui.sessionReview.diffStyle.unified": "통합 보기",
+  "ui.sessionReview.diffStyle.split": "분할 보기",
+  "ui.sessionReview.expandAll": "모두 펼치기",
+  "ui.sessionReview.collapseAll": "모두 접기",
+
+  "ui.sessionTurn.steps.show": "단계 표시",
+  "ui.sessionTurn.steps.hide": "단계 숨기기",
+  "ui.sessionTurn.summary.response": "응답",
+  "ui.sessionTurn.diff.showMore": "변경 사항 더 보기 ({{count}})",
+
+  "ui.sessionTurn.retry.retrying": "재시도 중",
+  "ui.sessionTurn.retry.inSeconds": "{{seconds}}초 후",
+
+  "ui.sessionTurn.status.delegating": "작업 위임 중",
+  "ui.sessionTurn.status.planning": "다음 단계 계획 중",
+  "ui.sessionTurn.status.gatheringContext": "컨텍스트 수집 중",
+  "ui.sessionTurn.status.searchingCodebase": "코드베이스 검색 중",
+  "ui.sessionTurn.status.searchingWeb": "웹 검색 중",
+  "ui.sessionTurn.status.makingEdits": "편집 수행 중",
+  "ui.sessionTurn.status.runningCommands": "명령어 실행 중",
+  "ui.sessionTurn.status.thinking": "생각 중",
+  "ui.sessionTurn.status.thinkingWithTopic": "생각 중 - {{topic}}",
+  "ui.sessionTurn.status.gatheringThoughts": "생각 정리 중",
+  "ui.sessionTurn.status.consideringNextSteps": "다음 단계 고려 중",
+
+  "ui.messagePart.diagnostic.error": "오류",
+  "ui.messagePart.title.edit": "편집",
+  "ui.messagePart.title.write": "작성",
+  "ui.messagePart.option.typeOwnAnswer": "직접 답변 입력",
+  "ui.messagePart.review.title": "답변 검토",
+
+  "ui.list.loading": "로딩 중",
+  "ui.list.empty": "결과 없음",
+  "ui.list.emptyWithFilter.prefix": "다음에 대한 결과 없음: ",
+  "ui.list.emptyWithFilter.suffix": "",
+
+  "ui.messageNav.newMessage": "새 메시지",
+
+  "ui.textField.copyToClipboard": "클립보드에 복사",
+  "ui.textField.copied": "복사됨",
+
+  "ui.imagePreview.alt": "이미지 미리보기",
+
+  "ui.tool.read": "읽기",
+  "ui.tool.list": "목록",
+  "ui.tool.glob": "Glob",
+  "ui.tool.grep": "Grep",
+  "ui.tool.webfetch": "웹 가져오기",
+  "ui.tool.shell": "셸",
+  "ui.tool.patch": "패치",
+  "ui.tool.todos": "할 일",
+  "ui.tool.todos.read": "할 일 읽기",
+  "ui.tool.questions": "질문",
+  "ui.tool.agent": "{{type}} 에이전트",
+
+  "ui.common.file.one": "파일",
+  "ui.common.file.other": "파일",
+  "ui.common.question.one": "질문",
+  "ui.common.question.other": "질문",
+
+  "ui.common.add": "추가",
+  "ui.common.cancel": "취소",
+  "ui.common.confirm": "확인",
+  "ui.common.dismiss": "닫기",
+  "ui.common.next": "다음",
+  "ui.common.submit": "제출",
+
+  "ui.permission.deny": "거부",
+  "ui.permission.allowAlways": "항상 허용",
+  "ui.permission.allowOnce": "한 번만 허용",
+
+  "ui.message.expand": "메시지 펼치기",
+  "ui.message.collapse": "메시지 접기",
+  "ui.message.copy": "복사",
+  "ui.message.copied": "복사됨!",
+  "ui.message.attachment.alt": "첨부 파일",
+
+  "ui.patch.action.deleted": "삭제됨",
+  "ui.patch.action.created": "생성됨",
+  "ui.patch.action.moved": "이동됨",
+  "ui.patch.action.patched": "패치됨",
+
+  "ui.question.subtitle.answered": "{{count}}개 답변됨",
+  "ui.question.answer.none": "(답변 없음)",
+  "ui.question.review.notAnswered": "(답변되지 않음)",
+  "ui.question.multiHint": "(해당하는 항목 모두 선택)",
+  "ui.question.custom.placeholder": "답변 입력...",
+}