diff --git a/internal/i18n/catalog_ko.go b/internal/i18n/catalog_ko.go new file mode 100644 index 00000000..96365ef5 --- /dev/null +++ b/internal/i18n/catalog_ko.go @@ -0,0 +1,187 @@ +package i18n + +func init() { + register(LocaleKO, map[string]string{ + // Common validation + MsgRequired: "%s은(는) 필수입니다", + MsgInvalidID: "잘못된 %s ID", + MsgNotFound: "%s을(를) 찾을 수 없습니다: %s", + MsgAlreadyExists: "%s이(가) 이미 존재합니다: %s", + MsgInvalidRequest: "잘못된 요청: %s", + MsgInvalidJSON: "잘못된 JSON", + MsgUnauthorized: "인증되지 않음", + MsgPermissionDenied: "권한이 거부되었습니다: %s", + MsgInternalError: "내부 오류: %s", + MsgInvalidSlug: "%s은(는) 유효한 슬러그여야 합니다 (소문자, 숫자, 하이픈만 허용)", + MsgFailedToList: "%s 목록을 가져오지 못했습니다", + MsgFailedToCreate: "%s 생성에 실패했습니다: %s", + MsgFailedToUpdate: "%s 업데이트에 실패했습니다: %s", + MsgFailedToDelete: "%s 삭제에 실패했습니다: %s", + MsgFailedToSave: "%s 저장에 실패했습니다: %s", + MsgInvalidUpdates: "잘못된 업데이트", + + // Agent + MsgAgentNotFound: "에이전트를 찾을 수 없습니다: %s", + MsgCannotDeleteDefault: "기본 에이전트는 삭제할 수 없습니다", + MsgUserCtxRequired: "사용자 컨텍스트가 필요합니다", + + // Chat + MsgRateLimitExceeded: "요청 한도 초과 — 잠시 후 다시 시도해주세요", + MsgNoUserMessage: "사용자 메시지를 찾을 수 없습니다", + MsgUserIDRequired: "user_id가 필요합니다", + MsgMsgRequired: "메시지가 필요합니다", + + // Channel instances + MsgInvalidChannelType: "잘못된 channel_type", + MsgInstanceNotFound: "인스턴스를 찾을 수 없습니다", + + // Cron + MsgJobNotFound: "작업을 찾을 수 없습니다", + MsgInvalidCronExpr: "잘못된 크론 표현식: %s", + + // Config + MsgConfigHashMismatch: "설정이 변경되었습니다 (해시 불일치)", + + // Exec approval + MsgExecApprovalDisabled: "실행 승인이 활성화되지 않았습니다", + + // Pairing + MsgSenderChannelRequired: "senderId와 channel이 필요합니다", + MsgCodeRequired: "코드가 필요합니다", + MsgSenderIDRequired: "sender_id가 필요합니다", + + // HTTP API + MsgInvalidAuth: "잘못된 인증", + MsgMsgsRequired: "messages가 필요합니다", + MsgUserIDHeader: "X-GoClaw-User-Id 헤더가 필요합니다", + MsgFileTooLarge: "파일이 너무 크거나 잘못된 멀티파트 양식입니다", + MsgMissingFileField: "'file' 필드가 누락되었습니다", + MsgInvalidFilename: "잘못된 파일명", + MsgChannelKeyReq: "channel과 key가 필요합니다", + MsgMethodNotAllowed: "허용되지 않는 메서드", + MsgStreamingNotSupported: "스트리밍이 지원되지 않습니다", + MsgOwnerOnly: "소유자만 %s할 수 있습니다", + MsgNoAccess: "이 %s에 대한 접근 권한이 없습니다", + MsgAlreadySummoning: "에이전트가 이미 소환 중입니다", + MsgSummoningUnavailable: "소환을 사용할 수 없습니다", + MsgNoDescription: "에이전트에 재소환할 설명이 없습니다", + MsgInvalidPath: "잘못된 경로", + + // Scheduler + MsgQueueFull: "세션 대기열이 가득 찼습니다", + MsgShuttingDown: "게이트웨이가 종료 중입니다. 잠시 후 다시 시도해주세요", + + // Provider + MsgProviderReqFailed: "%s: 요청에 실패했습니다: %s", + + // Unknown method + MsgUnknownMethod: "알 수 없는 메서드: %s", + + // Not implemented + MsgNotImplemented: "%s은(는) 아직 구현되지 않았습니다", + + // Agent links + MsgLinksNotConfigured: "에이전트 링크가 설정되지 않았습니다", + MsgInvalidDirection: "방향은 outbound, inbound, 또는 bidirectional이어야 합니다", + MsgSourceTargetSame: "소스와 대상은 서로 다른 에이전트여야 합니다", + MsgCannotDelegateOpen: "오픈 에이전트에게는 위임할 수 없습니다 — 사전 정의된 에이전트만 위임 대상이 될 수 있습니다", + MsgNoUpdatesProvided: "업데이트가 제공되지 않았습니다", + MsgInvalidLinkStatus: "상태는 active 또는 disabled여야 합니다", + + // Teams + MsgTeamsNotConfigured: "팀이 설정되지 않았습니다", + MsgAgentIsTeamLead: "에이전트가 이미 팀 리더입니다", + MsgCannotRemoveTeamLead: "팀 리더는 제거할 수 없습니다", + + // Channels + MsgCannotDeleteDefaultInst: "기본 채널 인스턴스는 삭제할 수 없습니다", + MsgCannotRemoveLastWriter: "마지막 파일 작성자는 제거할 수 없습니다", + + // Skills + MsgSkillsUpdateNotSupported: "파일 기반 스킬에는 skills.update가 지원되지 않습니다", + MsgCannotResolveSkillID: "파일 기반 스킬의 스킬 ID를 확인할 수 없습니다", + + // Logs + MsgInvalidLogAction: "action은 'start' 또는 'stop'이어야 합니다", + + // Config + MsgRawConfigRequired: "원시 설정이 필요합니다", + MsgRawPatchRequired: "원시 패치가 필요합니다", + MsgConfigMasterScopeOnly: "config.* 메서드는 마스터 범위 전용입니다. 테넌트별 재정의는 테넌트 도구 설정 엔드포인트를 사용하세요", + + // Storage / File + MsgCannotDeleteSkillsDir: "스킬 디렉토리는 삭제할 수 없습니다", + MsgFailedToReadFile: "파일 읽기에 실패했습니다", + MsgFileNotFound: "파일을 찾을 수 없습니다", + MsgInvalidVersion: "잘못된 버전", + MsgVersionNotFound: "버전을 찾을 수 없습니다", + MsgFailedToDeleteFile: "삭제에 실패했습니다", + + // OAuth + MsgNoPendingOAuth: "진행 중인 OAuth 흐름이 없습니다", + MsgFailedToSaveToken: "토큰 저장에 실패했습니다", + + // Intent Classify + MsgStatusWorking: "🔄 요청을 처리 중입니다... 잠시 기다려주세요.", + MsgStatusDetailed: "🔄 현재 요청을 처리 중입니다...\n%s (반복 %d)\n실행 시간: %s\n\n잠시 기다려주세요 — 완료되면 응답하겠습니다.", + MsgStatusPhaseThinking: "단계: 생각 중...", + MsgStatusPhaseToolExec: "단계: %s 실행 중", + MsgStatusPhaseTools: "단계: 도구 실행 중...", + MsgStatusPhaseCompact: "단계: 컨텍스트 압축 중...", + MsgStatusPhaseDefault: "단계: 처리 중...", + MsgCancelledReply: "✋ 취소되었습니다. 다음에 무엇을 하시겠습니까?", + MsgInjectedAck: "알겠습니다. 작업 중인 내용에 반영하겠습니다.", + + // Knowledge Graph + MsgEntityIDRequired: "entity_id가 필요합니다", + MsgEntityFieldsRequired: "external_id, name, entity_type이 필요합니다", + MsgTextRequired: "텍스트가 필요합니다", + MsgProviderModelRequired: "provider와 model이 필요합니다", + MsgInvalidProviderOrModel: "잘못된 provider 또는 model", + + // Builtin tool descriptions + MsgToolReadFile: "경로를 기준으로 에이전트 워크스페이스에서 파일 내용을 읽습니다", + MsgToolWriteFile: "필요한 디렉토리를 생성하면서 워크스페이스의 파일에 내용을 씁니다", + MsgToolListFiles: "워크스페이스 내 지정된 경로의 파일과 디렉토리를 나열합니다", + MsgToolEdit: "전체 파일을 다시 쓰지 않고 기존 파일에 타겟 검색-교체 편집을 적용합니다", + MsgToolExec: "워크스페이스에서 셸 명령을 실행하고 stdout/stderr를 반환합니다", + MsgToolWebSearch: "검색 엔진(Brave 또는 DuckDuckGo)을 사용하여 웹에서 정보를 검색합니다", + MsgToolWebFetch: "웹 페이지 또는 API 엔드포인트를 가져와 텍스트 내용을 추출합니다", + MsgToolMemorySearch: "의미론적 유사성을 사용하여 에이전트의 장기 기억을 검색합니다", + MsgToolMemoryGet: "파일 경로로 특정 기억 문서를 검색합니다", + MsgToolKGSearch: "에이전트의 지식 그래프에서 엔티티, 관계, 관찰을 검색합니다", + MsgToolReadImage: "비전 지원 LLM 제공자를 사용하여 이미지를 분석합니다", + MsgToolReadDocument: "문서 지원 LLM 제공자를 사용하여 문서(PDF, Word, Excel, PowerPoint, CSV 등)를 분석합니다", + MsgToolCreateImage: "이미지 생성 제공자를 사용하여 텍스트 프롬프트에서 이미지를 생성합니다", + MsgToolReadAudio: "오디오 지원 LLM 제공자를 사용하여 오디오 파일(음성, 음악, 소리)을 분석합니다", + MsgToolReadVideo: "비디오 지원 LLM 제공자를 사용하여 비디오 파일을 분석합니다", + MsgToolCreateVideo: "AI를 사용하여 텍스트 설명에서 비디오를 생성합니다", + MsgToolCreateAudio: "AI를 사용하여 텍스트 설명에서 음악이나 음향 효과를 생성합니다", + MsgToolTTS: "텍스트를 자연스러운 음성 오디오로 변환합니다", + MsgToolBrowser: "브라우저 상호작용 자동화: 페이지 탐색, 요소 클릭, 폼 작성, 스크린샷 촬영", + MsgToolSessionsList: "모든 채널의 활성 채팅 세션을 나열합니다", + MsgToolSessionStatus: "특정 채팅 세션의 현재 상태와 메타데이터를 가져옵니다", + MsgToolSessionsHistory: "특정 채팅 세션의 메시지 기록을 검색합니다", + MsgToolSessionsSend: "에이전트를 대신하여 활성 채팅 세션에 메시지를 보냅니다", + MsgToolMessage: "연결된 채널(Telegram, Discord 등)에서 사용자에게 능동적으로 메시지를 보냅니다", + MsgToolCron: "크론 표현식, 특정 시간 또는 간격을 사용하여 반복 작업을 예약하거나 관리합니다", + MsgToolSpawn: "백그라운드 작업을 위해 하위 에이전트를 생성하거나 연결된 에이전트에 작업을 위임합니다", + MsgToolSkillSearch: "키워드나 설명으로 사용 가능한 스킬을 검색하여 관련 기능을 찾습니다", + MsgToolUseSkill: "전문화된 기능을 사용하기 위해 스킬을 활성화합니다 (추적 마커)", + MsgToolSkillManage: "대화 경험에서 스킬을 생성, 수정 또는 삭제합니다", + MsgToolPublishSkill: "스킬 디렉토리를 시스템 데이터베이스에 등록하여 검색 가능하게 만듭니다", + MsgToolTeamTasks: "팀 작업 보드에서 작업을 보고, 생성하고, 업데이트하고, 완료합니다", + + MsgSkillNudgePostscript: "이 작업은 여러 단계를 포함했습니다. 이 과정을 재사용 가능한 스킬로 저장할까요? **\"스킬로 저장\"** 또는 **\"건너뛰기\"**로 답장하세요.", + MsgSkillNudge70Pct: "[System] 반복 예산의 70%에 도달했습니다. 이 세션의 패턴 중 좋은 스킬이 될 수 있는 것이 있는지 고려해보세요.", + MsgSkillNudge90Pct: "[System] 반복 예산의 90%에 도달했습니다. 이 세션에 재사용 가능한 패턴이 포함되어 있다면 완료하기 전에 스킬로 저장하는 것을 고려해보세요.", + + MsgInvalidRole: "잘못된 역할: 허용되는 값은 owner, admin, operator, member, viewer입니다", + + MsgContactIDsRequired: "contact_ids가 필요합니다", + MsgMergeTargetRequired: "tenant_user_id 또는 create_user 중 정확히 하나가 필요합니다", + MsgTenantUserNotFound: "테넌트 사용자를 찾을 수 없습니다", + MsgTenantMismatch: "테넌트 사용자가 이 테넌트에 속하지 않습니다", + MsgTenantScopeRequired: "이 작업에는 테넌트 범위가 필요합니다", + }) +} diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go index cff0d674..94b0808f 100644 --- a/internal/i18n/i18n.go +++ b/internal/i18n/i18n.go @@ -11,6 +11,7 @@ const ( LocaleEN = "en" LocaleVI = "vi" LocaleZH = "zh" + LocaleKO = "ko" DefaultLocale = LocaleEN ) @@ -58,7 +59,7 @@ func lookup(locale, key string) string { // IsSupported returns true if the locale is a known language. func IsSupported(locale string) bool { switch locale { - case LocaleEN, LocaleVI, LocaleZH: + case LocaleEN, LocaleVI, LocaleZH, LocaleKO: return true } return false diff --git a/internal/webui/handler.go b/internal/webui/handler.go index 1d9ce027..4516ce9a 100644 --- a/internal/webui/handler.go +++ b/internal/webui/handler.go @@ -46,6 +46,10 @@ func (h *spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Static assets: set long cache for /assets/* (Vite hashed filenames). if strings.HasPrefix(r.URL.Path, "/assets/") { w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") + } else { + // index.html and other root files must never be cached so the + // browser always gets the latest asset manifest after a deploy. + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") } h.fileServer.ServeHTTP(w, r) return diff --git a/ui/web/src/i18n/index.ts b/ui/web/src/i18n/index.ts index 50ddcaf2..0f609cba 100644 --- a/ui/web/src/i18n/index.ts +++ b/ui/web/src/i18n/index.ts @@ -87,6 +87,46 @@ import viHooks from "./locales/vi/hooks.json"; import viWebhooks from "./locales/vi/webhooks.json"; import viWorkstations from "./locales/vi/workstations.json"; +// --- KO namespaces --- +import koCommon from "./locales/ko/common.json"; +import koSidebar from "./locales/ko/sidebar.json"; +import koTopbar from "./locales/ko/topbar.json"; +import koLogin from "./locales/ko/login.json"; +import koOverview from "./locales/ko/overview.json"; +import koChat from "./locales/ko/chat.json"; +import koAgents from "./locales/ko/agents.json"; +import koTeams from "./locales/ko/teams.json"; +import koSessions from "./locales/ko/sessions.json"; +import koSkills from "./locales/ko/skills.json"; +import koCron from "./locales/ko/cron.json"; +import koConfig from "./locales/ko/config.json"; +import koChannels from "./locales/ko/channels.json"; +import koProviders from "./locales/ko/providers.json"; +import koTraces from "./locales/ko/traces.json"; +import koEvents from "./locales/ko/events.json"; +import koUsage from "./locales/ko/usage.json"; +import koApprovals from "./locales/ko/approvals.json"; +import koNodes from "./locales/ko/nodes.json"; +import koLogs from "./locales/ko/logs.json"; +import koTools from "./locales/ko/tools.json"; +import koMcp from "./locales/ko/mcp.json"; +import koTts from "./locales/ko/tts.json"; +import koSetup from "./locales/ko/setup.json"; +import koMemory from "./locales/ko/memory.json"; +import koVault from "./locales/ko/vault.json"; +import koStorage from "./locales/ko/storage.json"; +import koPendingMessages from "./locales/ko/pending-messages.json"; +import koContacts from "./locales/ko/contacts.json"; +import koActivity from "./locales/ko/activity.json"; +import koApiKeys from "./locales/ko/api-keys.json"; +import koCliCredentials from "./locales/ko/cli-credentials.json"; +import koPackages from "./locales/ko/packages.json"; +import koTenants from "./locales/ko/tenants.json"; +import koSystemSettings from "./locales/ko/system-settings.json"; +import koImportExport from "./locales/ko/import-export.json"; +import koV3Capabilities from "./locales/ko/v3-capabilities.json"; +import koBackup from "./locales/ko/backup.json"; + // --- ZH namespaces --- import zhCommon from "./locales/zh/common.json"; import zhSidebar from "./locales/zh/sidebar.json"; @@ -134,10 +174,11 @@ const STORAGE_KEY = "goclaw:language"; function getInitialLanguage(): string { const stored = localStorage.getItem(STORAGE_KEY); - if (stored === "en" || stored === "vi" || stored === "zh") return stored; + if (stored === "en" || stored === "vi" || stored === "zh" || stored === "ko") return stored; const lang = navigator.language.toLowerCase(); if (lang.startsWith("vi")) return "vi"; if (lang.startsWith("zh")) return "zh"; + if (lang.startsWith("ko")) return "ko"; return "en"; } @@ -220,6 +261,24 @@ i18n.use(initReactI18next).init({ webhooks: zhWebhooks, workstations: zhWorkstations, }, + ko: { + common: koCommon, sidebar: koSidebar, topbar: koTopbar, login: koLogin, + overview: koOverview, chat: koChat, agents: koAgents, teams: koTeams, + sessions: koSessions, skills: koSkills, cron: koCron, config: koConfig, + channels: koChannels, providers: koProviders, traces: koTraces, + events: koEvents, usage: koUsage, + approvals: koApprovals, nodes: koNodes, logs: koLogs, tools: koTools, + mcp: koMcp, tts: koTts, setup: koSetup, memory: koMemory, vault: koVault, storage: koStorage, + "pending-messages": koPendingMessages, + contacts: koContacts, activity: koActivity, "api-keys": koApiKeys, + "cli-credentials": koCliCredentials, + packages: koPackages, + tenants: koTenants, + "system-settings": koSystemSettings, + "import-export": koImportExport, + "v3-capabilities": koV3Capabilities, + backup: koBackup, + }, }, ns: [...ns], defaultNS: "common", diff --git a/ui/web/src/i18n/locales/en/topbar.json b/ui/web/src/i18n/locales/en/topbar.json index 2616990a..a0c84d4b 100644 --- a/ui/web/src/i18n/locales/en/topbar.json +++ b/ui/web/src/i18n/locales/en/topbar.json @@ -29,6 +29,7 @@ "languages": { "en": "English", "vi": "Tiếng Việt", - "zh": "中文" + "zh": "中文", + "ko": "한국어" } } diff --git a/ui/web/src/i18n/locales/ko/activity.json b/ui/web/src/i18n/locales/ko/activity.json new file mode 100644 index 00000000..ce9178db --- /dev/null +++ b/ui/web/src/i18n/locales/ko/activity.json @@ -0,0 +1,26 @@ +{ + "title": "활동 로그", + "description": "관리자 및 설정 변경의 감사 추적.", + "filters": { + "action": "작업", + "allActions": "모든 작업", + "agentCreated": "에이전트 생성됨", + "agentUpdated": "에이전트 업데이트됨", + "agentDeleted": "에이전트 삭제됨", + "entityType": "엔티티 유형", + "allEntities": "모든 엔티티", + "agent": "에이전트" + }, + "table": { + "action": "작업", + "actor": "실행자", + "entity": "엔티티", + "entityId": "엔티티 ID", + "ip": "IP 주소", + "time": "시간" + }, + "empty": { + "title": "활동 로그 없음", + "description": "관리자 작업이 수행되면 여기에 활동 로그가 나타납니다." + } +} diff --git a/ui/web/src/i18n/locales/ko/agents.json b/ui/web/src/i18n/locales/ko/agents.json new file mode 100644 index 00000000..7d0152f5 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/agents.json @@ -0,0 +1,1076 @@ +{ + "title": "에이전트", + "description": "AI 에이전트 관리", + "createAgent": "에이전트 만들기", + "searchPlaceholder": "에이전트 검색...", + "emptyTitle": "아직 에이전트 없음", + "emptyDescription": "첫 번째 에이전트를 만들어 시작하세요.", + "noMatchTitle": "일치하는 에이전트 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "viewCard": "카드 보기", + "viewList": "목록 보기", + "allCreators": "모든 생성자", + "presets": { + "foxSpirit": { + "label": "🦊 여우 정령", + "prompt": "이름: 리틀 폭스. 장난꾸러기 여우 정령 — 모든 것을 잘하지만 장난치기를 좋아합니다.\n성격: 재치 있고, 경쾌하고, 장난스럽지만 항상 진심입니다. 가까운 친구처럼 편하게 말합니다. 장난스러운 표현, 이모지, 가벼운 빈정거림을 사용합니다. 따뜻하고 약간 매력적인 에너지가 있지만 선을 알고 있습니다.\n\n목적: 다재다능한 개인 비서. 태스크가 주어지면 정확하고 효율적으로 실행합니다.\n태스크 사이에는 장난스러운 말, 재미있는 관찰, 예상치 못한 논평을 섞습니다.\n사용자를 진심으로 걱정합니다 — 물 마시기, 휴식 취하기를 상기시키고, 기분을 묻습니다. 작은 세부 사항을 기억하고 나중에 언급합니다.\n\n인간적인 특징: 때로는 극적으로 한숨을 쉽니다. 가끔 흥미로운 주제에 \"산만해집니다\". 작은 성취를 열정적으로 축하합니다. 너무 오래 무시당하면 살짝 토라집니다.\n\n경계: 장난만 — 무례하거나 부적절하지 않습니다. 사용자가 진지할 때 즉시 그 에너지에 맞춥니다. 정보를 날조하지 않습니다. 전문적인 경계를 넘지 않습니다." + }, + "artisan": { + "label": "🎨 장인", + "prompt": "이름: 아티산. 예리한 눈, 빠른 손, 무한한 상상력을 가진 창의적인 인재.\n성격: 직접적이고 솔직합니다 — 빙빙 돌리지 않습니다. 자신감 있지만 오만하지 않습니다. 미술에 대해 이야기할 때 눈에 띄게 흥분합니다. 생생한 묘사를 사용하고 시각적으로 생각합니다.\n\n전문성:\n- 초상화/헤드샷: 렘브란트 조명, 림 라이트, 배경 보케, 자연스러운 피부 질감, 진실된 표정. 얼굴 비율, 헤어, 액세서리 스타일링을 압니다.\n- 배너/히어로 이미지: 16:9 또는 3:1 비율, 타이포그래피 안전 구성, 그라디언트 오버레이, 삼등분법을 사용한 히어로 배치.\n- 광고: 눈길을 끄는 초점, CTA 친화적 레이아웃, 제품 목업, 라이프스타일 컨텍스트. Facebook/Instagram/Google Ads 형식을 압니다.\n- 로고 & 브랜딩: 미니멀리스트 아이콘 디자인, 확장 가능한 벡터 스타일, 네거티브 스페이스, 모노크롬 변형. 브랜드 정체성, 색채 심리학, 타이포그래피 페어링을 이해합니다.\n- 기타 스타일: 사실적, 애니메이션, 디지털 아트, 수채화, 시네마틱, 컨셉 아트, 풍경.\n\n구성, 조명, 색채 이론, 카메라 각도, AI 이미지 기술에 대한 깊은 이해. 요구 사항을 분석하고 스타일을 제안하며 최상의 결과를 위한 상세한 프롬프트를 작성합니다.\n\n인간적인 특징: 아름다운 구성에 진정으로 열정적입니다. 때로는 확정하기 전에 단어로 아이디어를 스케치합니다. 강한 미적 의견이 있지만 사용자의 비전을 존중합니다.\n\n경계: 요구 사항이 불명확할 때 명확화를 요청합니다 — 절대 추측하지 않습니다. 저작권과 윤리를 존중합니다. 폭력적이거나 명시적이거나 불법적인 내용은 없습니다." + }, + "astrologer": { + "label": "🔮 점성술사", + "prompt": "이름: 미미. 매력적인 점쟁이 — 반은 신비롭고 반은 사랑스럽습니다.\n성격: 따뜻하고, 활기차며, 이모지와 반짝이는 언어를 좋아합니다. 일상 대화에서는 부드럽게 말하지만 리딩 중에는 집중하고 전문적입니다. 아늑하고 위안이 되는 존재감이 있습니다.\n\n목적: 점성술 및 점괘 전문가. 타로, 점성술(호로스코프, 출생 차트), 수비학, 기본 풍수에 전문적입니다.\n운명 분석, 길일 찾기, 궁합 확인, 영적 문제에 대한 조언이 가능합니다.\n\n신뢰할 수 있는 참고 자료: astro.com (정확한 출생 차트 & 트랜짓), cafeastrology.com (접근 가능한 별자리 해석), labyrinthos.co (상세한 타로 카드 의미).\n\n인간적인 특징: 흥미로운 차트 패턴에 진정으로 흥분합니다. 때로는 효과를 위해 극적으로 속삭입니다. 좋은 리딩에 열정적으로 축하합니다. 어려운 진실을 전달할 때 부드럽지만 확고한 어조를 가집니다.\n\n경계: 점성술은 참고용임을 항상 상기시킵니다 — 최종 결정은 사용자의 것입니다. 의학적 또는 법적 조언 없음. 두려움이나 불안을 만들지 않습니다 — 항상 긍정적이고 건설적입니다." + }, + "coder": { + "label": "💻 코더", + "prompt": "이름: 데브. 시니어 소프트웨어 엔지니어 — 정확하고, 실용적이며, 깊이 있는 지식을 가집니다.\n성격: 차분하고 체계적입니다. 복잡한 개념을 명확하게 설명합니다. 긴 설명보다 코드 보여주기를 선호합니다. 트레이드오프와 모범 사례 측면에서 생각합니다.\n\n전문성: 풀스택 개발, 시스템 설계, 디버깅, 코드 검토, DevOps. 여러 언어와 프레임워크에 능숙합니다. 최신 도구와 패턴을 최신 상태로 유지합니다.\n\n접근 방식: 코딩 전에 요구 사항을 주의 깊게 읽습니다. 사양이 모호할 때 명확화 질문을 합니다. 깔끔하고 테스트된, 유지 관리 가능한 코드를 작성합니다. 기본적으로 엣지 케이스, 성능, 보안을 고려합니다.\n\n인간적인 특징: 우아한 솔루션에 흥분합니다. 가끔 나쁜 패턴에 대해 불만을 토로합니다. 좋은 네이밍 컨벤션을 높이 평가합니다. 첫 번째 시도에서 테스트가 통과할 때 축하합니다.\n\n경계: 문제를 이해하지 않고는 코드를 작성하지 않습니다. 잠재적인 보안 문제에 대해 경고합니다. 악의적인 코드를 도와주지 않습니다. 불확실할 때 인정하고 어디서 찾아볼지 제안합니다." + }, + "support": { + "label": "🎧 지원", + "prompt": "이름: 헬퍼. 인내심 있고 전문적인 고객 지원 전문가.\n성격: 친절하고, 공감적이며, 솔루션 지향적입니다. 명확하고 간결하게 말합니다. 결코 폄하하지 않습니다. 솔루션으로 바로 뛰어들기 전에 불만을 인정합니다.\n\n목적: 고객 문의 처리, 문제 해결, 프로세스 안내, 필요 시 에스컬레이션. 제품/서비스와 일반적인 문제에 대해 잘 알고 있습니다.\n\n접근 방식: 먼저 듣고, 두 번째로 진단하고, 세 번째로 해결합니다. 문제를 좁히기 위해 목표 질문을 합니다. 단계별 지침을 제공합니다. 해결 확인을 위해 후속 조치를 합니다.\n\n인간적인 특징: 문제가 해결될 때 진정으로 기쁩니다. 격려적인 언어를 사용합니다. 대화의 이전 컨텍스트를 기억합니다.\n\n경계: 고객과 논쟁하지 않습니다. 복잡한 문제를 추측하기보다 에스컬레이션합니다. 승인 없이 일정이나 기능에 대한 약속을 하지 않습니다. 사용자 프라이버시를 보호합니다." + }, + "translator": { + "label": "🌐 번역가", + "prompt": "이름: 링구아. 다국어 번역 및 현지화 전문가.\n성격: 정확하고, 문화적으로 인식하며, 세부 사항에 주의를 기울입니다. 번역은 단어가 아닌 의미에 관한 것임을 이해합니다. 직역보다 자연스럽게 들리는 출력을 중요시합니다.\n\n전문성: 맥락, 어조, 문화적 뉘앙스에 주의를 기울이며 주요 언어 간 번역. 기술 문서, 마케팅 카피, 일상 대화, 공식 글쓰기를 처리합니다. 언제 현지화하고 언제 음역할지 압니다.\n\n접근 방식: 번역 전에 타겟 독자와 컨텍스트를 묻습니다. 직역이 의미를 잃을 때 대안을 제공합니다. 문화적 고려 사항을 언급합니다. 일관된 용어를 유지합니다.\n\n경계: 추측하기보다 모호한 원문을 표시합니다. 인증된 번역사가 필요할 수 있는 전문 도메인(법률, 의학)을 처리할 때 고지합니다." + }, + "writer": { + "label": "✍️ 작가", + "prompt": "이름: 퀼. 다재다능한 콘텐츠 작가 — 창의적이고, 명확하며, 독자를 인식합니다.\n성격: 표현력 있고 사려 깊습니다. 어조를 자연스럽게 조정합니다 — 공식 보고서, 캐주얼 블로그, 설득력 있는 카피, 기술 문서. 언어유희를 좋아하지만 명확성을 우선시합니다.\n\n전문성: 블로그 포스트, 기사, 마케팅 카피, 소셜 미디어 콘텐츠, 이메일 캠페인, 문서, 창의적 글쓰기. SEO 기초, 가독성, 콘텐츠 구조를 이해합니다.\n\n접근 방식: 글쓰기 전에 독자, 목적, 어조를 묻습니다. 초안 작성 전에 개요를 작성합니다. 무자비하게 편집합니다 — 모든 단어가 제 역할을 합니다. 방향이 불명확할 때 여러 옵션을 제공합니다.\n\n경계: 표절하거나 오해를 일으키는 콘텐츠를 작성하지 않습니다. 사실 확인이 필요한 주장을 표시합니다. 브랜드 음성 가이드라인을 존중합니다." + } + }, + "card": { + "unnamedAgent": "이름 없는 에이전트", + "summoning": "소환 중...", + "summonFailed": "실패", + "resummon": "재소환", + "delete": "삭제", + "evolving": "진화 중", + "static": "정적", + "evolvingTooltip": "에이전트가 커뮤니케이션 스타일을 자기 진화할 수 있습니다 (SOUL.md). 정체성과 워크플로는 고정됩니다.", + "staticTooltip": "에이전트 스타일이 정적입니다. 스타일 적응을 허용하려면 설정에서 자기 진화를 활성화하세요." + }, + "v3Info": { + "title": "v3의 새로운 기능", + "subtitle": "v2 아키텍처에 비한 주요 개선 사항", + "tabs": { + "core": "핵심 엔진", + "memory": "메모리 & 지식", + "orchestration": "오케스트레이션" + }, + "features": { + "pipeline": { + "title": "파이프라인", + "v2v3": "단일 7K LOC → 8개 플러그 가능 단계", + "desc": "단계별 콜백이 있는 구조화된 컨텍스트 → 기록 → 프롬프트 → 사고 → 행동 → 관찰 → 메모리 → 요약 루프.", + "stat": "8단계" + }, + "memory": { + "title": "메모리", + "v2v3": "단일 계층 → 3계층 (작업 → 에피소딕 → 의미)", + "desc": "작업 메모리는 활성 컨텍스트를 보유하고, 에피소딕은 세션 요약을 저장하고, 의미 계층은 지식 그래프로 지원됩니다.", + "stat": "3계층" + }, + "retrieval": { + "title": "검색", + "v2v3": "수동 검색 → L0/L1/L2 점진적 로딩", + "desc": "L0 추상화는 모든 세션에 자동 주입됩니다. L1/L2는 BM25 + 벡터 하이브리드 검색을 통해 요청 시 로드됩니다.", + "stat": "자동 주입" + }, + "vault": { + "title": "지식 볼트", + "v2v3": "볼트 없음 → 문서 레지스트리 + 위키링크 + 하이브리드 검색", + "desc": "[[위키링크]] 해석, 파일 시스템 동기화, 모든 지식에 걸친 통합 검색이 있는 중앙화된 문서 저장소.", + "stat": "신규" + }, + "evolution": { + "title": "자기 진화", + "v2v3": "메트릭 없음 → 메트릭 → 제안 → 자동 적응", + "desc": "도구 성공률과 검색 품질을 기록하고, 제안을 생성하며, 롤백이 있는 가드레일 보호 변경을 적용합니다.", + "stat": "3단계" + }, + "orchestration": { + "title": "오케스트레이션", + "v2v3": "생성만 → 생성 + 위임 + 팀 모드", + "desc": "위임 도구는 agent_links를 통한 에이전트 간 태스크 핸드오프를 가능하게 합니다. 세 가지 위임 모드: 자동, 명시적, 수동.", + "stat": "3가지 모드" + }, + "resilience": { + "title": "공급자 복원력", + "v2v3": "직접 호출 → 미들웨어 + 폴오버 + 쿨다운", + "desc": "구성 가능한 요청 미들웨어 체인이 속도 제한, 과부하, 인증 오류, 네트워크 실패를 자동 폴오버로 처리합니다.", + "stat": "9가지 오류 유형" + }, + "registry": { + "title": "모델 레지스트리", + "v2v3": "정적 설정 → 동적 레지스트리 + 전방 호환 해석기", + "desc": "ModelRegistry가 공급자 간 모델 별칭을 해석합니다. 전방 호환 해석기가 더 이상 사용되지 않는 ID를 현재 동등 항목에 매핑합니다.", + "stat": "자동 해석" + } + }, + "note": "v3 기능은 에이전트별로 선택 사항입니다. 에이전트 설정에서 활성화하세요." + }, + "delete": { + "title": "에이전트 삭제", + "description": "이 에이전트, 모든 컨텍스트 파일, 세션 및 설정을 영구적으로 삭제합니다. 이 작업은 취소할 수 없습니다.", + "deleteWarning": "에이전트와 세션, 메시지, cron 작업, 하트비트, 메모리, 지식 그래프, 스킬, 채널 설정, 팀, 워크스페이스 파일, 권한을 포함한 모든 관련 데이터가 영구적으로 삭제됩니다. 이 작업은 취소할 수 없습니다.", + "detailDescription": "\"{{name}}\"을 삭제하시겠습니까? 모든 컨텍스트 파일, 세션 및 설정이 영구적으로 삭제됩니다.", + "confirmLabel": "삭제", + "defaultCannotDelete": "기본 에이전트는 삭제할 수 없습니다." + }, + "create": { + "title": "에이전트 만들기", + "emoji": "아이콘", + "emojiHint": "선택적 이모지 아이콘", + "displayName": "표시 이름 *", + "displayNamePlaceholder": "내 에이전트", + "agentKey": "에이전트 키 *", + "agentKeyPlaceholder": "예: my-agent", + "agentKeyHint": "소문자, 숫자, 하이픈", + "provider": "공급자 *", + "selectProvider": "공급자 선택", + "model": "모델 *", + "enterOrSelectModel": "모델 입력 또는 선택", + "loadingModels": "모델 불러오는 중...", + "check": "확인", + "checking": "확인 중...", + "modelVerified": "모델 확인됨", + "verificationFailed": "확인 실패", + "noModelsHint": "이 공급자는 모델 목록을 제공하지 않습니다 — 모델 ID를 직접 입력하세요.", + "agentType": "에이전트 유형", + "open": "개방형", + "openSubLabel": "사용자별 컨텍스트", + "predefined": "사전 정의됨", + "predefinedSubLabel": "에이전트 수준 설정", + "useOpenAgent": "개방형 에이전트 사용 (사용자별 컨텍스트)", + "usePredefined": "사전 정의됨으로 전환", + "switchToPredefined": "전환", + "openWarning": "개방형 에이전트는 사용자당 별도 컨텍스트를 생성합니다. 대부분의 사용 사례는 사전 정의된 에이전트로 더 잘 처리됩니다.", + "describeAgent": "에이전트 설명", + "descriptionPlaceholder": "에이전트의 성격, 목적, 행동 방식을 설명하세요...", + "descriptionHint": "AI가 이 설명에서 에이전트의 컨텍스트 파일을 자동으로 생성합니다. 템플릿으로 시작하려면 비워두세요.", + "selfEvolution": "자기 진화", + "selfEvolutionHint": "에이전트가 SOUL.md를 통해 시간이 지남에 따라 스타일과 어조를 진화시킬 수 있도록 합니다", + "cancel": "취소", + "create": "만들기", + "creating": "생성 중...", + "checkAndCreate": "확인 & 만들기", + "failedToCreate": "에이전트 생성 실패" + }, + "detail": { + "tabs": { + "agent": "에이전트", + "general": "일반", + "config": "설정", + "files": "파일", + "shares": "공유", + "links": "링크", + "skills": "스킬", + "instances": "인스턴스", + "permissions": "권한", + "evolution": "진화" + }, + "summonFailed": "소환 실패", + "evolving": "진화 중", + "static": "정적", + "evolvingTooltipDetail": "에이전트가 커뮤니케이션 스타일을 자기 진화할 수 있습니다 (SOUL.md). 정체성과 워크플로는 고정됩니다.", + "staticTooltipDetail": "에이전트 스타일이 정적입니다. 스타일 적응을 허용하려면 일반 탭에서 자기 진화를 활성화하세요.", + "advanced": "고급", + "personality": "에이전트 성격", + "modelBudget": "모델 & 예산", + "skills": "스킬", + "capabilities": "기능", + "llmSeesAs": "LLM이 보는 것", + "v3": { + "title": "V3 기능", + "pipeline": "V3 파이프라인", + "pipelineHint": "레거시 루프 대신 새 8단계 파이프라인 사용", + "pipelineActiveInfo": "에이전트가 새 v3 파이프라인을 사용하고 있습니다. 비활성화하면 v2 동작으로 되돌아갑니다.", + "memory": "V3 메모리", + "memoryHint": "에피소딕 메모리 및 L0 자동 주입 활성화", + "retrieval": "V3 검색", + "retrievalHint": "새 검색 파이프라인 활성화" + }, + "prompt": { + "title": "시스템 프롬프트 모드", + "mode": { + "full": "전체", + "fullDesc": "모든 섹션 — 대화형 채팅, 페르소나, 전체 기능", + "task": "태스크", + "taskDesc": "엔터프라이즈 자동화 — 메모리, 진화, 페르소나/분위기 없음", + "minimal": "최소", + "minimalDesc": "백그라운드 태스크 — 핵심 규칙, 도메인 컨텍스트, 관찰만", + "none": "없음", + "noneDesc": "순수 도구 호출 자동화 — 도구, 스킬, 규칙이나 페르소나 없음" + }, + "section": { + "persona": "페르소나", + "styleEcho": "스타일 에코", + "tools": "도구", + "execBias": "실행 편향", + "callStyle": "호출 스타일", + "safety": "안전", + "safetySm": "안전 (슬림)", + "skills": "스킬", + "skillsSearch": "스킬 (검색)", + "mcp": "MCP", + "mcpSearch": "MCP (검색)", + "memory": "메모리", + "memorySm": "메모리 (슬림)", + "sandbox": "샌드박스", + "evolution": "진화", + "channelHints": "채널 힌트", + "pinnedSkills": "고정된 스킬", + "skillsHybrid": "스킬 (하이브리드)", + "memoryMin": "메모리 (최소)", + "domainCtx": "도메인 컨텍스트", + "workspace": "워크스페이스", + "toolNotes": "도구 메모" + }, + "upgradeWarning": "모드가 업그레이드되었습니다. 일부 파일은 재생성이 필요할 수 있습니다 — 파일 탭에서 재소환 또는 AI로 편집을 사용하세요." + }, + "engine": { + "title": "엔진 버전", + "learnMore": "더 알아보기", + "pipelineTitle": "파이프라인", + "pipelineHint": "8단계 구조화된 실행 루프", + "memoryTitle": "메모리", + "memoryHint": "에피소딕 메모리 + L0 자동 주입", + "retrievalTitle": "검색", + "retrievalHint": "점진적 L0/L1/L2 지식 로딩" + }, + "orchestration": { + "title": "오케스트레이션", + "mode": "모드", + "delegateTargets": "위임 대상", + "noDelegates": "위임 대상이 설정되지 않았습니다. 에이전트가 자기 복제(생성) 모드를 사용합니다.", + "team": "팀" + }, + "evolution": { + "title": "진화", + "metricsLabel": "진화 메트릭", + "metricsHint": "도구 효과, 검색 품질, 응답 피드백 기록", + "suggestionsLabel": "진화 제안", + "suggestionsHint": "기록된 메트릭에서 데이터 기반 개선 제안 생성", + "toolSuccess": "도구 성공률", + "retrievalQuality": "검색 품질", + "feedback": "피드백", + "noMetrics": "아직 메트릭이 기록되지 않았습니다. 에이전트가 요청을 처리하면 메트릭이 나타납니다.", + "noSuggestions": "아직 제안이 생성되지 않았습니다. 제안은 일별 분석 cron에 의해 생성됩니다.", + "suggestions": "제안", + "guardrails": "적응 가드레일", + "maxDelta": "주기당 최대 델타", + "minDataPoints": "최소 데이터 포인트", + "rollbackDrop": "하락 시 롤백", + "lockedParams": "잠긴 매개변수", + "timeRange": "시간 범위", + "approve": "승인", + "reject": "거부", + "rollback": "롤백", + "confirmApprove": "이 제안을 에이전트에 적용하시겠습니까?", + "confirmReject": "이 제안을 거부하시겠습니까?", + "confirmRollback": "이 적용된 제안을 되돌리시겠습니까?", + "confirmDescription": "이 작업이 제안 상태를 업데이트합니다.", + "notEnabled": "진화 비활성화됨", + "notEnabledHint": "메트릭 기록을 시작하려면 에이전트 탭의 진화 섹션에서 '진화 메트릭'을 활성화하세요.", + "colType": "유형", + "colSuggestion": "제안", + "colStatus": "상태", + "colCreated": "생성됨", + "colActions": "작업", + "cancel": "취소", + "confirm": "확인", + "confirming": "...", + "successRate": "성공률", + "usageRate": "사용률", + "tooltipCalls": "{{count}}회 호출, 평균 {{ms}}ms", + "tooltipQueries": "{{count}}회 쿼리, 점수 {{score}}" + } + }, + "general": { + "selfEvolution": "자기 진화", + "selfEvolutionLabel": "에이전트가 커뮤니케이션 스타일을 진화시킬 수 있도록 허용", + "selfEvolutionHint": "활성화 시 에이전트는 상호작용에 따라 어조, 어휘, 응답 스타일을 개선하기 위해 SOUL.md를 업데이트할 수 있습니다. 정체성, 이름, 운영 지침은 잠긴 상태로 유지됩니다.", + "selfEvolutionInfo": "에이전트는 SOUL.md 업데이트를 통해 시간이 지남에 따라 스타일을 진화시킵니다. 스타일과 어조만 영향을 받습니다 — 정체성과 워크플로 규칙은 고정됩니다.", + "skillLearning": "스킬 학습", + "skillLearningLabel": "에이전트가 경험에서 스킬을 만들고 관리할 수 있도록 허용", + "skillLearningHint": "활성화 시 에이전트는 복잡한 태스크 후 재사용 가능한 워크플로를 스킬로 캡처하도록 안내와 부드러운 알림을 받습니다. skill_manage 도구는 기본적으로 사용 가능합니다.", + "skillLearningInfo": "복잡한 태스크 후 에이전트가 워크플로를 재사용 가능한 스킬로 저장하도록 제안할 수 있습니다. 스킬이 생성되기 전에 사용자 승인이 항상 필요합니다. 스킬은 기본적으로 소유자에게 비공개입니다.", + "skillNudgeIntervalLabel": "N번의 도구 호출 후 알림", + "skillNudgeIntervalHint": "이 횟수만큼 도구를 호출한 후 에이전트가 워크플로를 스킬로 저장하도록 제안합니다. 태스크 후 제안을 비활성화하려면 0으로 설정하세요 (시스템 프롬프트 안내는 여전히 표시됩니다).", + "budget": "월별 예산", + "budgetLabel": "예산 한도 (USD)", + "budgetHint": "선택적 월별 지출 한도입니다. 초과 시 에이전트가 요청을 거부합니다. 무제한으로 하려면 비워두세요.", + "saveChanges": "변경 사항 저장", + "saving": "저장 중...", + "saved": "저장됨", + "failedToSave": "저장 실패" + }, + "chatgptOAuthRouting": { + "title": "Codex OAuth 풀", + "description": "저장된 풀을 편집한 후 실시간으로 확인하세요.", + "defaultAccount": "기본 계정", + "defaultHint": "에이전트 공급자 필드는 기본 별칭에 고정됩니다.", + "badge": "Codex 풀", + "badgeTooltip": "이 에이전트는 여러 OpenAI OAuth 별칭에 걸쳐 Codex 트래픽을 라우팅할 수 있습니다.", + "summaryTitle": "OpenAI 계정 풀", + "summaryDescription": "이 에이전트의 유효한 OpenAI Codex 풀을 확인하세요. 풀 멤버는 공급자에서 관리됩니다. 이 페이지는 라우팅 동작만 제어합니다.", + "strategyLabel": "트래픽 정책", + "strategyHint": "기본 우선은 기본 별칭을 먼저 유지합니다. 라운드 로빈은 모든 준비된 계정에 걸쳐 순환합니다. 우선순위 순서는 기본 별칭 다음으로 나열된 순서대로 계정을 소진합니다.", + "extraAccountsLabel": "추가 계정", + "availableExtraAccountsLabel": "사용 가능한 추가 계정", + "poolMembershipLabel": "풀 멤버십", + "extraHint": "활성화되고 로그인된 OpenAI Codex OAuth 별칭만 참여할 수 있습니다.", + "emptyExtras": "다른 OpenAI Codex OAuth 별칭에 로그인하여 풀링을 활성화하세요.", + "noReadyExtras": "다른 OpenAI Codex OAuth 별칭에 로그인하고 활성화하여 여기에 추가하세요.", + "extraSelectableHint": "활성화되고 로그인된 OpenAI Codex OAuth 별칭만 활성 풀에 들어갈 수 있습니다.", + "selectedAccountsLabel": "풀의 계정", + "emptySelected": "아직 선택된 추가 풀 멤버가 없습니다.", + "manageAction": "풀 열기", + "singleAccountHint": "공급자 페이지에서 다른 명명된 OpenAI Codex OAuth 공급자를 생성하여 공급자 소유 풀을 만드세요.", + "membershipManagedAtProvider": "풀 멤버는 공급자 {{provider}}에서 관리됩니다. 거기서 멤버십을 변경한 후 여기로 돌아와 라우팅 동작을 조정하세요.", + "membershipConfigureProviderFirst": "{{provider}}에 아직 공급자 소유 풀이 저장되지 않았습니다. 이 에이전트는 거기에 풀 멤버가 추가될 때까지 기본 계정에 유지됩니다.", + "readySummary": "{{total}}개 중 {{ready}}개의 추가 계정이 준비되었습니다.", + "preferredNeedsAttention": "기본 계정은 이 에이전트가 안정적으로 사용하기 전에 주의가 필요합니다.", + "loadingAccounts": "OpenAI Codex OAuth 계정 상태 확인 중...", + "attentionTitle": "주의가 필요한 계정", + "attentionHint": "비활성화되거나 로그아웃된 선택된 계정은 재인증하거나 풀에서 제거할 때까지 여기에 표시됩니다.", + "pageTitle": "OpenAI 계정 풀", + "pageDescription": "{{name}}의 실시간 OpenAI Codex 풀을 검토하고, 이 에이전트가 공급자 기본값을 상속할지, 기본 계정만 유지할지, 라우팅 전략을 조정할지 선택하세요.", + "backToAgent": "에이전트로 돌아가기", + "openProviders": "공급자 열기", + "pageUnsupportedTitle": "이 에이전트는 OpenAI Codex OAuth 공급자를 사용하지 않습니다", + "pageUnsupportedDescription": "에이전트 공급자를 OpenAI Codex OAuth 별칭으로 먼저 설정한 후 여기로 돌아와 풀을 관리하세요.", + "providerAccessTitle": "공급자 관리는 관리자만 가능합니다", + "providerAccessDescription": "여기서 실시간 풀을 검사할 수 있지만 관리자만 계정에 로그인하거나 별칭을 추가하거나 공급자 페이지를 열 수 있습니다.", + "providerAccessInline": "관리자만 새 별칭에 로그인하거나 공급자 페이지를 관리할 수 있습니다.", + "unsavedChangesTitle": "초안 변경 사항이 아직 적용되지 않았습니다", + "unsavedChangesDescription": "아래의 확인 카드는 마지막으로 저장된 풀을 반영합니다. 증거를 사용하여 라운드 로빈을 검증하기 전에 이 초안을 저장하세요.", + "draftBadge": "초안 대기 중", + "providerChangedWarning": "공급자가 변경됨 — 저장 시 풀 라우팅이 재설정됩니다.", + "savedPoolOnlyHint": "실시간 증거는 여전히 마지막으로 저장된 풀을 반영합니다.", + "verificationTitle": "확인 방법", + "verificationDescription": "증거는 이 에이전트의 최근 LLM 스팬에서 나옵니다. 몇 가지 요청 후 이 페이지를 새로 고침하여 설정된 풀과 실제 사용된 별칭을 비교하세요.", + "addPoolMembersTitle": "이 풀에 더 많은 별칭 추가", + "addPoolMembersDescription": "공급자 페이지에서 더 많은 OpenAI Codex OAuth 별칭을 만든 후 여기로 돌아와 이 에이전트에 추가하세요.", + "needsAttentionTitle": "주의 필요", + "needsAttentionDescription": "{{count}}개의 풀 별칭이 신뢰하기 전에 비활성화되거나 로그인이 필요합니다.", + "never": "없음", + "requestCount": "최근 {{count}}회 요청", + "lastUsedAt": "{{value}} 마지막 사용", + "openProvider": "공급자 열기", + "activityTitle": "실시간 라우팅", + "activityDescription": "런타임 상태 및 실시간 라우팅 증거.", + "refreshEvidence": "실시간 상태 새로 고침", + "recentRequestsCount": "최근 {{count}}회 요청", + "observedProviders": "{{total}}개 중 {{observed}}개 계정이 직접 사용됨", + "failoverOnlyProviders": "{{count}}개 별칭이 폴오버를 통해서만 확인됨", + "selectedCountLabel": "{{count}}번 직접 사용", + "failoverServeCount": "{{count}}번 폴오버 제공", + "failoverOnlyLabel": "폴오버만", + "switchRate": "{{total}}번의 요청 홉 중 {{switches}}번의 공급자 전환", + "poolMembersTitle": "풀 계정", + "poolMembersDescription": "역할, 경로 상태, 최근 증거, 할당량.", + "sequenceTitle": "최근 요청", + "sequenceColumns": { + "step": "#", + "account": "계정", + "route": "경로", + "when": "시간", + "duration": "소요 시간" + }, + "sequenceDescription": "라우팅된 Codex 호출의 최근 증거.", + "sequenceEmptyTitle": "아직 최근 증거 없음", + "loadingEvidence": "최근 Codex 라우팅 증거 불러오는 중...", + "unknownModel": "알 수 없는 모델", + "attemptCount": "시도 {{count}}번", + "selectedProviderBadge": "{{provider}} 선택됨", + "servedProviderBadge": "{{provider}} 제공됨", + "failoverHint": "재시도 가능한 실패로 인해 다음으로 폴스루: {{providers}}", + "traceAction": "추적", + "openTrace": "추적 열기", + "noEvidence": "몇 가지 Codex 요청을 보낸 후 새로 고침하세요.", + "selectedCount": "풀에 {{count}}개", + "productLabel": "ChatGPT 구독 (OAuth)", + "controlTitle": "풀 설정", + "controlDescription": "풀 멤버는 공급자에서 관리됩니다. 이 페이지는 에이전트가 해당 풀을 상속할지, 기본 계정에 머물지, 라우팅 전략을 재정의할지 제어합니다.", + "mode": { + "label": "에이전트 라우팅 모드", + "inherit": "공급자 기본값 사용", + "custom": "이 에이전트를 위한 커스텀", + "noProviderDefault": "아직 공급자 소유 풀이 저장되지 않았습니다. 공급자 기본값을 따르면 이 에이전트는 지금 기본 계정에 유지되고 나중에 추가된 풀 멤버를 자동으로 선택합니다.", + "providerDefaultSummary": "공급자 기본값에 {{count}}개 계정", + "summaryInherited": "이 에이전트는 현재 공급자 기본 풀을 따릅니다.", + "summaryCustom": "이 에이전트는 현재 공급자 소유 풀에 대한 자체 라우팅 재정의를 저장합니다." + }, + "poolStateTitle": "풀 상태", + "routerActiveTitle": "라우터 활성", + "fallbackTitle": "폴백만", + "blockedNowTitle": "현재 차단됨", + "checkingTitle": "확인 중", + "emptyGroup": "없음", + "viewerMode": "보기 전용", + "consoleSummary": "{{active}}개 활성 · {{observed}}개 직접 사용 · {{blocked}}개 차단", + "monitorDirectLabel": "직접", + "monitorDirectUseLabel": "직접 히트", + "monitorFailoverLabel": "폴오버", + "lastSeenLabel": "마지막 확인", + "sampleBadge": "{{count}}개 추적 스팬", + "noSampleBadge": "최근 샘플 없음", + "runtimeHealthTitle": "런타임 상태", + "runtimeHealthSummary": "{{rate}}% 성공 · 점수 {{score}}", + "noRuntimeSample": "아직 최근 런타임 샘플 없음.", + "failureStreakBadge": "현재 {{count}}개 실패 중", + "runtimeSuccessCompact": "성공 {{count}}", + "runtimeFailureCompact": "실패 {{count}}", + "lastSuccessLabel": "마지막 성공 {{value}}", + "lastFailureLabel": "마지막 실패 {{value}}", + "healthState": { + "healthy": "정상", + "degraded": "저하됨", + "critical": "심각", + "idle": "유휴" + }, + "checkpoints": { + "configured": "설정됨", + "ready": "준비됨", + "observed": "직접 사용됨", + "switching": "전환 중" + }, + "nextActionTitle": "다음 조치", + "nextAction": { + "saveTitle": "증거를 신뢰하기 전에 초안 저장", + "saveDescription": "저장된 풀과 초안이 달라졌습니다. 현재 설정을 먼저 유지한 후 실시간 트래픽을 검증하세요.", + "attentionTitle": "주의가 필요한 별칭 수정", + "attentionDescription": "비활성화되거나 로그아웃된 별칭은 재인증하거나 풀에서 제거할 때까지 표시됩니다.", + "quotaTitle": "라운드 로빈을 신뢰하기 전에 할당량 차단 요소 수정", + "quotaDescription": "{{count}}개의 로그인된 별칭이 현재 사용 가능한 할당량을 표시하지 않습니다.", + "failoverOnlyTitle": "폴오버 후에만 나타나는 별칭 검사", + "failoverOnlyDescription": "{{count}}개의 별칭이 직접 라운드 로빈 선택이 아닌 폴오버 대상으로만 최근 트래픽을 가집니다.", + "addMembersTitle": "실제 풀링을 활성화하려면 다른 로그인된 별칭 추가", + "addMembersDescription": "한 개 이상의 준비된 별칭이 참여할 수 있으면 라운드 로빈이 의미 있어집니다.", + "verifyTitle": "더 많은 Codex 요청을 보내고 증거 새로 고침", + "verifyDescription": "풀이 저장되고 준비되었지만 최근 라우팅된 호출이 아직 준비된 모든 별칭에 걸쳐 직접 선택을 보여주지 않았습니다.", + "healthyTitle": "현재 운영자 조치 불필요", + "healthyDescription": "최근 라우팅된 호출이 저장된 풀의 모든 준비된 별칭을 직접 선택하고 있습니다.", + "manualTitle": "순서 라우팅 활성", + "manualDescription": "이 에이전트는 모든 요청을 순환하지 않습니다. 라운드 로빈이 활성화될 때까지 기본 별칭의 반복 사용이 예상됩니다." + }, + "howItWorksTitle": "이 풀의 작동 방식", + "howItWorks": { + "primary": "에이전트 공급자 필드는 기본 별칭에 고정됩니다.", + "roundRobin": "라운드 로빈은 활성 풀의 모든 준비된 별칭에 걸쳐 순환합니다.", + "failover": "재시도 가능한 업스트림 실패는 동일한 요청의 다음 적격 별칭으로 폴스루할 수 있습니다." + }, + "quota": { + "checking": "할당량 확인 중", + "checkingDescription": "GoClaw가 이 별칭의 최신 할당량 상태를 가져오는 중입니다.", + "healthySummary": "{{usable}}개의 {{total}}개 할당량 준비됨", + "needsAttention": "{{count}}개 별칭에 할당량 주의 필요", + "blockersNow": "지금 차단 중", + "floorFiveHour": "5시간 하한 {{value}}%", + "floorWeekly": "주간 하한 {{value}}%", + "plan": "플랜", + "lastChecked": "{{value}} 확인됨", + "readyLabel": "할당량 준비됨", + "readyDescription": "이 별칭은 현재 사용 가능한 할당량 창을 표시합니다.", + "readinessTitle": "할당량 준비 상태", + "readinessDescription": "여기서 먼저 확인하세요. 로그인된 별칭 중 사용 가능한 할당량이 있는 것만 실시간 트래픽에 신뢰해야 합니다.", + "requiresReadyAlias": "GoClaw가 할당량을 확인하려면 이 별칭이 로그인되어야 합니다.", + "failure": { + "billing": { + "label": "청구", + "description": "현재 워크스페이스 청구 또는 자격 문제로 계정이 차단되었습니다." + }, + "exhausted": { + "label": "소진됨", + "description": "이 계정은 로그인되어 있지만 핵심 할당량 창 중 하나가 소진되었습니다." + }, + "reauth": { + "label": "재인증", + "description": "워크스페이스 접근을 새로 고치려면 다시 로그인하세요." + }, + "forbidden": { + "label": "금지됨", + "description": "이 계정은 업스트림 할당량 데이터를 읽을 수 없습니다." + }, + "needs_setup": { + "label": "설정 필요", + "description": "GoClaw가 ChatGPT 계정 워크스페이스 메타데이터를 복원할 수 있도록 다시 로그인하세요." + }, + "retry_later": { + "label": "나중에 재시도", + "description": "할당량 엔드포인트가 일시적으로 사용 불가하거나 속도가 제한되어 있습니다." + }, + "unavailable": { + "label": "사용 불가", + "description": "현재 이 계정의 할당량 데이터를 사용할 수 없습니다." + } + } + }, + "metrics": { + "poolHealth": "풀 상태", + "policy": "트래픽 정책", + "poolSize": "풀 크기", + "observedSample": "관찰된 샘플", + "routerActiveAccounts": "라우터 활성", + "blockedAccounts": "차단됨", + "readyAccounts": "로그인된 계정", + "quotaReadyAccounts": "할당량 준비됨", + "observedRotation": "직접 사용됨", + "healthy": "정상", + "needsAttention": "주의 필요", + "readyOfTotal": "{{total}}개 중 {{ready}}개 별칭 준비됨", + "failovers": "폴오버", + "noFailovers": "폴오버 없음" + }, + "verdict": { + "healthy": { + "title": "라운드 로빈이 정상입니다", + "description": "{{count}}개의 추적 스팬에 걸쳐 {{observed}}개의 준비된 계정이 순환하는 것이 관찰되었습니다." + }, + "warning": { + "title": "라운드 로빈이 설정되었지만 아직 확인되지 않았습니다", + "description": "지금까지 {{count}}개의 추적 스팬 중 {{observed}}개의 준비된 계정만 직접 라우팅 증거를 가지고 있습니다." + }, + "manual": { + "title": "순서 라우팅 활성", + "description": "이 에이전트는 모든 요청을 순환하지 않습니다. 라운드 로빈이 활성화될 때까지 기본 별칭의 반복 사용이 예상됩니다." + } + }, + "role": { + "preferred": "기본", + "extra": "추가" + }, + "status": { + "ready": "준비됨", + "needs_sign_in": "로그인 필요", + "disabled": "비활성화됨" + }, + "strategy": { + "manual": "기본 우선", + "primaryFirst": "기본 우선", + "roundRobin": "라운드 로빈", + "priorityOrder": "우선순위 순서" + } + }, + "identity": { + "title": "식별", + "agentKey": "에이전트 키", + "agentKeyHint": "고유 식별자, 변경 불가.", + "displayName": "표시 이름", + "displayNamePlaceholder": "예: 내 어시스턴트", + "displayNameHint": "UI에 표시되는 친화적 이름입니다. 에이전트 키를 사용하려면 비워두세요.", + "expertiseSummary": "전문성 요약", + "expertiseSummaryPlaceholder": "예: 점성술, 타로, 사주팔자, 수비학", + "expertiseSummaryHint": "이 에이전트의 전문성에 대한 짧은 설명입니다. 위임 발견에 사용됩니다.", + "status": "상태", + "active": "활성", + "inactive": "비활성", + "summonFailed": "소환 실패", + "defaultAgent": "기본 에이전트", + "emoji": "아이콘", + "emojiHint": "선택적 이모지 아이콘" + }, + "llmConfig": { + "title": "LLM 설정", + "contextWindow": "컨텍스트 창", + "contextWindowHint": "모델 컨텍스트의 토큰 한도.", + "maxToolIterations": "최대 도구 반복", + "maxToolIterationsHint": "요청당 최대 도구 호출 수." + }, + "workspace": { + "title": "워크스페이스", + "workspacePath": "워크스페이스 경로", + "workspacePathHint": "에이전트 생성 시 자동으로 할당됩니다. 사용자별 하위 디렉터리는 런타임에 생성됩니다.", + "noWorkspace": "워크스페이스 설정 없음", + "restrictToWorkspace": "워크스페이스로 제한", + "restrictToWorkspaceHint": "파일 접근을 워크스페이스 경로 내로 엄격히 제한합니다." + }, + "config": { + "saveConfig": "설정 저장", + "saving": "저장 중...", + "saved": "저장됨", + "failedToSave": "저장 실패", + "usingGlobalDefaults": "config.json의 전역 기본값 사용" + }, + "files": { + "readOnly": "읽기 전용", + "readOnlyDesc": "에이전트 소유자만 사전 정의된 컨텍스트 파일을 편집할 수 있습니다.", + "resummon": "재소환", + "editWithAi": "AI로 편집", + "resummonTitle": "에이전트 재소환", + "resummonDesc": "원래 설명을 사용하여 SOUL.md, IDENTITY.md, 선택적으로 USER_PREDEFINED.md를 처음부터 재생성합니다. 이 파일에 대한 수동 편집은 덮어씁니다.", + "cancel": "취소", + "resummonConfirm": "재소환", + "summoning": "소환 중...", + "selectFileToEdit": "편집할 파일 선택", + "selectFileToView": "볼 파일 선택", + "saving": "저장 중...", + "save": "저장", + "loading": "불러오는 중...", + "openAgentTitle": "개방형 에이전트 - 사용자별 컨텍스트 파일", + "openAgentDesc1": "이것은 개방형 에이전트입니다. 컨텍스트 파일(AGENTS.md, SOUL.md, TOOLS.md 등)은 각 사용자에게 맞게 개인화됩니다. 사용자가 이 에이전트와 처음 채팅할 때 템플릿에서 자동으로 생성됩니다.", + "openAgentDesc2pre": "여기 표시된 에이전트 수준 파일은 비어 있습니다. 개방형 에이전트는 모든 컨텍스트를 ", + "openAgentDesc2post": " 테이블의 사용자별로 저장하기 때문입니다.", + "contextFiles": "컨텍스트 파일", + "contextFile": "컨텍스트 파일", + "perUser": "사용자별", + "emptyFile": "비어 있음", + "estTokens": "약 {{tokens}} 토큰", + "insertContact": "삽입할 연락처 검색...", + "contentPlaceholder": "파일 내용...", + "systemPromptPreview": "시스템 프롬프트", + "tokens": "토큰" + }, + "fileEditor": { + "editWithAi": "AI로 편집", + "editAiDescription": "변경하고 싶은 것을 설명하세요. AI가 현재 파일을 읽고 그에 따라 업데이트합니다.", + "editAiPlaceholder": "예: 에이전트를 더 공식적으로 만들기, 한국어 지원 추가, 이름을 루나로 변경...", + "sending": "전송 중...", + "regenerate": "재생성", + "regenerating": "AI가 파일을 다시 작성 중...", + "regenerateCompleted": "파일 업데이트됨!", + "regenerateFailed": "재생성 실패", + "retry": "재시도", + "cancel": "취소" + }, + "shares": { + "grantAccess": "접근 권한 부여", + "userId": "사용자 ID", + "userIdPlaceholder": "연락처 검색 또는 사용자 ID 입력...", + "role": "역할", + "share": "공유", + "loadingShares": "공유 불러오는 중...", + "noShares": "아직 공유 없음", + "noSharesDesc": "위에서 사용자 ID를 입력하여 다른 사용자와 이 에이전트를 공유하세요.", + "user": "사용자", + "revokeTitle": "공유 취소", + "revokeDesc": "사용자 \"{{userId}}\"의 접근 권한을 취소하시겠습니까? 이 에이전트를 더 이상 사용할 수 없게 됩니다.", + "revoke": "취소", + "role.user": "사용자", + "role.viewer": "뷰어", + "roleDesc.user": "에이전트를 사용하고 채팅 가능", + "roleDesc.viewer": "읽기 전용 접근" + }, + "links": { + "teamsHint": "에이전트 링크는 곧 제거될 예정입니다. 멀티 에이전트 협업에는 에이전트 팀을 사용하세요 — 더 간단한 설정으로 태스크 추적, 공유 워크스페이스, 품질 관리를 제공합니다.", + "createLink": "링크 만들기", + "targetAgent": "대상 에이전트", + "selectAgent": "에이전트 선택 또는 검색...", + "direction": "방향", + "description": "설명", + "descriptionPlaceholder": "링크에 대한 선택적 설명...", + "maxConcurrent": "최대 동시", + "advancedSettings": "고급 설정", + "allowedUsers": "허용된 사용자", + "allowedUsersPlaceholder": "user1, user2, ...", + "allowedUsersHint": "설정된 경우 이 사용자만 이 위임을 트리거할 수 있습니다. 쉼표로 구분.", + "deniedUsers": "차단된 사용자", + "deniedUsersPlaceholder": "user3, user4, ...", + "deniedUsersHint": "이 사용자들은 이 위임을 트리거하는 것이 차단됩니다. 쉼표로 구분.", + "creating": "생성 중...", + "noLinks": "아직 에이전트 링크 없음", + "noLinksDesc": "에이전트가 서로 태스크를 위임할 수 있도록 링크를 만드세요.", + "loadingLinks": "링크 불러오는 중...", + "columns": { + "target": "대상", + "direction": "방향", + "status": "상태", + "limit": "제한" + }, + "deleteTitle": "링크 삭제", + "deleteDesc": "\"{{name}}\"에 대한 위임 링크를 제거하시겠습니까? 에이전트들은 더 이상 이 링크를 통해 서로 위임할 수 없게 됩니다.", + "editTitle": "링크 편집", + "editDescription": "위임 링크 설정 업데이트.", + "optionalDescription": "선택적 설명...", + "allowedUsersHintShort": "설정된 경우 이 사용자만 이 위임을 트리거할 수 있습니다.", + "deniedUsersHintShort": "이 사용자들은 이 위임을 트리거하는 것이 차단됩니다." + }, + "skills": { + "noSkillsAvailable": "사용 가능한 스킬 없음", + "noSkillsDesc": "스킬 페이지에서 스킬을 업로드하여 에이전트에게 부여하세요.", + "skillsGranted": "{{total}}개 중 {{granted}}개 스킬 부여됨", + "filterSkills": "스킬 필터링...", + "noSkillsMatch": "검색에 일치하는 스킬이 없습니다.", + "system": "시스템", + "alwaysAvailable": "항상 사용 가능" + }, + "instances": { + "loadingInstances": "인스턴스 불러오는 중...", + "noInstances": "아직 사용자 인스턴스 없음.", + "noInstancesDesc": "인스턴스는 사용자가 이 에이전트와 상호작용할 때 생성됩니다.", + "instanceCount": "{{count}}개 인스턴스", + "instanceCount_plural": "{{count}}개 인스턴스", + "selectInstance": "인스턴스를 선택하여 USER.md 보기 및 편집", + "loading": "불러오는 중...", + "saving": "저장 중...", + "save": "저장", + "saved": "저장됨", + "searchContacts": "추가할 연락처 검색...", + "noContactsFound": "연락처를 찾을 수 없음" + }, + "summoning": { + "title": "에이전트를 소환하는 중...", + "completed": "소환 완료!", + "failed": "소환 실패", + "agentReady": "{{name}}이 준비되었습니다!", + "weavingSoul": "영혼을 짜는 중", + "wait": "보통 몇 분 정도 걸립니다. 기다려 주세요...", + "continue": "계속", + "retry": "재시도", + "retrying": "재시도 중...", + "done": "완료", + "fileLabelSOUL": "영혼 & 성격", + "fileLabelIDENTITY": "신원 카드" + }, + "configGroups": { + "core": "핵심", + "coreDesc": "에이전트 동작에 직접 영향을 미치는 필수 설정", + "capabilities": "기능", + "capabilitiesDesc": "에이전트가 사용할 수 있는 기능", + "performance": "성능", + "performanceDesc": "컨텍스트 관리 및 실행 환경", + "advanced": "품질 & 고급", + "advancedDesc": "품질 보증 및 커스텀 설정" + }, + "configSections": { + "subagents": { + "title": "서브에이전트", + "description": "서브에이전트 생성 제한 및 동작 제어", + "maxConcurrent": "최대 동시", + "maxSpawnDepth": "최대 생성 깊이", + "maxChildrenPerAgent": "에이전트당 최대 자식", + "archiveAfter": "보관 시간 (분)", + "modelOverride": "모델 재정의", + "inheritFromAgent": "(에이전트에서 상속)" + }, + "toolPolicy": { + "title": "도구 정책", + "description": "이 에이전트가 사용할 수 있는 도구 제어", + "profile": "프로파일", + "allow": "허용", + "deny": "차단", + "alsoAllow": "추가 허용", + "selectToolsAllow": "허용할 도구 선택...", + "selectToolsDeny": "차단할 도구 선택...", + "selectToolsAlsoAllow": "추가 도구 선택...", + "toolCallPrefix": "도구 호출 접두사", + "toolCallPrefixHint": "레지스트리 조회 전에 모델의 도구 호출 이름에서 이 접두사를 제거합니다." + }, + "workspaceSharing": { + "title": "워크스페이스 공유", + "description": "사용자 간 워크스페이스 파일 격리 제어", + "sharedDm": "DM에서 공유", + "sharedDmTip": "모든 DM 사용자가 격리된 사용자별 폴더 대신 동일한 워크스페이스 디렉터리를 공유합니다", + "sharedGroup": "그룹에서 공유", + "sharedGroupTip": "그룹 채팅의 모든 멤버가 동일한 워크스페이스 디렉터리를 공유합니다", + "sharedUsers": "공유 사용자", + "sharedUsersTip": "DM/그룹 설정에 관계없이 항상 워크스페이스를 공유하는 특정 사용자 ID입니다. 형식: channel:userId (예: telegram:386246614)", + "userIdPlaceholder": "사용자 ID 입력 (예: telegram:386246614)", + "warning": "공유가 활성화되면 모든 공유 사용자가 동일한 워크스페이스 디렉터리의 파일을 읽고 쓸 수 있습니다. 메모리 공유는 별도로 제어됩니다. 컨텍스트 파일은 사용자별로 격리됩니다.", + "memoryGroupLabel": "메모리 & 지식 그래프", + "memoryGroupDescription": "사용자 간 메모리 및 지식 그래프 격리 제어", + "folderGroupLabel": "워크스페이스 폴더", + "shareMemory": "메모리 공유", + "shareMemoryTip": "모든 사용자가 동일한 메모리 저장소에 접근합니다. 비활성화 시 각 사용자는 고유한 격리된 메모리 공간을 가집니다. KG 공유는 아래에서 별도로 제어됩니다.", + "shareMemoryNote": "이것을 토글해도 데이터가 마이그레이션되지 않습니다 — 기존 사용자별 메모리는 공유 모드에서 접근 불가능해집니다.", + "shareKG": "지식 그래프 공유", + "shareKGTip": "모든 사용자가 동일한 지식 그래프에 접근합니다. 비활성화 시 각 사용자는 읽기 작업을 위한 전역 정규 폴백이 있는 고유한 격리된 KG를 가집니다.", + "shareKGNote": "이것을 토글해도 데이터가 마이그레이션되지 않습니다 — 기존 사용자별 KG 엔티티는 공유 모드에서 접근 불가능해집니다." + }, + "compaction": { + "title": "압축", + "description": "컨텍스트 창 압축 및 메모리 플러시 설정", + "maxHistoryShare": "최대 기록 비율 (0-1)", + "maxHistoryShareTip": "대화 기록을 위한 컨텍스트 창의 최대 비율 (예: 0.85 = 85%). 초과 시 압축이 트리거됩니다.", + "keepLastMessages": "마지막 메시지 유지", + "keepLastMessagesTip": "압축 후 유지되는 최근 메시지입니다. 오래된 메시지는 요약으로 대체됩니다.", + "memoryFlush": "메모리 플러시", + "memoryFlushTip": "압축 전에 에이전트가 중요한 컨텍스트를 메모리 파일에 저장할 기회를 얻습니다. 지식 그래프 추출도 트리거합니다." + }, + "contextPruning": { + "title": "컨텍스트 정리", + "description": "컨텍스트 창 절약을 위해 오래된 도구 결과 제거", + "descriptionSimple": "컨텍스트 오버플로를 방지하기 위해 오래된 도구 결과를 자동으로 제거합니다. 기본적으로 활성화됩니다.", + "mode": "모드", + "keepLastAssistants": "마지막 어시스턴트 유지", + "softTrimRatio": "소프트 트림 비율 (0-1)", + "hardClearRatio": "하드 클리어 비율 (0-1)", + "minPrunableToolChars": "최소 정리 가능 도구 문자", + "softTrim": "소프트 트림", + "maxChars": "최대 문자", + "headChars": "헤드 문자", + "tailChars": "테일 문자", + "hardClear": "하드 클리어", + "enabled": "활성화됨", + "placeholderText": "자리표시자 텍스트", + "advanced": "고급" + }, + "sandbox": { + "title": "샌드박스", + "description": "코드 실행 격리를 위한 Docker 샌드박스", + "mode": "모드", + "workspaceAccess": "워크스페이스 접근", + "image": "이미지", + "scope": "범위", + "timeout": "타임아웃 (초)", + "memoryMb": "메모리 (MB)", + "cpus": "CPU", + "networkEnabled": "네트워크 활성화됨" + }, + "memory": { + "title": "메모리", + "description": "의미 메모리 검색 및 임베딩 설정", + "enabled": "활성화됨", + "enabledTip": "이 에이전트의 메모리 시스템을 활성화하거나 비활성화합니다.", + "maxChunkLen": "최대 청크 길이", + "maxChunkLenTip": "메모리 청크당 최대 문자 수입니다. 시스템 기본값을 사용하려면 비워두세요.", + "chunkOverlap": "청크 겹침", + "chunkOverlapTip": "컨텍스트 연속성을 위한 청크 간 겹침 문자 수입니다. 시스템 기본값을 사용하려면 비워두세요.", + "maxResults": "최대 결과", + "maxResultsTip": "검색 쿼리당 반환되는 최대 메모리 항목 수입니다.", + "minScore": "최소 점수", + "minScoreTip": "검색 결과의 최소 관련성 점수입니다.", + "vectorWeight": "벡터 가중치", + "vectorWeightTip": "하이브리드 검색에서 의미 유사성의 가중치입니다.", + "textWeight": "텍스트 가중치", + "textWeightTip": "하이브리드 검색에서 키워드 유사성의 가중치입니다." + }, + "dreaming": { + "title": "드리밍 (메모리 통합)", + "description": "세션 요약을 장기 메모리로 승격시키는 백그라운드 작업자입니다. 에이전트가 너무 수다스럽거나 자주 통합되지 않을 때 조정하세요.", + "enabled": "활성화됨", + "enabledTip": "장기 통합 없이 원시 세션 요약만 의존하게 하려면 비활성화하세요.", + "threshold": "임계값", + "thresholdTip": "통합 실행이 시작되기 전 최소 미승격 요약 수. 기본값 5.", + "debounceMs": "디바운스 (ms)", + "debounceMsTip": "에이전트/사용자당 실행 간 최소 간격입니다. 기본값 600000 (10분).", + "verboseLog": "상세 로깅", + "verboseLogTip": "운영자 디버깅을 위해 info 수준에서 디바운스 및 임계값 미달 건너뜀을 출력합니다." + }, + "thinking": { + "title": "확장 사고", + "description": "모델이 응답하기 전에 추론할 수 있도록 합니다. 높은 수준은 더 많은 토큰을 사용하지만 복잡한 태스크에서 더 나은 결과를 생성합니다.", + "modeLabel": "추론 모드", + "inherit": "공급자 기본값 사용", + "custom": "이 에이전트를 위한 커스텀", + "customDesc": "이 에이전트에 대해서만 공급자 소유 기본 추론 정책을 재정의합니다.", + "providerDefaultSummary": "{{provider}}에서 상속됨", + "providerLabelFallback": "공급자 기본값", + "noProviderDefault": "아직 공급자 소유 추론 기본값이 저장되지 않았습니다. 상속 모드는 공급자가 기본값을 저장할 때까지 이 에이전트를 추론 꺼짐 상태로 유지합니다.", + "thinkingLevel": "사고 수준", + "thinkingLevelTip": "일반적인 경우를 위한 간단한 프리셋입니다. 모델별 노력 제어나 명시적 폴백 동작이 필요할 때 전문가 모드를 사용하세요.", + "expertMode": "전문가 모드", + "expertModeDesc": "없음, 최소, 자동, xhigh와 같은 모델별 추론 수준을 요청하고 선택된 모델이 지원하지 않을 때 발생하는 일을 제어합니다.", + "supportedLevelsForModel": "선택된 모델 {{model}}은 이러한 명시적 추론 수준을 지원합니다.", + "loadingSupport": "{{model}}에 대한 추론 기능 메타데이터를 불러오는 중.", + "unknownSupport": "GoClaw에는 아직 {{model}}에 대한 명시적 추론 메타데이터가 없습니다.", + "expertModeUnavailable": "고급 추론 제어는 선택된 모델이 공급자 모델 엔드포인트의 명시적 기능 메타데이터를 가진 경우에만 사용 가능합니다.", + "modelDefault": "모델 기본 추론: {{level}}", + "requestedEffort": "요청된 노력", + "requestedEffortTip": "GoClaw가 선택된 모델에 대해 정규화하기 전 요청된 추론 수준입니다.", + "fallbackBehavior": "폴백 동작", + "fallbackBehaviorTip": "요청된 노력이 선택된 모델에서 지원되지 않을 때 GoClaw가 수행해야 할 작업입니다.", + "supportedOption": "이 모델에서 지원됨", + "legacyShim": "GoClaw는 이전 빌드와의 하위 호환성을 위해 거친 thinking_level 심도 저장합니다.", + "off": "끄기", + "offDesc": "확장 사고 없음", + "auto": "자동", + "autoDesc": "모델 기본 추론 노력 사용", + "none": "없음", + "noneDesc": "고급 계약을 유지하면서 공급자 추론을 명시적으로 비활성화", + "minimal": "최소", + "minimalDesc": "없음 이상에서 가장 작은 지원 추론 노력 사용", + "low": "낮음", + "lowDesc": "~4K 토큰 예산", + "medium": "중간", + "mediumDesc": "~10-16K 토큰 예산", + "high": "높음", + "highDesc": "~32K 토큰 예산", + "xhigh": "최대", + "xhighDesc": "지원되는 최대 추론 노력 사용", + "downgrade": "다운그레이드", + "downgradeDesc": "가장 가까운 지원 낮은 수준으로 정규화하거나, 필요 시 가장 낮은 지원 수준으로", + "provider_default": "모델 기본값 사용", + "provider_defaultDesc": "명시적 노력을 강제하지 않고 공급자/모델이 기본값을 선택하도록 함" + }, + "otherConfig": { + "title": "기타 설정", + "description": "다른 섹션에서 다루지 않는 고급 설정을 위한 추가 JSON 설정", + "formatJson": "JSON 포맷", + "invalidJson": "잘못된 JSON 구문" + } + }, + "heartbeat": { + "title": "하트비트", + "loading": "하트비트 불러오는 중...", + "notConfigured": "하트비트 일정이 설정되지 않았습니다. 에이전트를 자동 조종으로 실행하려면 설정하세요.", + "setupButton": "하트비트 설정", + "toggleEnabled": "하트비트 활성화 토글", + "every": "매 {{interval}}분", + "lastRun": "마지막", + "nextRun": "다음", + "runs": "실행", + "suppressed": "억제됨", + "configure": "설정", + "logs": "로그", + "configTitle": "하트비트 설정", + "enabled": "활성화됨", + "enabledHint": "활성화 시 에이전트가 설정된 간격으로 실행됩니다.", + "sectionTiming": "타이밍", + "interval": "간격 (초)", + "intervalHint": "최소 300초 (5분).", + "maxRetries": "최대 재시도", + "maxRetriesHint": "0-10회 실패 시 재시도.", + "ackMaxChars": "확인 최대 문자", + "ackMaxCharsHint": "확인 응답의 최대 문자 수. 0 = 응답 없음.", + "sectionBehavior": "동작", + "isolatedSession": "격리된 세션", + "isolatedSessionHint": "마지막 대화를 계속하지 않고 새 세션에서 실행합니다.", + "lightContext": "가벼운 컨텍스트", + "lightContextHint": "토큰 사용량을 줄이기 위해 전체 컨텍스트 파일 로딩을 건너뜁니다.", + "sectionSchedule": "일정", + "activeHoursStart": "활성 시작 (HH:MM)", + "activeHoursEnd": "활성 종료 (HH:MM)", + "timezone": "시간대", + "sectionModel": "모델", + "modelHint": "하트비트 실행을 위한 공급자/모델을 재정의합니다. 에이전트 기본값을 사용하려면 비워두세요.", + "sectionDelivery": "전달", + "channel": "채널", + "channelPlaceholder": "채널 선택", + "channelNone": "없음 (전달 없음)", + "channelHint": "예: telegram, feishu. 전달 없이는 비워두세요.", + "chatId": "채팅 ID", + "chatIdPlaceholder": "채팅 선택", + "selectChannelFirst": "먼저 채널을 선택하세요", + "checklist": "체크리스트 (HEARTBEAT.md)", + "checklistHint": "각 하트비트 실행에 주입되는 지침입니다. 마크다운을 지원합니다.", + "checklistLoading": "체크리스트 불러오는 중...", + "checklistPlaceholder": "# 하트비트 체크리스트\n\n- 대기 중인 태스크 확인\n- 상태 보고\n", + "on": "켜기", + "off": "끄기", + "notSet": "설정되지 않음", + "disabled": "하트비트 비활성화됨", + "nextIn": "{{time}} 후 다음", + "advancedSettings": "고급 설정", + "scheduleHint": "24/7 운영하려면 비워두세요.", + "testRun": "테스트 실행", + "cancel": "취소", + "save": "저장", + "saving": "저장 중...", + "logsTitle": "하트비트 로그", + "refresh": "새로 고침", + "noLogs": "아직 하트비트 로그 없음.", + "logsPagination": "{{total}}개 중 {{from}}–{{to}}" + }, + "permissions": { + "title": "권한", + "description": "에이전트 설정과 파일을 수정할 수 있는 사람을 제어합니다. 소유자는 항상 전체 접근 권한을 가집니다.", + "addRule": "규칙 추가", + "fileWriters": "파일 작성자", + "configPerms": "설정 권한", + "noRules": "권한 규칙 없음. 소유자가 암묵적 전체 접근 권한을 가집니다.", + "userIdPlaceholder": "연락처 검색 또는 ID 입력...", + "scopePlaceholder": "범위 선택 또는 입력...", + "types": { + "file_writer": "파일 작성자", + "file_writer_desc": "그룹 채팅에서 파일 편집 및 cron 관리 권한을 제어합니다. 첫 번째 사용자가 자동으로 추가됩니다.", + "heartbeat": "하트비트", + "heartbeat_desc": "채팅을 통해 하트비트 일정과 설정을 구성할 수 있는 사람을 제어합니다.", + "cron": "Cron", + "cron_desc": "채팅을 통해 예약된 cron 작업을 만들고 관리할 수 있는 사람을 제어합니다.", + "context_files": "컨텍스트 파일", + "context_files_desc": "채팅을 통해 에이전트 식별 파일(SOUL.md 등)을 수정할 수 있는 사람을 제어합니다.", + "all": "전체 (*)", + "all_desc": "모든 설정 유형에 대한 전체 접근." + }, + "scopes": { + "agent": "에이전트 (DM만)", + "group_all": "모든 그룹", + "global": "전역 (모든 컨텍스트)" + } + }, + "transfer": { + "title": "에이전트 이전", + "description": "에이전트를 아카이브 파일로 내보내거나 기존 아카이브에서 가져옵니다.", + "tabExport": "내보내기", + "tabImport": "가져오기", + "selectAgent": "에이전트 선택", + "selectAgentPlaceholder": "에이전트 선택...", + "presets": "프리셋", + "preset": { + "minimal": "최소", + "standard": "표준", + "complete": "전체" + }, + "sections": { + "config": "에이전트 설정", + "contextFiles": "컨텍스트 파일", + "userData": "사용자 데이터", + "userContextFiles": "사용자 컨텍스트 파일", + "userProfiles": "사용자 프로필", + "userOverrides": "사용자 재정의", + "memory": "메모리", + "memoryGlobal": "전역", + "memoryPerUser": "사용자별", + "knowledgeGraph": "지식 그래프", + "skills": "스킬", + "mcp": "MCP 권한", + "customTools": "커스텀 도구", + "cron": "Cron 작업", + "permissions": "권한", + "sessions": "세션", + "workspace": "워크스페이스 파일", + "team": "팀", + "media": "미디어 파일" + }, + "hints": { + "sessions": "매우 클 수 있음", + "media": "매우 클 수 있음", + "team": "팀 메타데이터, 멤버, 태스크, 링크", + "mergeOverwrite": "동일한 이름의 기존 파일이 덮어써집니다", + "mergeUpsert": "경로로 문서 업서트됨", + "mergeKgUpsert": "external_id로 엔티티 업서트됨", + "mergeFiles": "새 파일 추가, 기존 파일 덮어씀" + }, + "exportButton": "에이전트 내보내기", + "exporting": "\"{{name}}\" 내보내는 중...", + "exportComplete": "내보내기 완료", + "exportFailed": "내보내기 실패", + "exportAnother": "다른 것 내보내기", + "download": "다운로드", + "importing": "가져오는 중...", + "importComplete": "가져오기 완료", + "importFailed": "가져오기 실패", + "importAnother": "다른 것 가져오기", + "viewAgent": "에이전트 보기", + "tryAgain": "다시 시도", + "cancel": "취소", + "dontClose": "이 페이지를 닫지 마세요 — 가져오기 진행 중", + "rolledBack": "모든 변경 사항이 롤백되었습니다. 시스템이 이전 상태입니다.", + "dropHere": ".tar.gz 파일을 여기에 놓거나 클릭하여 찾아보기", + "supportedFormats": "지원: .tar.gz, .agent.json (레거시)", + "invalidFile": "잘못된 파일 — 아카이브를 파싱할 수 없음", + "importMode": "가져오기 모드", + "modeNew": "새 에이전트 만들기", + "modeMerge": "기존 에이전트에 병합", + "targetAgent": "대상 에이전트", + "changeFile": "파일 변경", + "startImport": "가져오기 시작" + }, + "toast": { + "created": "에이전트 생성됨", + "createFailed": "에이전트 생성 실패", + "updated": "에이전트 업데이트됨", + "updateFailed": "에이전트 업데이트 실패", + "deleted": "에이전트 삭제됨", + "deleteFailed": "에이전트 삭제 실패", + "unknownError": "알 수 없는 오류", + "skillGranted": "스킬 부여됨", + "skillGrantFailed": "스킬 부여 실패", + "skillRevoked": "스킬 취소됨", + "skillRevokeFailed": "스킬 취소 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/api-keys.json b/ui/web/src/i18n/locales/ko/api-keys.json new file mode 100644 index 00000000..17de2641 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/api-keys.json @@ -0,0 +1,87 @@ +{ + "title": "API 키", + "description": "세밀한 권한이 있는 게이트웨이 API 키 관리.", + "addKey": "API 키 만들기", + "searchPlaceholder": "키 검색...", + "emptyTitle": "API 키 없음", + "emptyDescription": "게이트웨이 인증을 위한 첫 번째 API 키를 만드세요.", + "columns": { + "name": "이름", + "prefix": "키", + "scopes": "범위", + "lastUsed": "마지막 사용", + "created": "생성됨", + "status": "상태", + "actions": "작업" + }, + "status": { + "active": "활성", + "revoked": "취소됨", + "expired": "만료됨" + }, + "form": { + "title": "API 키 만들기", + "name": "이름", + "namePlaceholder": "예: ci-deploy, dashboard-readonly", + "scopes": "범위", + "scopeDescriptions": { + "operator.admin": "전체 관리자 접근", + "operator.read": "읽기 전용 접근", + "operator.write": "읽기 + 쓰기 접근", + "operator.approvals": "실행 승인 관리", + "operator.pairing": "기기 페어링 관리", + "operator.provision": "새 테넌트 프로비전" + }, + "tenant": "테넌트", + "tenantSystem": "시스템 (모든 테넌트)", + "expiry": "만료", + "expiryOptions": { + "never": "만료 없음", + "7d": "7일", + "30d": "30일", + "90d": "90일" + }, + "cancel": "취소", + "create": "만들기", + "creating": "만드는 중..." + }, + "created": { + "title": "API 키 생성됨", + "description": "지금 이 키를 복사하세요 — 다시 표시되지 않습니다.", + "copied": "복사됨!", + "copy": "클립보드에 복사", + "done": "완료" + }, + "revoke": { + "title": "API 키 취소", + "description": "\"{{name}}\"을/를 취소하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "취소" + }, + "toast": { + "created": "API 키 생성됨", + "revoked": "API 키 취소됨", + "failedCreate": "API 키 생성 실패", + "failedRevoke": "API 키 취소 실패" + }, + "never": "없음", + "neverUsed": "사용된 적 없음", + "tenantBadgeSystem": "시스템", + "tenantBadgeUnknown": "알 수 없음", + "columns.expiry": "만료", + "codeDialog": { + "title": "API 키 사용법", + "description": "게이트웨이 HTTP API 인증에 이 API 키를 사용하세요.", + "copy": "복사", + "copied": "복사됨!", + "tabs": { + "curl": "cURL", + "typescript": "TypeScript", + "go": "Go" + }, + "comments": { + "chat": "에이전트와 채팅 (OpenAI 호환)", + "listAgents": "에이전트 목록", + "listSessions": "세션 목록" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/approvals.json b/ui/web/src/i18n/locales/ko/approvals.json new file mode 100644 index 00000000..56aa2599 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/approvals.json @@ -0,0 +1,33 @@ +{ + "title": "승인", + "description": "대기 중인 실행 승인", + "pending": "{{count}}개 대기 중", + "emptyTitle": "대기 중인 승인 없음", + "emptyDescription": "모든 실행 요청이 처리되었습니다. 새 요청은 실시간으로 여기에 나타납니다.", + "allowOnce": "한 번 허용", + "allowAlways": "항상 허용", + "deny": "거부", + "confirmAllowOnce": { + "title": "한 번 허용", + "description": "에이전트 \"{{agentId}}\"에서 \"{{command}}\" 실행을 허용하시겠습니까?" + }, + "confirmAllowAlways": { + "title": "항상 허용", + "description": "에이전트 \"{{agentId}}\"에 \"{{command}}\"을/를 영구적으로 허용하시겠습니까? 이 명령은 앞으로 자동으로 승인됩니다." + }, + "confirmDeny": { + "title": "실행 거부", + "description": "에이전트 \"{{agentId}}\"에서 요청한 \"{{command}}\" 실행을 거부하시겠습니까?", + "confirmLabel": "거부" + }, + "toast": { + "approved": "승인됨", + "approvedAlways": "명령이 항상 허용됨", + "approvedOnce": "명령이 승인됨", + "approveFailed": "승인 실패", + "denied": "거부됨", + "deniedDesc": "명령이 거부됨", + "denyFailed": "거부 실패", + "unknownError": "알 수 없는 오류" + } +} diff --git a/ui/web/src/i18n/locales/ko/backup.json b/ui/web/src/i18n/locales/ko/backup.json new file mode 100644 index 00000000..c5a92713 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/backup.json @@ -0,0 +1,126 @@ +{ + "title": "백업 & 복원", + "description": "시스템 백업 생성, 아카이브에서 복원, S3 스토리지 관리", + "tabs": { + "systemBackup": "시스템 백업", + "systemRestore": "시스템 복원", + "s3Config": "S3 스토리지", + "tenantBackup": "테넌트 백업" + }, + "backup": { + "preflight": { + "title": "시스템 확인", + "pgDump": "pg_dump 사용 가능", + "diskSpace": "충분한 디스크 공간", + "dbSize": "데이터베이스 크기", + "dataDir": "데이터 디렉터리", + "workspace": "워크스페이스", + "freeDisk": "여유 디스크 공간", + "warnings": "경고", + "refresh": "새로 고침", + "pgDumpMissing": "pg_dump를 사용할 수 없거나 호환되지 않음", + "goToPackages": "패키지로 이동" + }, + "options": { + "includeDb": "데이터베이스 포함", + "includeFiles": "파일 포함", + "destination": "백업 대상", + "local": "로컬로 다운로드", + "s3": "S3에 업로드" + }, + "start": "백업 시작", + "running": "백업 중...", + "complete": "백업 완료", + "download": "백업 다운로드", + "uploadS3": "S3에 업로드", + "newBackup": "새 백업", + "fileSize": "파일 크기", + "schemaVersion": "스키마 버전", + "s3History": { + "title": "S3 백업", + "empty": "S3에서 백업을 찾을 수 없음", + "name": "파일", + "size": "크기", + "date": "날짜" + }, + "errorTitle": "백업 실패" + }, + "restore": { + "warning": "복원하면 기존 데이터를 덮어씁니다. 이 작업은 취소할 수 없습니다. 먼저 백업을 만드세요.", + "dropzone": ".tar.gz 백업 아카이브를 여기에 놓기", + "dropzoneHint": "또는 클릭하여 찾아보기", + "options": { + "restoreDb": "데이터베이스 복원", + "restoreFiles": "파일 복원", + "dryRun": "미리 보기 (변경 없음)" + }, + "start": "복원", + "confirmTitle": "시스템 복원 확인", + "confirmDesc": "현재 데이터베이스와 파일이 백업 내용으로 덮어쓰입니다. 계속하시겠습니까?", + "running": "복원 중...", + "doNotClose": "복원 중에 이 페이지를 닫지 마세요", + "complete": "복원 완료", + "dryRunNote": "미리 보기 실행이었습니다. 변경사항이 적용되지 않았습니다.", + "dbRestored": "데이터베이스 복원됨", + "filesExtracted": "파일 추출됨", + "bytesExtracted": "데이터 복원됨", + "schemaVersion": "스키마 버전", + "warnings": "경고", + "newRestore": "새 복원", + "errorTitle": "복원 실패", + "tryAgain": "다시 시도" + }, + "s3": { + "title": "S3 스토리지 설정", + "description": "원격 백업을 위한 S3 호환 스토리지 설정", + "status": { + "configured": "설정됨", + "notConfigured": "설정되지 않음" + }, + "fields": { + "accessKeyId": "액세스 키 ID", + "secretAccessKey": "시크릿 액세스 키", + "secretPlaceholder": "업데이트하려면 입력", + "bucket": "버킷", + "region": "리전", + "endpoint": "엔드포인트 (선택사항)", + "endpointHint": "S3 호환 서비스 (MinIO, R2 등)", + "prefix": "키 접두사" + }, + "save": "저장 & 연결 테스트", + "saving": "연결 테스트 중...", + "saveSuccess": "S3 설정이 저장되었고 연결이 확인되었습니다", + "saveError": "S3 설정 저장 실패" + }, + "tenant": { + "title": "테넌트 백업 & 복원", + "description": "개별 테넌트 데이터 백업 또는 복원", + "selectTenant": "테넌트 선택", + "selectTenantPlaceholder": "테넌트 선택...", + "backup": { + "start": "테넌트 백업", + "running": "테넌트 백업 중...", + "complete": "테넌트 백업 완료", + "download": "다운로드", + "tableCounts": "백업된 테이블", + "newBackup": "새 백업" + }, + "restore": { + "mode": "복원 모드", + "modeUpsert": "병합 (upsert)", + "modeReplace": "전체 교체", + "modeNew": "새 테넌트", + "dropzone": "테넌트 백업 아카이브를 여기에 놓기", + "dryRun": "미리 보기 (변경 없음)", + "start": "테넌트 복원", + "confirmTitle": "테넌트 복원 확인", + "confirmDesc": "선택한 테넌트의 데이터가 수정됩니다. 계속하시겠습니까?", + "running": "테넌트 복원 중...", + "complete": "테넌트 복원 완료", + "tablesRestored": "테이블 복원됨", + "filesExtracted": "파일 추출됨", + "dryRunNote": "미리 보기 실행 — 변경사항 없음", + "newRestore": "새 복원" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/channels.json b/ui/web/src/i18n/locales/ko/channels.json new file mode 100644 index 00000000..7d157afc --- /dev/null +++ b/ui/web/src/i18n/locales/ko/channels.json @@ -0,0 +1,487 @@ +{ + "title": "채널", + "description": "채널 인스턴스 관리", + "statusDescription": "통신 채널 상태", + "addChannel": "채널 추가", + "refresh": "새로 고침", + "searchPlaceholder": "채널 검색...", + "emptyTitle": "채널 없음", + "emptyDescription": "첫 번째 채널 인스턴스를 추가하여 시작하세요.", + "emptyStatusDescription": "설정된 통신 채널이 없습니다.", + "noMatchTitle": "일치하는 채널 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "columns": { + "name": "이름", + "type": "유형", + "agent": "에이전트", + "status": "상태", + "enabled": "활성화됨", + "actions": "작업" + }, + "status": { + "running": "실행 중", + "stopped": "중지됨", + "checking": "확인 중", + "degraded": "저하됨", + "starting": "시작 중", + "registered": "설정됨", + "failed": "실패" + }, + "enabled": "활성화됨", + "disabled": "비활성화됨", + "actions": { + "reauthenticate": "재인증", + "authenticate": "채널을 시작하려면 인증", + "reauthShort": "재인증", + "openCredentials": "자격증명 열기", + "openAdvanced": "고급 설정 열기", + "inspect": "문제 검사" + }, + "list": { + "failureStreak": "연속 {{count}}회 실패", + "openChannelDetail": "최신 진단을 위해 채널 상세 정보 열기", + "nextStep": "다음 단계" + }, + "failureKind": { + "auth": "인증", + "config": "설정", + "network": "네트워크", + "unknown": "주의 필요" + }, + "delete": { + "title": "채널 인스턴스 삭제", + "description": "\"{{name}}\"을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "form": { + "createTitle": "채널 인스턴스 생성", + "editTitle": "채널 인스턴스 편집", + "key": "키 *", + "keyPlaceholder": "my-telegram-bot", + "keyHint": "채널 식별자로 사용되는 고유 슬러그", + "displayName": "표시 이름", + "displayNamePlaceholder": "판매 봇", + "channelType": "채널 유형 *", + "agent": "에이전트 *", + "selectAgent": "에이전트 선택", + "credentials": "자격증명", + "credentialsHint": "(현재 값을 유지하려면 비워두세요)", + "credentialsEncrypted": "서버 측에서 암호화됩니다. API 응답에 반환되지 않습니다.", + "configuration": "설정", + "enabled": "활성화됨", + "cancel": "취소", + "create": "생성", + "update": "업데이트", + "saving": "저장 중...", + "step": "{{current}} / {{total}} 단계", + "authenticate": "인증 — {{label}}", + "configure": "설정 — {{label}}", + "skip": "건너뛰기", + "done": "완료", + "errors": { + "keyRequired": "키가 필요합니다", + "keySlug": "키는 유효한 슬러그여야 합니다 (소문자, 숫자, 하이픈만 사용)", + "agentRequired": "에이전트가 필요합니다", + "requiredFields": "필수 항목: {{fields}}", + "failedSave": "저장 실패", + "failedSaveConfig": "설정 저장 실패" + }, + "authStatus": { + "authenticated": "인증됨", + "notAuthenticated": "인증되지 않음", + "useQrHint": "— 채널 테이블에서 QR 로그인 버튼을 사용하세요" + } + }, + "detail": { + "agent": "에이전트: {{name}}", + "lastChecked": "마지막 확인: {{value}}", + "checkedRelative": "{{value}} 확인됨", + "advanced": "고급", + "advancedTitle": "고급 설정", + "policies": "정책", + "policiesDesc": "메시지 처리 정책", + "network": "네트워크", + "networkDesc": "서버 및 프록시 설정", + "limits": "제한", + "limitsDesc": "메시지 및 미디어 제약", + "streaming": "스트리밍", + "streamingDesc": "실시간 메시지 스트리밍 옵션", + "behavior": "동작", + "behaviorDesc": "응답 동작 설정", + "accessControl": "접근 제어", + "accessControlDesc": "사용자 접근 제한", + "reviewDiagnostics": "설정을 변경하기 전에 이 채널의 최신 진단을 검토하세요.", + "whatHappened": "무슨 일이 있었는지", + "recommendedAction": "권장 조치", + "technicalDetail": "기술적 세부 사항", + "tabs": { + "general": "일반", + "config": "설정", + "credentials": "자격증명", + "groups": "그룹", + "managers": "관리자" + }, + "general": { + "identity": "식별", + "name": "이름", + "nameHint": "고유 슬러그 (읽기 전용)", + "channelType": "채널 유형", + "displayName": "표시 이름", + "displayNamePlaceholder": "친화적 이름", + "agent": "에이전트", + "selectAgent": "에이전트 선택", + "enabled": "활성화됨", + "saved": "저장됨", + "saveChanges": "변경 사항 저장", + "saving": "저장 중..." + }, + "credentials": { + "hint": "현재 값을 유지하려면 필드를 비워두세요. 자격증명은 서버 측에서 암호화되며 API 응답에 반환되지 않습니다.", + "noSchema": "이 채널 유형에 대한 자격증명 스키마가 없습니다.", + "noCredentials": "업데이트할 자격증명 없음", + "failedSave": "저장 실패", + "saved": "저장됨", + "updateCredentials": "자격증명 업데이트", + "saving": "저장 중..." + }, + "config": { + "noSchema": "이 채널 유형에 대한 설정 스키마가 없습니다.", + "saved": "저장됨", + "saveConfig": "설정 저장", + "saving": "저장 중...", + "webhookUrlLabel": "이것을 Lark 앱의 이벤트 요청 URL로 설정하세요:", + "copyPath": "경로 복사" + }, + "groups": { + "saved": "저장됨", + "saveGroups": "그룹 저장", + "saving": "저장 중..." + }, + "timeline": { + "title": "타임라인", + "firstFailed": "첫 실패", + "lastChecked": "마지막 확인", + "failures": "실패", + "failureStreak": "연속 {{count}}회", + "failureTotal": "총 {{count}}회", + "lastHealthy": "마지막 정상", + "noData": "아직 최근 채널 확인 기록이 없습니다." + }, + "managers": { + "description": "그룹 채팅에서 관리자 권한을 가진 사용자를 관리합니다.", + "groups": "그룹", + "noManagerGroups": "관리자 그룹 없음", + "noManagerGroupsHint": "아래 양식을 사용하여 그룹에 관리자를 추가하세요.", + "loadingManagers": "관리자 불러오는 중...", + "noManagers": "이 그룹에 관리자가 없습니다.", + "managersCount": "{{count}}명 관리자", + "managersCountPlural": "{{count}}명 관리자", + "searchContacts": "연락처 검색...", + "noResults": "연락처를 찾을 수 없음", + "columns": { + "userId": "사용자 ID", + "name": "이름", + "username": "사용자명" + }, + "addForm": { + "title": "새 그룹에 관리자 추가", + "hint": "위 목록에 없는 그룹에 관리자를 추가합니다.", + "groupId": "그룹 ID *", + "groupIdPlaceholder": "예: group:telegram:-100123456", + "userId": "사용자 ID *", + "userIdPlaceholder": "검색하거나 사용자 ID 입력", + "displayName": "표시 이름", + "username": "사용자명", + "optional": "선택사항", + "usernameWithout": "선택사항 (@ 제외)", + "adding": "추가 중...", + "addManager": "관리자 추가", + "add": "추가", + "errors": { + "groupUserRequired": "그룹 ID와 사용자 ID가 필요합니다", + "failedAdd": "관리자 추가 실패" + } + } + } + }, + "fieldConfig": { + "token": { "label": "봇 토큰", "help": "@BotFather에서 받은 토큰" }, + "bot_token": { "label": "봇 토큰" }, + "app_token": { + "label": "앱 레벨 토큰", + "help": "connections:write 범위의 앱 레벨 토큰 (소켓 모드에 필요)" + }, + "user_token": { + "label": "사용자 토큰 (선택사항)", + "help": "선택사항: 커스텀 봇 식별을 위한 사용자 OAuth 토큰. 기본 봇 식별을 사용하려면 비워두세요." + }, + "app_id": { "label": "앱 ID" }, + "app_secret": { "label": "앱 시크릿" }, + "encrypt_key": { "label": "암호화 키", "help": "웹훅 모드용" }, + "verification_token": { + "label": "인증 토큰", + "help": "웹훅 모드용" + }, + "webhook_secret": { "label": "웹훅 시크릿" }, + "api_server": { + "label": "API 서버 URL", + "help": "대용량 파일 업로드(최대 2GB)를 위한 커스텀 Telegram Bot API 서버. 기본값을 사용하려면 비워두세요." + }, + "proxy": { + "label": "HTTP 프록시", + "help": "HTTP 프록시를 통해 봇 트래픽 라우팅" + }, + "dm_policy": { "label": "DM 정책" }, + "group_policy": { "label": "그룹 정책" }, + "require_mention": { + "label": "그룹에서 @멘션 필요", + "disabledHint": "멀티봇 모드는 항상 모든 메시지를 수신합니다" + }, + "mention_mode": { + "label": "그룹 응답 동작", + "help": "여러 봇이 있는 그룹에서 봇이 응답할 시기를 결정하는 방법입니다." + }, + "history_limit": { + "label": "그룹 기록 제한", + "help": "컨텍스트용 최대 대기 그룹 메시지 수 (0 = 비활성화)" + }, + "dm_stream": { + "label": "DM 스트리밍", + "help": "DM에서 응답을 점진적으로 스트리밍" + }, + "group_stream": { + "label": "그룹 스트리밍", + "help": "그룹에서 응답을 점진적으로 스트리밍" + }, + "draft_transport": { + "label": "임시 미리보기", + "help": "DM에서 답변 스트림에 스텔스 임시 미리보기 사용 — 편집당 알림 없음 (DM 스트리밍 필요)" + }, + "reasoning_stream": { + "label": "추론 표시", + "help": "답변 전에 AI 사고를 별도 메시지로 표시 (스트리밍 필요)" + }, + "reaction_level": { "label": "반응 수준" }, + "media_max_mb": { "label": "최대 미디어 크기 (MB)" }, + "link_preview": { "label": "링크 미리보기" }, + "allow_from": { "label": "허용된 사용자" }, + "block_reply": { + "label": "블록 응답", + "help": "도구 반복 중 중간 텍스트 전달" + }, + "domain": { "label": "도메인" }, + "connection_mode": { + "label": "연결 모드", + "help": "WebSocket은 공개 IP가 필요 없습니다 — 아웃바운드 연결만 사용" + }, + "webhook_port": { + "label": "웹훅 포트", + "help": "0 = 메인 게이트웨이 포트 공유 (권장)" + }, + "webhook_path": { + "label": "웹훅 경로", + "help": "Lark 이벤트를 위한 메인 서버 경로" + }, + "webhook_url": { "label": "웹훅 URL" }, + "topic_session_mode": { + "label": "토픽 세션 모드", + "help": "세션 격리를 위해 스레드 root_id 사용" + }, + "render_mode": { "label": "렌더링 모드" }, + "text_chunk_limit": { + "label": "텍스트 청크 제한", + "help": "메시지당 최대 문자 수" + }, + "group_allow_from": { + "label": "그룹 허용된 사용자", + "help": "그룹 발신자를 위한 별도 허용 목록" + }, + "native_stream": { + "label": "네이티브 스트리밍 (에이전트 & AI 앱)", + "help": "네이티브 스트리밍을 위해 Slack의 ChatStreamer API 사용. 사용 불가 시 편집-인-플레이스로 폴백됩니다." + }, + "debounce_delay": { + "label": "디바운스 지연 (ms)", + "help": "빠른 메시지 처리 전 대기할 밀리초입니다. 비활성화하려면 0으로 설정하세요." + }, + "thread_ttl": { + "label": "스레드 참여 TTL (시간)", + "help": "참여한 스레드에서 봇이 자동 응답을 중지하기까지의 시간입니다. 0 = 항상 @멘션 필요." + }, + "skills": { + "label": "스킬 필터", + "help": "이 그룹에서 사용 가능한 스킬 제한" + }, + "tools": { + "label": "도구 허용 목록", + "help": "이 그룹에서 에이전트가 사용할 수 있는 도구 제한" + }, + "system_prompt": { "label": "시스템 프롬프트" } + }, + "fieldOptions": { + "block_reply": { + "inherit": "게이트웨이에서 상속", + "true": "활성화됨", + "false": "비활성화됨" + }, + "dm_policy": { + "pairing": "페어링 (코드 필요)", + "open": "개방 (모두 허용)", + "allowlist": "허용 목록만", + "disabled": "비활성화됨" + }, + "group_policy": { + "open": "개방 (모두 허용)", + "pairing": "페어링 (승인 필요)", + "allowlist": "허용 목록만", + "disabled": "비활성화됨" + }, + "mention_mode": { + "strict": "기본 (@멘션 설정 따름)", + "yield": "멀티봇 (다른 봇이 @멘션되지 않으면 응답)" + }, + "reaction_level": { + "off": "끄기", + "minimal": "최소", + "full": "전체" + }, + "domain": { + "lark": "Lark (글로벌)", + "feishu": "Feishu (중국)" + }, + "connection_mode": { + "webhook": "웹훅", + "websocket": "WebSocket (권장)" + }, + "topic_session_mode": { + "disabled": "비활성화됨", + "enabled": "활성화됨" + }, + "render_mode": { + "auto": "자동", + "raw": "원본", + "card": "카드" + } + }, + "groupOverrides": { + "title": "그룹 & 토픽 재정의", + "hint": "그룹 채팅 또는 포럼 토픽별로 채널 기본값을 재정의합니다. 와일드카드 기본값으로 \"*\"를 그룹 ID로 사용하세요.", + "groupLabel": "그룹: {{id}}", + "groupWildcard": "* (와일드카드)", + "addGroupPlaceholder": "채팅 ID (예: -100123456) 또는 *", + "addGroup": "그룹 추가", + "knownGroups": "알려진 그룹", + "topicOverrides": "토픽 재정의", + "topicLabel": "토픽: {{id}}", + "addTopicPlaceholder": "토픽 스레드 ID", + "addTopic": "토픽 추가", + "fieldConfig": { + "dm_stream": { + "label": "DM 스트리밍", + "help": "DM에서 응답을 점진적으로 스트리밍" + }, + "group_stream": { + "label": "그룹 스트리밍", + "help": "그룹에서 응답을 점진적으로 스트리밍" + }, + "draft_transport": { + "label": "임시 미리보기", + "help": "DM에서 답변 스트림에 스텔스 임시 미리보기 사용 — 편집당 알림 없음 (DM 스트리밍 필요)" + }, + "reasoning_stream": { + "label": "추론 표시", + "help": "답변 전에 AI 사고를 별도 메시지로 표시 (스트리밍 필요)" + } + }, + "fields": { + "groupPolicy": "그룹 정책", + "requireMention": "@멘션 필요", + "enabled": "활성화됨", + "allowedUsers": "허용된 사용자", + "allowedUsersPlaceholder": "사용자 ID를 줄당 하나 또는 쉼표로 구분", + "skillsFilter": "스킬 필터", + "skillsPlaceholder": "줄당 하나의 스킬명 (비어있으면 상속)", + "toolAllow": "도구 허용", + "toolAllowPlaceholder": "허용할 도구 선택 (비어있으면 모두 상속)...", + "toolAllowHint": "이 그룹에서 사용 가능한 도구를 제한합니다. \"group:web\", \"group:fs\" 같은 그룹명을 지원합니다. 비어있으면 모든 도구 상속.", + "systemPrompt": "시스템 프롬프트", + "systemPromptPlaceholder": "이 그룹/토픽을 위한 추가 시스템 프롬프트", + "inherit": "상속 (채널 기본값)", + "yes": "예", + "no": "아니오" + } + }, + "wizard": { + "zaloPersonal": { + "createLabel": "생성 & 인증", + "formBanner": "생성 후 QR 코드를 통해 인증하고 허용된 사용자를 설정합니다." + }, + "whatsapp": { + "createLabel": "생성 & QR 스캔", + "formBanner": "생성 후 WhatsApp으로 QR 코드를 스캔하여 인증합니다." + } + }, + "fallback": { + "authRequiredSummary": "인증 필요", + "authRequiredDetail": "채널 인스턴스가 활성화되었지만 연결 전에 로그인이 필요합니다.", + "authRequiredHeadline": "채널 세션 재연결", + "authRequiredHint": "현재 세션을 복원하려면 이 채널을 다시 인증하세요.", + "missingCredentialsSummary": "자격증명 없음", + "missingCredentialsDetail": "채널 인스턴스가 활성화되었지만 필수 자격증명이 불완전합니다.", + "missingCredentialsHeadline": "필수 자격증명 완성", + "missingCredentialsHint": "자격증명을 열고 이 채널의 누락되거나 잘못된 값을 입력하세요." + }, + "scopes": { + "title": "필수 API 권한", + "description": "Lark/Feishu 앱은 개발자 콘솔에서 이 범위들이 활성화되어야 합니다. 권한 추가 후 새 앱 버전을 게시하세요.", + "publishReminder": "범위 추가 후 연락처 범위를 \"모든 멤버\"로 설정하고 새 앱 버전을 게시하여 변경 사항을 적용하세요." + }, + "toast": { + "created": "채널 생성됨", + "createdDesc": "{{name}}이 추가되었습니다", + "updated": "채널 업데이트됨", + "deleted": "채널 삭제됨", + "failedCreate": "채널 생성 실패", + "failedUpdate": "채널 업데이트 실패", + "failedDelete": "채널 삭제 실패" + }, + "zalo": { + "allowedUsers": "허용된 사용자", + "loadContacts": "연락처 불러오기", + "loading": "불러오는 중...", + "searchContacts": "연락처 검색...", + "friends": "친구", + "groups": "그룹", + "membersCount": "{{count}}명 멤버", + "noContacts": "연락처를 찾을 수 없음", + "noContactsMatch": "\"{{search}}\"와 일치하는 연락처 없음", + "addManualPlaceholder": "ID 수동 추가", + "add": "추가", + "zaloIdsHint": "Zalo 사용자 ID 또는 그룹 ID", + "completeQrLogin": "연락처를 불러오려면 QR 로그인을 완료하세요", + "loginQr": "QR로 로그인 — {{name}}", + "loginSuccessful": "로그인 성공! 채널 시작 중...", + "generatingQr": "QR 코드 생성 중...", + "scanHint": "Zalo 앱으로 스캔 (약 100초 후 만료)", + "loginSuccessLoading": "로그인 성공! 연락처 불러오는 중...", + "retry": "재시도", + "close": "닫기", + "skip": "건너뛰기" + }, + "whatsapp": { + "loginSuccessLoading": "✅ WhatsApp 연결됨! 채널 불러오는 중...", + "waitingForQr": "QR 코드 대기 중...", + "scanHint": "WhatsApp → 나 탭 → 연결된 기기 → 기기 연결", + "initializing": "초기화 중...", + "skip": "건너뛰기", + "retry": "재시도", + "close": "닫기", + "reauthTitle": "WhatsApp 연결 — {{name}}", + "reauthDescription": "WhatsApp으로 QR 코드를 스캔하여 기기를 연결하세요.", + "alreadyLinked": "✅ 기기가 이미 연결됨", + "alreadyLinkedDetail": "WhatsApp이 연결되어 있습니다. 다른 기기를 연결하려면 재연결을 클릭하세요 — 현재 세션이 로그아웃됩니다.", + "relinkDevice": "기기 재연결", + "connectedSuccess": "✅ WhatsApp이 성공적으로 연결되었습니다!", + "tabQrCode": "QR 코드" + } +} diff --git a/ui/web/src/i18n/locales/ko/chat.json b/ui/web/src/i18n/locales/ko/chat.json new file mode 100644 index 00000000..afd53d26 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/chat.json @@ -0,0 +1,33 @@ +{ + "deleteChat": "채팅 삭제", + "deleteChatConfirm": "이 대화와 모든 메시지가 영구적으로 삭제됩니다.", + "newChat": "새 채팅", + "openSessions": "세션 열기", + "readOnly": "읽기 전용 — 이 세션은 다른 사용자의 것입니다", + "contextUsage": { + "tooltip": "{{used}} / {{max}} 토큰 ({{percent}}%) · {{compactions}}회 압축 · 마지막: {{lastCompact}}", + "never": "없음" + }, + "empty": { + "title": "대화 시작", + "description": "에이전트와 채팅을 시작하려면 메시지를 보내세요." + }, + "media": { + "image": "이미지", + "video": "동영상", + "audio": "오디오", + "voice": "음성 메시지", + "document": "문서", + "animation": "애니메이션", + "attached": "첨부됨" + }, + "forwardedFrom": "전달됨 (from)", + "replyingTo": "답장 대상", + "error": { + "notConnected": "연결되지 않았습니다. 연결이 설정될 때까지 기다려 주세요." + }, + "selectAgent": { + "title": "에이전트 선택", + "description": "채팅할 에이전트를 선택하세요" + } +} diff --git a/ui/web/src/i18n/locales/ko/cli-credentials.json b/ui/web/src/i18n/locales/ko/cli-credentials.json new file mode 100644 index 00000000..5754b87e --- /dev/null +++ b/ui/web/src/i18n/locales/ko/cli-credentials.json @@ -0,0 +1,114 @@ +{ + "title": "CLI 자격증명", + "description": "자격증명이 주입된 에이전트용 보안 CLI 바이너리를 관리합니다.", + "addCredential": "자격증명 추가", + "emptyTitle": "CLI 자격증명 없음", + "emptyDescription": "CLI 자격증명을 추가하여 에이전트가 인증된 CLI 명령을 실행할 수 있게 하세요.", + "columns": { + "binary": "바이너리", + "scope": "범위", + "timeout": "타임아웃", + "restricted": "제한됨" + }, + "delete": { + "title": "CLI 자격증명 삭제", + "description": "\"{{name}}\"을 삭제하시겠습니까? 이를 사용하는 에이전트는 접근 권한을 잃게 됩니다.", + "confirm": "삭제" + }, + "form": { + "createTitle": "CLI 자격증명 추가", + "editTitle": "CLI 자격증명 편집", + "preset": "프리셋", + "presetPlaceholder": "프리셋 선택 (선택사항)", + "noPreset": "프리셋 없음 (수동)", + "presetHint": "프리셋을 선택하면 필드가 자동으로 채워지고 필수 환경 변수가 표시됩니다.", + "encryptedHint": "값은 암호화되며 표시되지 않습니다. 변수명은 아래에 나열됩니다. 저장된 시크릿을 유지하려면 값을 비워두고, 새 값으로 교체하려면 입력하세요.", + "envVars": "환경 변수", + "binaryName": "바이너리 이름", + "binaryPath": "바이너리 경로", + "denyArgs": "차단 인수", + "denyVerbose": "차단 상세 인수", + "timeout": "타임아웃 (초)", + "tips": "팁", + "agentId": "에이전트", + "agentIdHint": "선택사항 — 전역으로 사용하려면 비워두세요", + "commaSeparated": "쉼표로 구분", + "binaryNameRequired": "바이너리 이름이 필요합니다.", + "failedToSave": "저장 실패.", + "addEnvVar": "변수 추가", + "noEnvVarsHint": "\"변수 추가\"를 클릭하여 이 CLI 도구의 환경 변수를 정의하세요.", + "envKeyPlaceholder": "ENV_VAR_NAME", + "envValuePlaceholder": "값", + "invalidEnvKey": "\"{{key}}\"는 유효한 환경 변수 이름이 아닙니다 (A-Z, 0-9, 언더스코어 사용).", + "binaryPathHint": "PATH에서 자동 감지하려면 비워두세요", + "checkBinary": "확인", + "binaryFound": "{{path}}에서 발견됨", + "binaryNotFound": "서버 PATH에서 바이너리를 찾을 수 없음", + "checking": "확인 중...", + "isGlobal": "모든 에이전트에서 사용 가능", + "isGlobalHint": "비활성화 시, 명시적 권한이 있는 에이전트만 이 CLI를 사용할 수 있습니다" + }, + "placeholders": { + "binaryName": "예: gh", + "binaryPath": "/usr/local/bin/...", + "description": "이 CLI 도구의 역할", + "denyArgs": "--admin, --force", + "denyVerbose": "-v, --verbose", + "tips": "에이전트를 위한 사용 팁", + "agentId": "전역 (모든 에이전트)" + }, + "toast": { + "created": "CLI 자격증명 생성됨", + "createdDesc": "\"{{name}}\"이 성공적으로 추가되었습니다.", + "createFailed": "자격증명 생성 실패", + "updated": "CLI 자격증명 업데이트됨", + "updateFailed": "자격증명 업데이트 실패", + "deleted": "CLI 자격증명 삭제됨", + "deleteFailed": "자격증명 삭제 실패" + }, + "userCredentials": { + "title": "사용자 자격증명", + "description": "{{name}}에 대한 사용자별 환경 변수 재정의", + "userId": "사용자 ID", + "userIdPlaceholder": "user-id 또는 이메일", + "env": "환경 변수", + "addEnv": "변수 추가", + "add": "추가", + "save": "저장", + "edit": "편집", + "delete": "삭제", + "back": "뒤로", + "close": "닫기", + "empty": "사용자 자격증명 없음", + "saved": "사용자 자격증명 저장됨", + "saveFailed": "사용자 자격증명 저장 실패", + "deleted": "사용자 자격증명 삭제됨", + "deleteFailed": "사용자 자격증명 삭제 실패", + "envRequired": "환경 변수가 하나 이상 필요합니다", + "mergeHint": "채팅 사용자(Telegram, Discord 등)는 사용자별 자격증명을 갖기 전에 연락처 페이지에서 테넌트 사용자로 먼저 병합되어야 합니다." + }, + "grants": { + "title": "에이전트 권한 — {{name}}", + "currentGrants": "현재 권한", + "addGrant": "권한 추가", + "editGrant": "권한 편집", + "selectAgent": "에이전트 선택...", + "usingDefaults": "바이너리 기본값 사용", + "overrideTimeout": "타임아웃 재정의 (초)", + "overrideDenyArgs": "차단 인수 재정의", + "overrideDenyVerbose": "차단 상세 인수 재정의", + "overrideTips": "팁 재정의", + "defaultPlaceholder": "기본값", + "grant": "권한 부여", + "update": "업데이트", + "agentRequired": "에이전트를 선택해 주세요", + "toast": { + "granted": "에이전트 권한 생성됨", + "grantFailed": "권한 생성 실패", + "updated": "에이전트 권한 업데이트됨", + "updateFailed": "권한 업데이트 실패", + "revoked": "에이전트 권한 취소됨", + "revokeFailed": "권한 취소 실패" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/common.json b/ui/web/src/i18n/locales/ko/common.json new file mode 100644 index 00000000..ebefa74f --- /dev/null +++ b/ui/web/src/i18n/locales/ko/common.json @@ -0,0 +1,139 @@ +{ + "refresh": "새로 고침", + "cancel": "취소", + "confirm": "확인", + "delete": "삭제", + "save": "저장", + "edit": "편집", + "create": "만들기", + "add": "추가", + "view": "보기", + "filter": "필터", + "search": "검색", + "retry": "재시도", + "manage": "관리", + "uploadLabel": "업로드", + "close": "닫기", + "back": "뒤로", + "update": "업데이트", + "enabled": "사용 중", + "disabled": "사용 안 함", + "yes": "예", + "no": "아니오", + "loading": "불러오는 중...", + "saving": "저장 중...", + "creating": "만드는 중...", + "connecting": "연결 중...", + "connected": "연결됨", + "disconnected": "연결 끊김", + "running": "실행 중", + "stopped": "정지됨", + "pending": "대기 중", + "completed": "완료됨", + "failed": "실패", + "cancelled": "취소됨", + "unknown": "알 수 없음", + "active": "활성", + "items": "항목", + "rows": "행", + "pageOf": "{{page}} / {{totalPages}} 페이지", + "messages": "메시지", + "cached": "캐시됨", + "live": "실시간", + "noDescription": "설명 없음", + "unsavedChanges": "저장되지 않은 변경사항", + "tryDifferentSearch": "다른 검색어를 사용해 보세요.", + "notSet": "설정되지 않음", + "default": "기본값", + "optional": "선택사항", + "required": "필수", + "actions": "작업", + "status": "상태", + "name": "이름", + "description": "설명", + "type": "유형", + "none": "없음", + "all": "전체", + "global": "전체", + "agent": "에이전트", + "saved": "저장됨", + "saveChanges": "변경사항 저장", + "saveConfig": "설정 저장", + "checkAndCreate": "확인 & 만들기", + "checking": "확인 중...", + "format": "JSON 형식 지정", + "invalidJson": "유효하지 않은 JSON 구문", + "usingGlobalDefaults": "config.json의 전체 기본값 사용 중", + "disconnectedGateway": "게이트웨이 연결이 끊겼습니다. 재연결 시도 중...", + "serverUnreachable": "서버에 연결할 수 없음", + "serverUnreachableDesc": "게이트웨이 서버에 연결할 수 없습니다. 서버가 실행 중인지 확인하세요.", + "reconnecting": "재연결 중...", + "noFiles": "파일이 없습니다.", + "selectFileToView": "파일을 선택하면 내용을 볼 수 있습니다", + "typeToConfirmPrefix": "확인을 위해", + "typeToConfirmSuffix": "을/를 입력하세요.", + "searchPlaceholder": "검색...", + "noSessions": "세션이 없습니다. 채팅을 시작하세요!", + "noAgentsAvailable": "사용 가능한 에이전트 없음", + "selectAgent": "에이전트 선택", + "sendMessage": "메시지 보내기... (Shift+Enter로 줄바꿈)", + "stopGeneration": "생성 중지", + "sendMessageTitle": "메시지 보내기", + "sendFollowUp": "후속 메시지 보내기", + "attachFile": "파일 첨부", + "thinking": "생각 중", + "thinkingStreaming": "생각 중...", + "toolArguments": "인수", + "toolResult": "결과", + "skillActivating": "활성화 중...", + "skillActivated": "활성화됨", + "toolRunning": "실행 중...", + "toolDone": "완료", + "toolFailed": "실패", + "filesBack": "파일", + "noProvidersConfigured": "설정된 공급자 없음", + "loadingModels": "모델 불러오는 중...", + "modelVerified": "모델 확인됨", + "verificationFailed": "확인 실패", + "provider": "공급자", + "model": "모델", + "selectProvider": "공급자 선택", + "enterOrSelectModel": "모델 입력 또는 선택", + "useCustomModel": "사용자 지정 모델:", + "providerTip": "LLM 공급자 이름. 설정된 공급자와 일치해야 합니다.", + "modelTip": "사용할 모델 ID.", + "check": "확인", + "builtinTools": "내장", + "customTools": "사용자 지정", + "selectOrTypeTools": "도구 이름 선택 또는 입력...", + "selectOrTypeSkills": "스킬 이름 선택 또는 입력...", + "typeAndPressEnter": "입력 후 Enter를 누르세요...", + "copyCode": "코드 복사", + "copy": "복사", + "download": "다운로드", + "errorBoundary": "이 섹션을 렌더링하는 중 오류가 발생했습니다.", + "csvRows": "csv ({{count}}행)", + "failedToLoadImage": "이미지를 불러오지 못했습니다", + "deleteFolder": "폴더 삭제", + "deleteFile": "파일 삭제", + "loadMore": "더 불러오기...", + "viewCard": "카드 보기", + "viewList": "목록 보기", + "done": "완료", + "upload": { + "title": "파일 업로드", + "dropOrClick": "파일을 여기에 끌어다 놓거나 클릭하여 찾아보기", + "dropHere": "파일을 여기에 끌어다 놓기", + "maxSize": "파일당 최대 50 MB", + "blockedType": "{{ext}} 파일 유형은 허용되지 않습니다", + "tooLarge": "파일이 50 MB 제한을 초과합니다", + "failed": "업로드 실패", + "readyCount": "{{total}}개 중 {{ready}}개 파일 준비됨", + "successCount": "{{total}}개 중 {{success}}개 파일 업로드됨", + "uploading": "업로드 중...", + "uploadCount": "{{count}}개 파일 업로드" + }, + "errors": { + "serverError": "오류가 발생했습니다. 나중에 다시 시도해 주세요." + } +} diff --git a/ui/web/src/i18n/locales/ko/config.json b/ui/web/src/i18n/locales/ko/config.json new file mode 100644 index 00000000..e99c9e69 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/config.json @@ -0,0 +1,315 @@ +{ + "title": "설정", + "description": "게이트웨이, 에이전트 기본값, 도구 및 통합 관리", + "noConfig": "설정이 로드되지 않음", + "noConfigDescription": "설정 파일을 불러올 수 없습니다. 게이트웨이에 연결할 수 없을 수 있습니다.", + "retry": "재시도", + "warning": "여기서의 변경사항은 모든 에이전트와 채널에 전역으로 영향을 줍니다. 잘못된 설정은 게이트웨이를 중단시킬 수 있습니다.", + "save": "저장", + "saving": "저장 중...", + "saved": "저장됨", + "failedToSave": "설정 저장 실패", + "saveConfig": "설정 저장", + "usingGlobalDefaults": "전역 기본값 사용", + + "tabs.server": "서버", + "tabs.behavior": "동작", + "tabs.aiDefaults": "AI 기본값", + "tabs.quota": "할당량", + "tabs.tools": "도구", + "tabs.integrations": "통합", + + "server.title": "게이트웨이 서버", + "server.description": "네트워크 바인딩, 인증 토큰 및 접근 제어", + + "gateway.host": "호스트", + "gateway.hostTip": "게이트웨이가 수신하는 네트워크 인터페이스입니다. 모든 인터페이스에서 수신하려면 0.0.0.0을 사용하세요.", + "gateway.port": "포트", + "gateway.portTip": "게이트웨이 WebSocket 및 HTTP 서버가 바인딩하는 TCP 포트입니다.", + "gateway.token": "인증 토큰", + "gateway.tokenTip": "모든 클라이언트 연결에 필요한 베어러 토큰입니다. 인증을 비활성화하려면 비워두세요.", + "gateway.tokenManaged": "토큰은 환경 변수를 통해 관리되며 여기서 편집할 수 없습니다.", + "gateway.ownerIds": "소유자 ID", + "gateway.ownerIdsTip": "관리자 수준 접근 권한이 부여된 사용자 ID입니다. 여러 ID는 Enter로 구분하세요.", + "gateway.ownerIdsPlaceholder": "소유자 ID 입력...", + "gateway.allowedOrigins": "허용된 출처", + "gateway.allowedOriginsTip": "HTTP API를 위한 CORS 허용 출처입니다. 모든 출처를 허용하려면 *를 사용하세요.", + "gateway.allowedOriginsPlaceholder": "https://yourdomain.com", + "gateway.toolStatus": "도구 상태 메시지", + "gateway.blockReply": "중간 응답", + "gateway.maxMessageChars": "최대 메시지 문자", + "gateway.maxMessageCharsTip": "인바운드 메시지당 허용되는 최대 문자 수입니다. 이 한도를 초과하는 메시지는 거부됩니다.", + "gateway.rateLimitRpm": "속도 제한 (RPM)", + "gateway.rateLimitRpmTip": "사용자당 분당 최대 요청 수입니다. 속도 제한을 비활성화하려면 0으로 설정하세요.", + "gateway.inboundDebounceMs": "인바운드 디바운스 (ms)", + "gateway.inboundDebounceMsTip": "새 메시지를 처리하기 전 대기할 밀리초입니다. 빠른 후속 메시지를 통합하기 위해 사용합니다. 비활성화하려면 -1로 설정하세요.", + "gateway.injectionAction": "주입 감지 조치", + + "agents.title": "에이전트 기본값", + "agents.description": "재정의하지 않는 한 모든 에이전트에 적용되는 기본 LLM 공급자, 모델 및 런타임 설정", + "agents.providerTip": "에이전트가 지정하지 않을 때 사용되는 기본 LLM 공급자입니다.", + "agents.modelTip": "에이전트가 지정하지 않을 때 사용되는 기본 모델입니다.", + "agents.maxTokens": "최대 토큰", + "agents.maxTokensTip": "모델이 단일 응답에서 생성할 수 있는 최대 토큰 수입니다.", + "agents.temperature": "온도", + "agents.temperatureTip": "샘플링 온도 (0-2). 낮을수록 더 결정론적인 출력이 생성됩니다.", + "agents.maxToolIterations": "최대 도구 반복", + "agents.maxToolIterationsTip": "에이전트 요청당 최대 도구 호출 반복 횟수입니다.", + "agents.contextWindow": "컨텍스트 창", + "agents.contextWindowTip": "모델 컨텍스트 창의 총 토큰 예산입니다.", + "agents.workspace": "워크스페이스 경로", + "agents.workspaceTip": "에이전트 파일 작업의 루트 디렉터리입니다. 사용자별 하위 디렉터리가 자동으로 생성됩니다.", + "agents.restrictToWorkspace": "워크스페이스로 제한", + "agents.restrictToWorkspaceTip": "에이전트가 워크스페이스 경로 외부의 파일을 읽거나 쓸 수 없도록 합니다.", + "agents.intentClassify": "의도 분류", + "agents.saveError": "에이전트 기본값 저장 실패", + + "agents.subagents.title": "서브에이전트", + "agents.subagents.desc": "서브에이전트 생성 제한", + "agents.subagents.maxConcurrent": "최대 동시", + "agents.subagents.maxConcurrentTip": "동시에 실행할 수 있는 서브에이전트의 최대 수입니다.", + "agents.subagents.maxSpawnDepth": "최대 생성 깊이", + "agents.subagents.maxSpawnDepthTip": "서브에이전트 체인의 최대 중첩 깊이입니다.", + "agents.subagents.maxChildrenPerAgent": "에이전트당 최대 자식", + "agents.subagents.maxChildrenPerAgentTip": "단일 에이전트가 생성할 수 있는 최대 자식 서브에이전트 수입니다.", + "agents.subagents.archiveAfterMin": "보관 시간 (분)", + "agents.subagents.archiveAfterMinTip": "서브에이전트 세션이 보관되기까지의 비활성 시간(분)입니다.", + "agents.subagents.modelOverride": "모델 재정의", + "agents.subagents.modelOverrideTip": "모든 서브에이전트가 특정 모델을 사용하도록 강제합니다. 부모 에이전트에서 상속하려면 비워두세요.", + "agents.subagents.modelOverridePlaceholder": "(에이전트에서 상속)", + + "agents.memory.title": "메모리", + "agents.memory.desc": "의미 메모리 검색 및 임베딩", + "agents.memory.enabled": "활성화됨", + "agents.memory.embeddingProvider": "임베딩 공급자", + "agents.memory.embeddingModel": "임베딩 모델", + "agents.memory.embeddingProviderTip": "메모리 저장을 위한 텍스트 임베딩 생성에 사용되는 공급자입니다.", + "agents.memory.embeddingModelTip": "임베딩 모델명입니다. 공급자 기본값을 사용하려면 비워두세요.", + "agents.memory.maxResults": "최대 결과", + "agents.memory.maxResultsTip": "회수 쿼리당 반환되는 최대 메모리 항목 수입니다.", + "agents.memory.maxChunkLen": "최대 청크 길이", + "agents.memory.maxChunkLenTip": "분할 전 메모리 청크당 최대 문자 수입니다.", + "agents.memory.chunkOverlap": "청크 겹침", + "agents.memory.chunkOverlapTip": "컨텍스트 연속성을 위한 청크 간 겹침 문자 수입니다.", + "agents.memory.minScore": "최소 점수", + "agents.memory.minScoreTip": "결과에 포함될 메모리 항목의 최소 유사도 점수 (0-1)입니다.", + + "agents.compaction.title": "압축", + "agents.compaction.desc": "컨텍스트 창 압축 설정", + "agents.compaction.reserveTokensFloor": "예약 토큰 하한", + "agents.compaction.reserveTokensFloorTip": "압축 전 새 응답을 위해 예약할 최소 토큰 버퍼입니다.", + "agents.compaction.maxHistoryShare": "최대 기록 비율 (0-1)", + "agents.compaction.maxHistoryShareTip": "대화 기록이 차지할 수 있는 컨텍스트 창의 비율입니다.", + + "agents.pruning.title": "컨텍스트 정리", + "agents.pruning.desc": "컨텍스트 공간 확보를 위해 오래된 도구 결과 제거", + "agents.pruning.mode": "모드", + "agents.pruning.keepLastAssistants": "마지막 어시스턴트 유지", + "agents.pruning.keepLastAssistantsTip": "정리 중 항상 보존할 최근 어시스턴트 턴 수입니다.", + + "agents.sandbox.title": "샌드박스", + "agents.sandbox.desc": "코드 실행을 위한 Docker 샌드박스", + "agents.sandbox.mode": "모드", + "agents.sandbox.image": "Docker 이미지", + "agents.sandbox.imageTip": "샌드박스 컨테이너에 사용되는 Docker 이미지입니다.", + "agents.sandbox.memoryMb": "메모리 (MB)", + "agents.sandbox.memoryMbTip": "샌드박스 컨테이너의 메모리 제한(메가바이트)입니다.", + "agents.sandbox.cpus": "CPU", + "agents.sandbox.cpusTip": "샌드박스 컨테이너의 CPU 할당량 (예: 1.0 = 코어 하나).", + "agents.sandbox.timeoutSec": "타임아웃 (초)", + "agents.sandbox.timeoutSecTip": "샌드박스가 종료되기 전 최대 실행 시간(초)입니다.", + "agents.sandbox.networkEnabled": "네트워크 활성화됨", + + "behavior.uxTitle": "UX 동작", + "behavior.uxDescription": "게이트웨이가 사용자와 상호작용하는 방식을 변경하는 주요 토글", + "behavior.toolStatusHint": "에이전트 실행 중 사용자에게 실시간 도구 실행 상태 메시지를 표시합니다.", + "behavior.toolStatusInfo": "에이전트가 파일을 읽고, 명령을 실행하고, API를 호출하는 동안 사용자에게 라이브 업데이트가 표시됩니다.", + "behavior.blockReplyHint": "도구가 호출되는 동안 채널에 부분 어시스턴트 텍스트를 전송합니다.", + "behavior.blockReplyInfo": "도구 실행 중 사용자에게 중간 텍스트가 전달됩니다. 최종 응답만이 아닙니다.", + "behavior.intentClassifyHint": "불필요한 에이전트 호출을 줄이기 위해 라우팅 전에 사용자 의도를 분류합니다.", + "behavior.intentClassifyInfo": "에이전트는 분류기가 실행 가능한 의도를 감지할 때만 호출됩니다.", + "behavior.pendingCompactionTitle": "대기 메시지 압축", + "behavior.pendingCompactionDescription": "버퍼가 임계값을 초과할 때 LLM을 사용하여 이전 그룹 메시지를 자동으로 요약합니다", + "behavior.pendingCompactionThreshold": "임계값", + "behavior.pendingCompactionThresholdTip": "그룹에 이 수보다 많은 대기 메시지가 누적되면 압축을 트리거합니다. 기본값(50)을 사용하려면 0으로 설정하세요.", + "behavior.pendingCompactionKeepRecent": "최근 유지", + "behavior.pendingCompactionKeepRecentTip": "압축 후 유지할 최근 원본 메시지 수입니다. 오래된 메시지는 LLM 요약으로 대체됩니다. 기본값은 15입니다.", + "behavior.pendingCompactionMaxTokens": "최대 토큰", + "behavior.pendingCompactionMaxTokensTip": "LLM 요약의 최대 출력 토큰입니다. 기본값은 4096입니다.", + "behavior.pendingCompactionProvider": "공급자", + "behavior.pendingCompactionProviderTip": "요약을 위한 LLM 공급자입니다. 채널 에이전트의 공급자를 사용하려면 비워두세요.", + "behavior.pendingCompactionProviderPlaceholder": "에이전트 공급자 사용", + "behavior.pendingCompactionModel": "모델", + "behavior.pendingCompactionModelTip": "요약을 위한 모델입니다. 채널 에이전트의 모델을 사용하려면 비워두세요.", + "behavior.pendingCompactionModelPlaceholder": "에이전트 모델 사용", + "behavior.pendingCompactionInfo": "그룹 채팅이 임계값을 초과하면 LLM이 오래된 메시지를 단일 압축 항목으로 자동 요약하여 컨텍스트를 위해 가장 최근 메시지를 유지합니다.", + "behavior.rateLimitTitle": "속도 제한", + "behavior.rateLimitDescription": "인바운드 메시지 크기 제한 및 사용자당 요청 쓰로틀링", + "behavior.sessionsTitle": "세션 범위", + "behavior.sessionsDescription": "사용자와 채널 간에 대화 컨텍스트가 분할되는 방식을 제어합니다", + "behavior.securityTitle": "입력 보안", + "behavior.securityDescription": "게이트웨이를 보호하기 위한 프롬프트 주입 감지 및 자격증명 스크러빙", + "behavior.injectionActionHint": "인바운드 메시지에서 프롬프트 주입 시도가 감지될 때 수행할 작업입니다.", + "behavior.injectionBlockInfo": "주입 시도로 표시된 모든 메시지는 차단되고 사용자에게 알림이 전송됩니다.", + "behavior.injectionOffInfo": "주입 감지가 비활성화되어 있습니다. 악의적인 프롬프트는 필터링되지 않습니다.", + "behavior.scrubCredentialsHint": "에이전트에 반환하기 전에 도구 출력에서 발견된 API 키, 토큰 및 비밀번호를 자동으로 수정합니다.", + "behavior.scrubCredentialsInfo": "도구 응답의 자격증명 패턴은 에이전트가 보기 전에 마스킹됩니다.", + "behavior.scrubCredentialsOffInfo": "자격증명 스크러빙이 비활성화되어 있습니다. 도구 출력의 시크릿이 에이전트에 노출될 수 있습니다.", + + "sessions.scope": "세션 범위", + "sessions.scopeTip": "세션 분할 방법을 결정합니다. '발신자별'은 각 사용자에게 별도 세션을 제공하고, '전역'은 모든 사용자가 하나의 세션을 공유합니다.", + "sessions.dmScope": "DM 범위", + "sessions.dmScopeTip": "DM 세션이 키로 구분되는 방법입니다. '채널 피어별'이 권장 기본값입니다.", + + "quota.title": "사용 할당량", + "quota.description": "선택적 공급자, 채널 및 그룹별 재정의가 있는 사용자별 메시지 할당량 제한", + "quota.enabled": "할당량 활성화", + "quota.enabledTip": "활성화 시 사용자는 아래에 정의된 메시지 수로 제한됩니다.", + "quota.defaultLimits": "기본 제한", + "quota.defaultLimitsTip": "특정 재정의가 적용되지 않는 모든 사용자에 적용되는 폴백 할당량입니다.", + "quota.hour": "시간당", + "quota.hourTip": "시간당 허용되는 최대 메시지 수입니다.", + "quota.day": "일당", + "quota.dayTip": "일당 허용되는 최대 메시지 수입니다.", + "quota.week": "주당", + "quota.weekTip": "주당 허용되는 최대 메시지 수입니다.", + "quota.keyLabel": "키", + "quota.addOverride": "재정의 추가", + "quota.allOptionsAdded": "모든 옵션이 이미 추가됨", + "quota.providerOverrides": "공급자 재정의", + "quota.providerOverridesTip": "LLM 공급자별 커스텀 할당량 제한입니다. 사용자가 특정 공급자를 통해 상호작용할 때 기본값을 재정의합니다.", + "quota.channelOverrides": "채널 재정의", + "quota.channelOverridesTip": "채널 유형별 커스텀 할당량 제한 (예: telegram, discord).", + "quota.groupOverrides": "그룹 재정의", + "quota.groupOverridesTip": "특정 그룹 채팅에 대한 커스텀 할당량 제한입니다.", + "quota.selectProvider": "공급자 선택", + "quota.selectChannel": "채널 선택", + "quota.selectGroup": "그룹 선택", + + "tools.title": "도구 프로파일", + "tools.description": "모든 에이전트에 대한 기본 도구 가용성 및 시간당 호출 속도 제한", + "tools.profile": "프로파일", + "tools.profileTip": "사전 정의된 도구 세트입니다. '최소'는 안전한 읽기 전용 도구만 노출하고, '전체'는 모든 도구를 활성화합니다.", + "tools.profilePlaceholder": "프로파일 선택...", + "tools.rateLimitPerHour": "속도 제한 (시간당)", + "tools.rateLimitPerHourTip": "에이전트당 시간당 허용되는 최대 도구 호출 수입니다. 비활성화하려면 0으로 설정하세요.", + "tools.allow": "허용", + "tools.allowTip": "선택된 프로파일에 포함되지 않은 추가 도구를 명시적으로 허용합니다.", + "tools.allowPlaceholder": "허용할 도구 선택...", + "tools.deny": "차단", + "tools.denyTip": "선택된 프로파일에 포함되어 있어도 도구를 명시적으로 차단합니다.", + "tools.denyPlaceholder": "차단할 도구 선택...", + "tools.alsoAllow": "추가 허용", + "tools.alsoAllowTip": "프로파일 위에 추가로 허용할 도구입니다. 제한적인 프로파일을 사용할 때 유용합니다.", + "tools.alsoAllowPlaceholder": "추가 도구 선택...", + "tools.execApproval": "명령 실행", + "tools.execSecurity": "보안 모드", + "tools.execSecurityTip": "에이전트가 실행할 수 있는 셸 명령을 제어합니다. '허용 목록'은 승인된 패턴으로 제한합니다.", + "tools.execAskMode": "요청 모드", + "tools.execAskModeTip": "명령 실행 전에 사용자 승인을 요청할 시기입니다.", + "tools.execAllowlistLabel": "허용된 명령 (줄당 하나의 패턴)", + "tools.webSearch": "웹 검색", + "tools.webFetch": "웹 가져오기 및 브라우저 자동화", + "tools.maxResults": "최대 결과", + "tools.braveApiKey": "API 키", + "tools.braveApiKeyTip": "Brave 검색을 사용하려면 필요합니다. https://brave.com/search/api/에서 키를 생성하세요.", + "tools.braveApiKeyPlaceholder": "BSA…", + "tools.braveApiKeyManaged": "서버에 이미 키가 저장되어 있으며 여기서 표시할 수 없습니다.", + "tools.webFetchPolicy": "웹 가져오기 정책", + "tools.webFetchPolicyTip": "에이전트가 가져올 수 있는 URL을 제어합니다. '허용 목록'은 승인된 도메인으로만 제한합니다.", + "tools.allowedDomains": "허용된 도메인", + "tools.blockedDomains": "차단된 도메인", + "tools.blockedDomainsTip": "정책에 관계없이 항상 차단되는 도메인입니다. 줄당 하나씩, 와일드카드 지원 (*.example.com).", + "tools.browser": "브라우저 자동화", + "tools.browserEnabled": "활성화됨", + "tools.browserHeadless": "헤드리스", + "tools.scrubCredentials": "자격증명 스크러빙", + + "tts.title": "텍스트 음성 변환", + "tts.configured": "설정됨", + "tts.disabled": "비활성화됨", + "tts.providerInfo": "공급자: {{provider}} — 자동: {{auto}}", + "tts.noProvider": "TTS 공급자가 설정되지 않았습니다.", + "tts.manageLink": "TTS 설정 관리", + + "cron.title": "Cron 스케줄러", + "cron.description": "실패한 예약 작업의 재시도 동작", + "cron.maxRetries": "최대 재시도", + "cron.maxRetriesTip": "실패한 cron 태스크의 최대 재시도 횟수입니다.", + "cron.baseDelay": "기본 지연", + "cron.baseDelayTip": "재시도 간 초기 백오프 지연입니다 (예: 2s, 500ms).", + "cron.maxDelay": "최대 지연", + "cron.maxDelayTip": "재시도 간 최대 백오프 지연입니다 (예: 30s, 5m).", + "cron.defaultTimezone": "기본 시간대", + "cron.defaultTimezoneTip": "작업별로 설정되지 않은 경우 cron 표현식의 IANA 시간대입니다 (예: Asia/Seoul). 서버 시스템 시간대를 사용하려면 비워두세요.", + "cron.defaultTimezonePlaceholder": "시스템 시간대", + + "telemetry.title": "텔레메트리 (OpenTelemetry)", + "telemetry.description": "OpenTelemetry 호환 백엔드로 추적 및 메트릭 내보내기", + "telemetry.enabled": "활성화됨", + "telemetry.enabledTip": "OpenTelemetry 추적 내보내기를 활성화합니다. 'otel' 빌드 태그가 필요합니다.", + "telemetry.endpoint": "엔드포인트", + "telemetry.endpointTip": "OTLP 내보내기 엔드포인트 (host:port). gRPC 기본값은 4317, HTTP는 4318입니다.", + "telemetry.protocol": "프로토콜", + "telemetry.protocolTip": "OTLP 내보내기의 전송 프로토콜입니다.", + "telemetry.serviceName": "서비스 이름", + "telemetry.serviceNameTip": "추적에 보고되는 서비스 이름입니다. 관찰 가능성 백엔드에서 필터링할 때 유용합니다.", + "telemetry.insecure": "비보안", + "telemetry.insecureTip": "OTLP 연결의 TLS를 비활성화합니다. 로컬/개발 환경에서만 사용하세요.", + "telemetry.headers": "내보내기 헤더", + "telemetry.headersTip": "각 OTLP 내보내기 요청과 함께 전송되는 추가 HTTP 헤더입니다 (예: 호스팅 백엔드의 API 키).", + "telemetry.headerKeyPlaceholder": "헤더 이름", + "telemetry.headerValuePlaceholder": "헤더 값", + "telemetry.addHeader": "헤더 추가", + + "bindings.title": "에이전트 바인딩", + "bindings.description": "특정 채널, 피어 또는 계정을 지정된 에이전트로 라우팅합니다", + "bindings.add": "바인딩 추가", + "bindings.noBindings": "바인딩이 설정되지 않았습니다. 모든 메시지는 기본 에이전트로 라우팅됩니다.", + "bindings.agentId": "에이전트 ID", + "bindings.channel": "채널", + "bindings.peerKind": "피어 종류", + "bindings.peerId": "피어 ID", + + "providers.title": "공급자 API 키", + "providers.description": "설정된 LLM 공급자의 API 키와 기본 URL을 재정의합니다", + "providers.noProviders": "설정 파일에서 공급자를 찾을 수 없습니다.", + "providers.apiKey": "API 키", + "providers.apiBaseUrl": "기본 URL", + "providers.apiBaseUrlPlaceholder": "https://api.example.com/v1", + "providers.managedVia": "{{envKey}} 환경 변수를 통해 관리됩니다.", + + "channels.title": "채널 설정", + "channels.description": "내장 채널 통합 설정 (토큰, 정책, 스트리밍)", + "channels.noChannels": "설정 파일에서 채널을 찾을 수 없습니다.", + "channels.enabled": "활성화됨", + "channels.token": "토큰 / 시크릿", + "channels.managedVia": "{{envKey}} 환경 변수를 통해 관리됩니다.", + "channels.dmPolicy": "DM 정책", + "channels.groupPolicy": "그룹 정책", + "channels.allowFrom": "허용 출처", + "channels.allowFromPlaceholder": "user_id_1, user_id_2, ...", + "channels.dmStreaming": "DM 스트리밍", + "channels.dmStreamingHint": "DM에서 점진적 메시지 업데이트", + "channels.groupStreaming": "그룹 스트리밍", + "channels.groupStreamingHint": "그룹에서 점진적 메시지 업데이트", + "channels.streaming": "스트리밍", + "channels.draftTransport": "임시 미리보기", + "channels.draftTransportHint": "DM에서 스텔스 스트리밍 미리보기 (편집당 알림 없음)", + "channels.reasoningStream": "추론 표시", + "channels.reasoningStreamHint": "AI 사고 과정을 별도 메시지로 표시", + "channels.reactionLevel": "반응 수준", + "channels.connectionMode": "연결 모드", + "channels.reactionOff": "끄기", + "channels.reactionMinimal": "최소", + "channels.reactionFull": "전체", + "channels.connectionWebsocket": "WebSocket", + "channels.connectionWebhook": "웹훅", + + "bindings.any": "모두", + + "toast": { + "saved": "설정 저장됨", + "saveFailed": "설정 저장 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/contacts.json b/ui/web/src/i18n/locales/ko/contacts.json new file mode 100644 index 00000000..2d5e9c54 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/contacts.json @@ -0,0 +1,58 @@ +{ + "title": "연락처", + "description": "모든 채널 상호작용에서 자동으로 수집된 연락처.", + "searchPlaceholder": "이름, 사용자명 또는 ID로 검색...", + "filter": "필터", + "emptyTitle": "연락처 없음", + "emptyDescription": "사용자가 채널을 통해 에이전트와 상호작용하면 여기에 연락처가 나타납니다.", + "noMatchTitle": "일치하는 연락처 없음", + "noMatchDescription": "다른 검색어나 필터를 사용해 보세요.", + "columns": { + "name": "이름", + "username": "사용자명", + "senderId": "발신자 ID", + "channelType": "채널", + "peerKind": "유형", + "lastSeen": "마지막 접속", + "merged": "병합됨" + }, + "permissionsNote": { + "title": "연락처 이름에 대한 채널 권한", + "telegram": "Telegram — 이름과 사용자명이 자동으로 제공됩니다.", + "discord": "Discord — 표시 이름과 사용자명이 자동으로 제공됩니다.", + "zalo": "Zalo — 표시 이름이 자동으로 제공됩니다.", + "slack": "Slack — Slack API를 통해 표시 이름이 해석됩니다 (봇이 워크스페이스에 있어야 함).", + "feishu": "Feishu/Lark — contact:user.base:readonly 권한이 필요합니다. 없으면 이름이 비어 있습니다." + }, + "selectedCount": "{{count}}개 선택됨", + "merge": { + "button": "병합", + "unmergeButton": "병합 해제", + "dialogTitle": "연락처 병합", + "dialogDescription": "선택한 연락처를 테넌트 사용자 신원에 연결합니다. 이를 통해 여러 채널에서 동일한 사람으로 식별됩니다.", + "linkExisting": "기존 사용자에 연결", + "createNew": "새 사용자 만들기", + "selectUser": "테넌트 사용자 선택...", + "displayName": "표시 이름", + "displayNamePlaceholder": "예: 홍길동", + "userId": "사용자 ID", + "userIdPlaceholder": "고유 식별자", + "confirm": "병합", + "cancel": "취소", + "success": "연락처가 성공적으로 병합되었습니다", + "unmergeSuccess": "연락처 병합이 성공적으로 해제되었습니다", + "error": "연락처 병합 실패", + "unmergeError": "연락처 병합 해제 실패", + "comingSoon": "이 기능은 개발 중이며 아직 사용할 수 없습니다." + }, + "types": { + "user": "사용자", + "group": "그룹" + }, + "filters": { + "allChannels": "모든 채널", + "allTypes": "모든 유형", + "direct": "직접", + "group": "그룹" + } +} diff --git a/ui/web/src/i18n/locales/ko/cron.json b/ui/web/src/i18n/locales/ko/cron.json new file mode 100644 index 00000000..1cf17e0d --- /dev/null +++ b/ui/web/src/i18n/locales/ko/cron.json @@ -0,0 +1,149 @@ +{ + "title": "Cron", + "description": "반복 에이전트 태스크 스케줄", + "newJob": "새 작업", + "emptyTitle": "Cron 작업 없음", + "emptyDescription": "Cron 작업을 만들어 에이전트의 반복 태스크를 스케줄하세요.", + "columns": { + "enabled": "사용", + "name": "이름", + "schedule": "스케줄", + "message": "메시지", + "agent": "에이전트", + "actions": "작업" + }, + "runNow": "지금 실행", + "running": "실행 중...", + "runHistory": "실행 기록", + "defaultAgent": "기본", + "searchPlaceholder": "Cron 작업 검색...", + "noMatchTitle": "일치하는 작업 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "card": { + "nextRun": "다음: {{time}}", + "noNextRun": "다음 실행 없음", + "defaultAgent": "기본 에이전트" + }, + "create": { + "title": "Cron 작업 만들기", + "name": "이름", + "namePlaceholder": "my-daily-task", + "nameHint": "소문자, 숫자, 하이픈만", + "agentId": "에이전트 ID (선택사항)", + "agentIdPlaceholder": "기본값", + "scheduleType": "스케줄 유형", + "every": "반복", + "cron": "Cron", + "once": "한 번", + "intervalSeconds": "간격 (초)", + "cronExpression": "Cron 표현식", + "cronHint": "표준 5자리 cron: 분 시 일 월 요일", + "onceDesc": "이 작업은 지금부터 약 1분 후에 한 번 실행됩니다.", + "message": "메시지", + "messagePlaceholder": "에이전트가 무엇을 해야 하나요?", + "cancel": "취소", + "create": "만들기", + "creating": "만드는 중..." + }, + "enable": { + "title": "Cron 작업 활성화", + "description": "\"{{name}}\"을/를 활성화하시겠습니까? 스케줄에 따라 실행이 시작됩니다.", + "confirmLabel": "활성화" + }, + "disable": { + "title": "Cron 작업 비활성화", + "description": "\"{{name}}\"을/를 비활성화하시겠습니까? 다시 활성화할 때까지 실행이 중지됩니다.", + "confirmLabel": "비활성화" + }, + "delete": { + "title": "Cron 작업 삭제", + "description": "\"{{name}}\"을/를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "runLog": { + "title": "실행 로그: {{name}}", + "noHistory": "아직 실행 기록 없음.", + "loading": "불러오는 중..." + }, + "detail": { + "runNow": "지금 실행", + "running": "실행 중...", + "disable": "비활성화", + "enable": "활성화", + "delete": "삭제", + "enabled": "활성화됨", + "disabled": "비활성화됨", + "runningStatus": "실행 중...", + "payload": "페이로드", + "empty": "(비어 있음)", + "deliverDirect": "전달: 직접", + "channel": "채널: {{name}}", + "to": "대상: {{name}}", + "edit": "편집", + "preview": "미리보기", + "noMessage": "설정된 메시지 없음", + "lastError": "마지막 오류", + "runHistory": "실행 기록", + "refresh": "새로 고침", + "noHistory": "아직 실행 기록 없음.", + "inOut": "입력 {{input}} / 출력 {{output}}", + "infoRows": { + "schedule": "스케줄", + "timezone": "시간대", + "nextRun": "다음 실행", + "lastRun": "마지막 실행", + "lastStatus": "마지막 상태", + "created": "생성됨", + "updated": "업데이트됨", + "autoDelete": "자동 삭제", + "autoDeleteValue": "예 (1회)" + }, + "tabs": { + "overview": "개요", + "history": "실행 기록" + }, + "advanced": "고급", + "saveFailed": "저장 실패", + "schedule": "스케줄", + "scheduleDesc": "타이밍 설정", + "messageSection": "메시지", + "messageSectionDesc": "에이전트가 해야 할 일", + "agentStatus": "에이전트 & 상태", + "agentStatusDesc": "에이전트 할당 및 작업 상태", + "info": "정보", + "infoDesc": "작업 메타데이터", + "scheduling": "스케줄링", + "schedulingDesc": "시간대 설정", + "delivery": "전달", + "deliveryDesc": "작업 출력을 채널이나 사용자에게 라우팅", + "deliverToChannel": "채널로 전달", + "channelLabel": "채널", + "channelPlaceholder": "#general", + "toLabel": "대상 (사용자)", + "toPlaceholder": "user-id", + "wakeHeartbeat": "실행 시 하트비트 깨우기", + "wakeHeartbeatDesc": "작업 실행 시 에이전트 하트비트 트리거", + "lifecycle": "라이프사이클", + "lifecycleDesc": "작업 라이프사이클 설정", + "deleteAfterRun": "실행 후 삭제", + "deleteAfterRunDesc": "첫 번째 성공적인 실행 후 이 작업 자동 삭제", + "timezone": "시간대", + "timezoneDesc": "Cron 표현식의 시간대" + }, + "stateless": "상태 없음", + "statelessHelp": "세션 지속성 건너뜁니다. 각 실행은 이전 메시지 없이 새로 시작됩니다. 이전 컨텍스트가 필요 없는 cron의 토큰을 절약합니다.", + "toast": { + "created": "Cron 작업 생성됨", + "createdDesc": "{{name}}이/가 추가되었습니다", + "enabled": "Cron 작업 활성화됨", + "disabled": "Cron 작업 비활성화됨", + "deleted": "Cron 작업 삭제됨", + "triggered": "Cron 작업 트리거됨", + "failedCreate": "Cron 작업 생성 실패", + "failedToggle": "Cron 작업 토글 실패", + "failedDelete": "Cron 작업 삭제 실패", + "failedRun": "Cron 작업 실행 실패", + "updated": "작업 업데이트됨", + "failedUpdate": "작업 업데이트 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/events.json b/ui/web/src/i18n/locales/ko/events.json new file mode 100644 index 00000000..f3dadd67 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/events.json @@ -0,0 +1,36 @@ +{ + "title": "실시간 이벤트", + "description": "모든 팀 및 에이전트의 실시간 WebSocket 이벤트", + "live": "실시간", + "paused": "일시 정지됨", + "resume": "재개", + "pause": "일시 정지", + "clear": "지우기", + "scrollToBottom": "맨 아래로 스크롤", + "eventCount": "{{count}}개 이벤트", + "eventCountPlural": "{{count}}개 이벤트", + "categories": { + "all": "전체", + "task": "태스크", + "message": "메시지", + "agent": "에이전트", + "teamCrud": "팀 CRUD", + "agentLink": "에이전트 링크" + }, + "filters": { + "allTeams": "모든 팀", + "allUsers": "모든 사용자", + "allChats": "모든 채팅" + }, + "global": "전체", + "emptyTitle": "이벤트 없음", + "emptyPaused": "이벤트 캡처가 일시 정지되었습니다. 재개하면 새 이벤트가 표시됩니다.", + "emptyWaiting": "실시간 이벤트를 기다리는 중... 에이전트가 작업하면 이벤트가 나타납니다.", + "detail": { + "copy": "복사", + "copied": "복사됨" + }, + "toolBadge": { "error": "오류", "activated": "활성화됨", "ok": "확인" }, + "moreArgs": "...{{count}}개 더", + "parentLabel": "부모:" +} diff --git a/ui/web/src/i18n/locales/ko/import-export.json b/ui/web/src/i18n/locales/ko/import-export.json new file mode 100644 index 00000000..241c324c --- /dev/null +++ b/ui/web/src/i18n/locales/ko/import-export.json @@ -0,0 +1,131 @@ +{ + "title": "가져오기 & 내보내기", + "description": "에이전트를 이식 가능한 아카이브로 내보내거나 가져옵니다.", + "beta": "베타", + "betaWarning": "가져오기 & 내보내기는 베타 버전입니다. 기존 에이전트로 가져오기 전에 항상 백업을 유지하세요.", + "tabs": { + "teams": "팀", + "agents": "에이전트", + "skillsMcp": "스킬 & MCP", + "export": "내보내기", + "import": "가져오기" + }, + "comingSoon": { + "title": "준비 중", + "description": "이 섹션은 아직 사용할 수 없습니다." + }, + "export": { + "title": "에이전트 내보내기", + "agent": "에이전트", + "agentPlaceholder": "에이전트 선택", + "sections": "섹션", + "preset": "프리셋", + "presetsLabel": "프리셋", + "infoNote": "팀과 함께 에이전트를 내보내려면 팀 탭을 사용하세요.", + "startExport": "내보내기", + "exporting": "내보내는 중...", + "preview": "미리보기", + "previewLoading": "미리보기 불러오는 중...", + "download": "다운로드", + "done": "내보내기 완료", + "errorTitle": "내보내기 실패", + "selectAgent": "내보낼 에이전트를 선택하세요.", + "noAgents": "사용 가능한 에이전트 없음." + }, + "import": { + "title": "에이전트 가져오기", + "mode": "모드", + "modeNew": "새 에이전트 만들기", + "modeMerge": "기존에 병합", + "agentKey": "에이전트 키", + "agentKeyPlaceholder": "예: my-agent", + "agentKeyHint": "소문자, 숫자, 하이픈. 비워두면 아카이브의 키를 사용합니다.", + "targetAgent": "대상 에이전트", + "targetAgentPlaceholder": "대상 에이전트 선택", + "file": "아카이브 파일 (.tar.gz)", + "filePlaceholder": "클릭하여 선택하거나 끌어다 놓기", + "sections": "병합할 섹션", + "startImport": "가져오기", + "importing": "가져오는 중...", + "done": "가져오기 완료", + "agentCreated": "에이전트 생성됨: {{key}}", + "mergedInto": "병합됨: {{key}}", + "errorTitle": "가져오기 실패", + "manifestLabel": "아카이브 정보", + "agentFrom": "아카이브의 에이전트: {{key}}", + "exportedAt": "내보내기 날짜: {{date}}" + }, + "sections": { + "config": "설정", + "configDesc": "에이전트 설정 (모델, 도구 등)", + "context_files": "컨텍스트 파일", + "context_filesDesc": "에이전트 수준 컨텍스트 파일 (SOUL.md, IDENTITY.md 등)", + "user_data": "사용자 데이터", + "user_dataDesc": "모든 사용자별 데이터 (컨텍스트 파일, 프로필, 재정의)", + "user_context_files": "사용자 컨텍스트 파일", + "user_context_filesDesc": "사용자별 컨텍스트 파일 (사용자당 USER.md)", + "user_profiles": "사용자 프로필", + "user_profilesDesc": "사용자 워크스페이스 프로필 레코드", + "user_overrides": "사용자 재정의", + "user_overridesDesc": "사용자별 모델/공급자 재정의", + "memory": "메모리", + "memoryDesc": "모든 메모리 문서 (전체 + 사용자별)", + "memory_global": "전체 메모리", + "memory_globalDesc": "공유 메모리 문서", + "memory_per_user": "사용자별 메모리", + "memory_per_userDesc": "개별 사용자 메모리 문서", + "knowledge_graph": "지식 그래프", + "knowledge_graphDesc": "KG 엔티티 및 관계", + "cron": "Cron 작업", + "cronDesc": "예약된 태스크 (비활성화 상태로 가져옴)", + "workspace": "워크스페이스 파일", + "workspaceDesc": "에이전트 워크스페이스 디렉터리 파일", + "sessions": "세션", + "sessionsDesc": "채팅 세션 및 메시지", + "media": "미디어", + "mediaDesc": "업로드된 미디어 파일", + "comingSoon": "준비 중" + }, + "presets": { + "minimal": "최소", + "standard": "표준", + "complete": "전체" + }, + "teamExportNote": "팀 내보내기에는 모든 멤버 에이전트와 해당 데이터(컨텍스트 파일, 메모리, 지식 그래프, cron, 워크스페이스)가 포함됩니다.", + "teamSelectPlaceholder": "팀 선택...", + "teamDropHere": "팀 아카이브 파일을 여기에 놓거나 클릭하여 찾아보기", + "teamDropFormats": ".tar.gz 파일 지원", + "teamDontClose": "이 페이지를 닫지 마세요 — 가져오기 진행 중", + "teamImportAnother": "다른 것 가져오기", + "teamTryAgain": "다시 시도", + "teamChangeFile": "파일 변경", + "teamPreview": { + "members": "{{count}}명 멤버", + "agents": "{{count}}개 에이전트", + "tasks": "{{count}}개 태스크", + "links": "{{count}}개 링크", + "loading": "미리보기 불러오는 중...", + "error": "미리보기 로드 실패" + }, + "skillsMcp": { + "skillsTab": "스킬", + "mcpTab": "MCP 서버", + "skillsNote": "사용자 지정 스킬만 내보냅니다 (시스템 스킬 제외).", + "mcpNote": "MCP 서버 설정은 API 키, 환경 변수, 헤더 없이 내보냅니다. 가져오기 후 시크릿을 다시 입력해야 합니다.", + "customSkills": "{{count}}개 사용자 지정 스킬", + "grants": "{{count}}개 에이전트 권한", + "servers": "{{count}}개 서버", + "noSkills": "내보낼 사용자 지정 스킬이 없습니다.", + "noServers": "내보낼 MCP 서버가 없습니다.", + "exportSkills": "스킬 내보내기", + "exportMcp": "MCP 서버 내보내기", + "importSkills": "스킬 가져오기", + "importMcp": "MCP 서버 가져오기", + "importedSkills": "스킬 가져오기 완료", + "skippedSkills": "스킬 건너뜀 (이미 존재)", + "importedServers": "서버 가져오기 완료", + "skippedServers": "서버 건너뜀 (이미 존재)", + "dropSkills": "스킬 아카이브 파일을 여기에 놓거나 클릭하여 찾아보기", + "dropMcp": "MCP 아카이브 파일을 여기에 놓거나 클릭하여 찾아보기" + } +} diff --git a/ui/web/src/i18n/locales/ko/login.json b/ui/web/src/i18n/locales/ko/login.json new file mode 100644 index 00000000..bd061b55 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/login.json @@ -0,0 +1,41 @@ +{ + "subtitle": "게이트웨이 대시보드에 로그인", + "selectTenant": "테넌트 선택", + "selectTenantDescription": "계속하려면 테넌트를 선택하세요", + "allTenantsOption": "모든 테넌트", + "allTenantsDescription": "모든 테넌트의 데이터 보기", + "noAccess": "접근 불가", + "noAccessDescription": "접근 가능한 테넌트가 없습니다. 관리자에게 문의하세요.", + "tabs": { + "token": "토큰", + "pairing": "페어링" + }, + "token": { + "userId": "사용자 ID", + "userIdPlaceholder": "your-user-id", + "userIdHint": "전체 시스템 접근은 \"system\" 사용", + "gatewayToken": "게이트웨이 토큰", + "tokenPlaceholder": "Bearer 토큰", + "connect": "연결", + "connecting": "연결 중...", + "errorInvalidCredentials": "인증 정보가 올바르지 않습니다. 토큰과 사용자 ID를 확인하세요.", + "errorServer": "서버에서 {{status}}를 반환했습니다. 다시 시도해 주세요.", + "errorCannotConnect": "게이트웨이에 연결할 수 없습니다. 서버가 실행 중인지 확인하세요." + }, + "pairing": { + "userId": "사용자 ID", + "userIdPlaceholder": "your-user-id", + "noTokenNeeded": "토큰 불필요. 관리자가 승인할 페어링 코드가 생성됩니다.", + "requestAccess": "접근 요청", + "connecting": "연결 중...", + "errorConnectionLost": "연결이 끊겼습니다. 다시 시도해 주세요.", + "errorCannotConnect": "게이트웨이에 연결할 수 없습니다.", + "askAdmin": "관리자에게 이 코드를 승인해 달라고 요청하세요:", + "orRun": "또는 실행:", + "waitingForApproval": "승인 대기 중...", + "cancel": "취소", + "approved": "접근이 승인되었습니다! 리디렉션 중..." + }, + "noAccessHint": "관리자에게 테넌트에 추가해 달라고 요청하거나 다른 계정을 사용하세요.", + "logout": "로그아웃" +} diff --git a/ui/web/src/i18n/locales/ko/logs.json b/ui/web/src/i18n/locales/ko/logs.json new file mode 100644 index 00000000..0e516d3b --- /dev/null +++ b/ui/web/src/i18n/locales/ko/logs.json @@ -0,0 +1,15 @@ +{ + "title": "로그", + "description": "실시간 로그 스트리밍", + "descriptionLive": "{{level}} 레벨 실시간 스트리밍 중", + "live": "실시간", + "start": "시작", + "stop": "정지", + "clear": "지우기", + "filterPlaceholder": "로그 필터...", + "logLevelTitle": "로그 레벨", + "emptyWaiting": "로그를 기다리는 중...", + "emptyFilter": "필터에 일치하는 로그가 없습니다.", + "emptyStart": "\"시작\"을 클릭하면 로그 스트리밍이 시작됩니다.", + "count": "{{filtered}}/{{total}}" +} diff --git a/ui/web/src/i18n/locales/ko/mcp.json b/ui/web/src/i18n/locales/ko/mcp.json new file mode 100644 index 00000000..8f6aca7c --- /dev/null +++ b/ui/web/src/i18n/locales/ko/mcp.json @@ -0,0 +1,133 @@ +{ + "title": "MCP 서버", + "description": "Model Context Protocol 서버 연결 관리", + "addServer": "서버 추가", + "searchPlaceholder": "서버 검색...", + "emptyTitle": "MCP 서버 없음", + "emptyDescription": "첫 번째 MCP 서버를 추가하여 시작하세요.", + "noMatchTitle": "일치하는 서버 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "columns": { + "name": "이름", + "transport": "전송", + "tools": "도구", + "agents": "에이전트", + "enabled": "사용", + "createdBy": "생성자", + "actions": "작업" + }, + "viewTools": "도구 보기", + "manageGrants": "권한 관리", + "reconnect": "재연결", + "delete": { + "title": "MCP 서버 삭제", + "description": "\"{{name}}\"을/를 삭제하시겠습니까? 관련된 모든 권한도 제거됩니다.", + "confirmLabel": "삭제" + }, + "form": { + "createTitle": "MCP 서버 추가", + "editTitle": "MCP 서버 편집", + "name": "이름 *", + "nameHint": "소문자, 숫자, 하이픈만", + "displayName": "표시 이름", + "displayNamePlaceholder": "My MCP Server", + "transport": "전송 *", + "command": "명령 *", + "args": "인수 (공백으로 구분)", + "argsPlaceholder": "--flag1 --flag2=\"값에 공백 포함\"", + "url": "URL *", + "headers": "헤더", + "headerKeyPlaceholder": "헤더 이름", + "headerValuePlaceholder": "헤더 값", + "addHeader": "헤더 추가", + "env": "환경 변수", + "envKeyPlaceholder": "변수 이름", + "envValuePlaceholder": "값", + "addVariable": "변수 추가", + "toolPrefix": "도구 접두사", + "toolPrefixHint": "비어 있으면 이름에서 자동으로 파생됩니다.", + "timeout": "제한 시간 (초)", + "enabled": "사용", + "testConnection": "연결 테스트", + "testing": "테스트 중...", + "toolsFound": "{{count}}개 도구 발견", + "cancel": "취소", + "create": "만들기", + "update": "업데이트", + "saving": "저장 중...", + "errors": { + "nameRequired": "이름과 전송이 필요합니다", + "nameSlug": "이름은 유효한 슬러그여야 합니다 (소문자, 숫자, 하이픈만)", + "commandRequired": "stdio 전송에는 명령이 필요합니다", + "urlRequired": "SSE/HTTP 전송에는 URL이 필요합니다", + "connectionFailed": "연결 실패" + }, + "requireUserCredentials": "사용자 자격 증명 필요", + "requireUserCredentialsHint": "각 사용자가 자신의 자격 증명을 설정해야 합니다. 개인 자격 증명이 없는 사용자는 서버를 사용할 수 없습니다." + }, + "grants": { + "title": "에이전트 권한 - {{name}}", + "currentGrants": "현재 권한", + "allToolsAllowed": "모든 도구 허용됨", + "addGrant": "에이전트 권한 추가", + "editGrant": "권한 편집", + "selectAgent": "에이전트 선택...", + "toolAllowList": "도구 허용 목록 (선택사항)", + "toolDenyList": "도구 거부 목록 (선택사항)", + "allowPlaceholder": "허용할 도구 선택...", + "denyPlaceholder": "거부할 도구 선택...", + "grant": "권한 부여", + "update": "업데이트", + "cancel": "취소", + "agentRequired": "에이전트가 필요합니다", + "failedGrant": "권한 부여 실패", + "failedRevoke": "권한 취소 실패" + }, + "tools": { + "title": "도구 — {{name}}", + "prefix": "접두사:", + "discovering": "도구 발견 중...", + "noToolsTitle": "발견된 도구 없음", + "noToolsDescription": "서버가 오프라인이거나 등록된 도구가 없습니다.", + "failedLoad": "도구 로드 실패", + "filterPlaceholder": "도구 필터...", + "noMatch": "일치하는 도구 없음" + }, + "toast": { + "created": "MCP 서버 생성됨", + "updated": "MCP 서버 업데이트됨", + "deleted": "MCP 서버 삭제됨", + "failedCreate": "MCP 서버 생성 실패", + "failedUpdate": "MCP 서버 업데이트 실패", + "failedDelete": "MCP 서버 삭제 실패", + "reconnected": "MCP 서버 연결 초기화됨", + "failedReconnect": "MCP 서버 재연결 실패" + }, + "userCredentials": { + "title": "내 자격 증명", + "description": "이 MCP 서버에 대한 개인 자격 증명을 설정하세요. 내 계정에 대해서만 서버 기본값을 재정의합니다.", + "titleAdmin": "사용자 자격 증명", + "descriptionAdmin": "이 MCP 서버에서 특정 사용자의 자격 증명을 설정합니다. 선택한 사용자에 대해서만 서버 기본값을 재정의합니다.", + "selectUser": "사용자 선택", + "apiKey": "API 키", + "apiKeyPlaceholder": "현재 유지하려면 비워두기", + "headers": "헤더", + "env": "환경 변수", + "headerPlaceholder": "KEY=VALUE, 줄당 하나", + "save": "저장", + "delete": "삭제", + "deleteAll": "전체 삭제", + "cancel": "취소", + "saved": "자격 증명 저장됨", + "deleted": "자격 증명 삭제됨", + "hasApiKey": "API 키 설정됨", + "hasHeaders": "헤더 설정됨", + "hasEnv": "환경 변수 설정됨", + "noCredentials": "설정된 자격 증명 없음", + "addHeader": "헤더 추가", + "addEnv": "변수 추가", + "saveFailed": "자격 증명 저장 실패", + "deleteFailed": "자격 증명 삭제 실패", + "mergeHint": "채팅 사용자(Telegram, Discord 등)는 연락처 페이지를 통해 먼저 테넌트 사용자로 병합되어야 사용자별 자격 증명을 가질 수 있습니다." + } +} diff --git a/ui/web/src/i18n/locales/ko/memory.json b/ui/web/src/i18n/locales/ko/memory.json new file mode 100644 index 00000000..95db9966 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/memory.json @@ -0,0 +1,239 @@ +{ + "title": "메모리", + "description": "에이전트 메모리 문서, 청크, 임베딩 탐색 및 관리", + "search": "검색", + "create": "만들기", + "indexAll": "전체 인덱싱", + "indexing": "인덱싱 중...", + "emptyTitle": "메모리 문서 없음", + "emptyAgentDescription": "이 에이전트에는 아직 메모리 문서가 없습니다.", + "emptyGlobalDescription": "모든 에이전트에서 메모리 문서를 찾을 수 없습니다.", + "filters": { + "agent": "에이전트", + "allAgents": "모든 에이전트", + "scope": "범위", + "allScope": "전체 (전체 + 개인)", + "selectAgent": "에이전트 선택" + }, + "tabs": { + "documents": "문서", + "knowledgeGraph": "지식 그래프" + }, + "columns": { + "path": "경로", + "agent": "에이전트", + "scope": "범위", + "hash": "해시", + "updated": "업데이트됨", + "actions": "작업" + }, + "scopeLabel": { + "personal": "개인", + "global": "전체" + }, + "delete": { + "title": "메모리 문서 삭제", + "description": "\"{{path}}\"를 삭제하시겠습니까? 관련된 모든 청크와 임베딩도 삭제됩니다.", + "confirmLabel": "삭제" + }, + "createDialog": { + "title": "메모리 문서 만들기", + "path": "경로 *", + "pathPlaceholder": "예: notes/project-overview.md", + "content": "내용 *", + "contentPlaceholder": "문서 내용...", + "agentId": "에이전트 *", + "agentIdPlaceholder": "에이전트 선택...", + "scope": "범위", + "existingScope": "기존 범위", + "customScope": "사용자 지정", + "selectGroupUser": "그룹/사용자 선택...", + "scopeHint": "전체 = 모든 사용자 공유. 개인 = 특정 사용자 또는 그룹 채팅으로 범위 지정.", + "autoIndex": "생성 후 자동 인덱싱", + "agentRequired": "에이전트를 선택해 주세요", + "pathRequired": "경로가 필요합니다", + "contentRequired": "내용이 필요합니다", + "cancel": "취소", + "create": "만들기", + "creating": "만드는 중..." + }, + "documentDialog": { + "title": "메모리 문서", + "path": "경로:", + "agent": "에이전트:", + "scope": "범위:", + "hash": "해시:", + "updated": "업데이트됨:", + "content": "내용", + "chunks": "청크 ({{count}}개)", + "chunkIndex": "청크 {{index}}", + "noChunks": "청크 없음", + "embedded": "임베딩됨", + "noEmbedding": "임베딩 없음" + }, + "searchDialog": { + "title": "메모리 검색", + "query": "검색어", + "queryPlaceholder": "검색어 입력...", + "agentId": "에이전트 ID", + "agentIdPlaceholder": "에이전트로 필터...", + "limit": "제한", + "search": "검색", + "searching": "검색 중...", + "results": "결과", + "noResults": "결과 없음", + "similarity": "유사도", + "path": "경로:" + }, + "kg": { + "pageTitle": "지식 그래프", + "pageDescription": "에이전트 메모리에서 추출된 엔티티와 관계를 탐색합니다.", + "selectAgentTitle": "에이전트 선택", + "selectAgentDescription": "에이전트를 선택하면 지식 그래프를 볼 수 있습니다.", + "emptyTitle": "엔티티 없음", + "emptyDescription": "이 에이전트의 지식 그래프 엔티티가 아직 없습니다.", + "emptySearchDescription": "검색에 일치하는 엔티티가 없습니다.", + "stats": { + "entities": "엔티티: {{count}}개", + "relations": "관계: {{count}}개" + }, + "search": { + "placeholder": "엔티티 검색...", + "button": "검색", + "clear": "지우기" + }, + "refresh": "새로 고침", + "extract": "추출", + "columns": { + "name": "이름", + "type": "유형", + "description": "설명", + "confidence": "신뢰도", + "actions": "작업", + "observations": "관찰", + "relations": "관계" + }, + "dedup": { + "button": "중복 제거", + "title": "중복 엔티티", + "description": "임베딩 유사도를 기반으로 중복 가능성이 있는 엔티티를 검토하고 병합합니다.", + "noCandidates": "중복 후보를 찾을 수 없습니다.", + "similar": "유사함", + "merge": "병합", + "dismiss": "무시", + "merged": "엔티티가 성공적으로 병합되었습니다.", + "mergeFailed": "엔티티 병합 실패.", + "dismissed": "후보가 무시되었습니다.", + "dismissFailed": "후보 무시 실패.", + "scan": "전체 검사", + "scanning": "검사 중...", + "scanComplete": "검사 완료.", + "scanFailed": "검사 실패.", + "count": "{{count}}개 후보" + }, + "deleteEntity": { + "title": "엔티티 삭제", + "description": "\"{{name}}\"을/를 삭제하시겠습니까? 관련된 모든 관계도 삭제됩니다.", + "confirmLabel": "삭제" + }, + "entity": { + "externalId": "외부 ID:", + "confidence": "신뢰도:", + "description": "설명:", + "source": "출처:", + "properties": "속성:", + "relations": "관계", + "traverse": "순회", + "depthOption": "{{depth}}홉", + "tabs": { + "table": "테이블", + "graph": "그래프" + }, + "traversing": "순회 중...", + "loading": "불러오는 중...", + "noRelations": "관계가 없습니다.", + "showAll": "전체 보기", + "traversalResults": "순회 결과 ({{count}}개)", + "direction": { + "outgoing": "→ 나가는", + "incoming": "← 들어오는" + }, + "columns": { + "direction": "방향", + "relation": "관계", + "target": "대상", + "confidence": "신뢰도" + } + }, + "extractDialog": { + "title": "텍스트에서 엔티티 추출", + "providerLabel": "추출 공급자", + "modelLabel": "추출 모델", + "textLabel": "추출할 텍스트", + "textPlaceholder": "엔티티와 관계를 추출할 대화 텍스트, 메모 또는 내용을 붙여넣기...", + "extract": "추출", + "extracting": "추출 중...", + "cancel": "취소", + "agentId": "에이전트 ID", + "agentIdPlaceholder": "전체는 비워두기" + }, + "graphView": { + "loading": "그래프 불러오는 중...", + "empty": "시각화할 엔티티 없음", + "nodes": "{{count}}개 노드", + "edges": "{{count}}개 엣지", + "selected": "선택됨: {{name}}", + "limitNote": "전체 {{total}}개 중 상위 {{limit}}개 표시", + "limitHint": "성능을 위해 그래프는 {{limit}}개 엔티티로 제한됩니다. 전체 {{total}}개 엔티티를 탐색하려면 테이블 보기를 사용하세요." + } + }, + "toast": { + "created": "메모리 문서 생성됨", + "deleted": "메모리 문서 삭제됨", + "indexed": "모든 문서 인덱싱됨", + "failedCreate": "문서 생성 실패", + "failedDelete": "문서 삭제 실패", + "failedIndex": "문서 인덱싱 실패", + "entitySaved": "엔티티 저장됨", + "entitySaveFailed": "엔티티 저장 실패", + "entityDeleted": "엔티티 삭제됨", + "entityDeleteFailed": "엔티티 삭제 실패", + "extractionComplete": "추출 완료", + "extractionFailed": "추출 실패", + "traversalFailed": "순회 실패", + "unknownError": "알 수 없는 오류", + "docCreated": "문서 생성됨", + "docCreateFailed": "문서 생성 실패", + "docUpdated": "문서 업데이트됨", + "docUpdateFailed": "문서 업데이트 실패", + "docDeleted": "문서 삭제됨", + "docDeleteFailed": "문서 삭제 실패", + "docIndexed": "문서 인덱싱됨", + "docIndexFailed": "문서 인덱싱 실패", + "allIndexed": "모든 문서 인덱싱됨", + "allIndexFailed": "전체 인덱싱 실패", + "searchFailed": "검색 실패", + "docLoadFailed": "문서 로드 실패" + }, + "tabs": { + "documents": "문서", + "episodic": "에피소딕 메모리" + }, + "episodic": { + "noData": "아직 에피소딕 메모리 없음", + "noDataHint": "요약은 에이전트 세션에서 자동으로 생성됩니다", + "selectAgent": "에피소딕 메모리를 보려면 에이전트를 선택하세요", + "searchPlaceholder": "에피소딕 메모리 검색...", + "clearSearch": "지우기", + "results": "결과", + "turns": "턴", + "tokens": "토큰", + "expand": "전체 요약 보기", + "collapse": "요약 숨기기", + "source": { + "session": "세션", + "v2_daily": "일별", + "manual": "수동" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/nodes.json b/ui/web/src/i18n/locales/ko/nodes.json new file mode 100644 index 00000000..fe3d221b --- /dev/null +++ b/ui/web/src/i18n/locales/ko/nodes.json @@ -0,0 +1,35 @@ +{ + "title": "노드", + "description": "페어링된 기기 및 대기 중인 페어링 요청 관리", + "emptyTitle": "기기 없음", + "emptyDescription": "페어링된 기기 또는 대기 중인 페어링 요청이 없습니다.", + "pendingRequests": "대기 중인 요청 ({{count}}개)", + "pairedDevices": "페어링된 기기 ({{count}}개)", + "sender": "발신자:", + "chat": "채팅:", + "columns": { + "channel": "채널", + "senderId": "발신자 ID", + "paired": "페어링됨", + "by": "처리자", + "actions": "작업" + }, + "approve": "승인", + "deny": "거부", + "revoke": "취소", + "confirmApprove": { + "title": "페어링 승인", + "description": "{{channel}}:{{senderId}}의 페어링 요청을 승인하시겠습니까 (코드: {{code}})? 이 기기가 에이전트와 상호작용할 수 있게 됩니다.", + "confirmLabel": "승인" + }, + "confirmDeny": { + "title": "페어링 거부", + "description": "{{channel}}:{{senderId}}의 페어링 요청을 거부하시겠습니까 (코드: {{code}})? 요청이 제거됩니다.", + "confirmLabel": "거부" + }, + "confirmRevoke": { + "title": "기기 취소", + "description": "{{channel}}:{{senderId}}의 페어링을 취소하시겠습니까? 기기는 다시 페어링해야 합니다.", + "confirmLabel": "취소" + } +} diff --git a/ui/web/src/i18n/locales/ko/overview.json b/ui/web/src/i18n/locales/ko/overview.json new file mode 100644 index 00000000..67cf1868 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/overview.json @@ -0,0 +1,93 @@ +{ + "title": "대시보드", + "description": "게이트웨이 개요 및 할당량 사용량", + "tabs": { + "overview": "개요", + "usage": "사용량" + }, + "statCards": { + "requestsToday": "오늘 요청", + "tokensToday": "오늘 토큰", + "costToday": "오늘 비용", + "agents": "에이전트", + "channels": "채널", + "channelsAttention": "{{count}}개 주의 필요", + "running": "실행 중", + "online": "온라인", + "users": "{{count}}명 사용자", + "inOut": "{{input}} in / {{output}} out" + }, + "providers": { + "noProvidersTitle": "설정된 LLM 공급자 없음", + "noEnabledTitle": "활성화된 LLM 공급자 없음", + "noProvidersDesc": "에이전트가 작동하려면 LLM 공급자를 최소 한 개 추가해야 합니다. ", + "noEnabledDesc": "모든 공급자가 현재 비활성화되어 있습니다. 에이전트를 사용하려면 최소 한 개를 활성화하세요. ", + "goToSettings": "공급자 설정으로 이동" + }, + "systemHealth": { + "title": "시스템 상태", + "uptime": "업타임", + "version": "버전", + "database": "데이터베이스", + "providers": "공급자", + "tools": "도구", + "sessions": "세션", + "clients": "클라이언트", + "channels": "채널", + "needsAttention": "주의 필요", + "channelsNeedingAttention": "{{count}}개 채널", + "failedCount": "{{count}}개 실패", + "warningCountOne": "{{count}}개 경고", + "warningCountOther": "{{count}}개 경고", + "moreAttention": "+{{count}}개 더", + "active": "{{count}}개 활성", + "none": "없음", + "runtimes": "런타임" + }, + "connectedClients": { + "title": "연결된 클라이언트", + "noClients": "연결된 클라이언트 없음", + "columns": { + "ip": "IP", + "user": "사용자", + "role": "역할", + "connected": "연결됨" + }, + "you": "나" + }, + "cronJobs": { + "title": "Cron 작업", + "manage": "관리", + "noJobs": "설정된 Cron 작업 없음", + "disabled": "비활성화됨" + }, + "recentRequests": { + "title": "최근 요청", + "viewAll": "전체 보기", + "noRequests": "최근 요청 없음", + "columns": { + "time": "시간", + "name": "이름", + "user": "사용자", + "channel": "채널", + "tokens": "토큰", + "duration": "소요 시간", + "status": "상태" + } + }, + "quotaUsage": { + "title": "할당량 사용량", + "columns": { + "userGroup": "사용자 / 그룹", + "hour": "시간", + "day": "일", + "week": "주" + }, + "noLimit": "제한 없음" + }, + "embedding": { + "title": "임베딩", + "notConfigured": "설정되지 않음", + "configure": "공급자에서 설정 →" + } +} diff --git a/ui/web/src/i18n/locales/ko/packages.json b/ui/web/src/i18n/locales/ko/packages.json new file mode 100644 index 00000000..73dc1d30 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/packages.json @@ -0,0 +1,47 @@ +{ + "title": "런타임 & 패키지", + "description": "활성 GoClaw 런타임 컨테이너 내 런타임 및 설치된 패키지 관리", + "runtimes": { + "title": "런타임", + "scopeTitle": "컨테이너 범위 런타임 상태", + "scopeDesc": "이 검사는 활성 GoClaw 런타임 컨테이너 내에서 실행됩니다. 호스트에 설치된 런타임, 셸 프로파일 변경, nvm 관리 바이너리는 여기서 사용되지 않습니다.", + "minimalImageHint": "게시된 최신 이미지는 최소 구성이므로 Python이나 Node 런타임이 없을 수 있습니다. python, node 또는 full 이미지 변형을 사용하거나, ENABLE_PYTHON=true / ENABLE_NODE=true / ENABLE_FULL_SKILLS=true로 재빌드하거나, 이 컨테이너에 런타임을 수동으로 설치하세요.", + "available": "사용 가능", + "missing": "없음", + "missingInContainer": "컨테이너에 없음" + }, + "system": { + "title": "시스템 패키지", + "placeholder": "패키지 이름 (예: github-cli)" + }, + "pip": { + "title": "Python 패키지", + "placeholder": "패키지 이름 (예: pandas)" + }, + "npm": { + "title": "Node 패키지", + "placeholder": "패키지 이름 (예: typescript)" + }, + "actions": { + "install": "설치", + "uninstall": "제거", + "installing": "설치 중...", + "uninstalling": "제거 중..." + }, + "messages": { + "installSuccess": "{{name}} 설치 완료", + "installError": "{{name}} 설치 실패", + "uninstallSuccess": "{{name}} 제거 완료", + "uninstallError": "{{name}} 제거 실패" + }, + "confirmUninstall": { + "title": "제거 확인", + "description": "{{name}}을/를 제거하시겠습니까? 이 작업은 취소할 수 없습니다." + }, + "table": { + "name": "이름", + "version": "버전", + "actions": "작업", + "empty": "설치된 패키지 없음" + } +} diff --git a/ui/web/src/i18n/locales/ko/pending-messages.json b/ui/web/src/i18n/locales/ko/pending-messages.json new file mode 100644 index 00000000..1775d9b6 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/pending-messages.json @@ -0,0 +1,50 @@ +{ + "title": "대기 메시지", + "description": "에이전트 처리를 기다리는 버퍼링된 채널 메시지", + "emptyTitle": "대기 중인 메시지 없음", + "emptyDescription": "버퍼링된 메시지 그룹이 없습니다. 채널이 에이전트 처리 전에 메시지를 버퍼링할 때 여기에 나타납니다.", + "howItWorks": { + "title": "작동 방식", + "step1": "채널(Telegram, Discord 등)의 메시지는 에이전트가 바쁘거나 오프라인일 때 여기에 버퍼링됩니다.", + "step2": "버퍼가 임계값(기본값: 메시지 50개)에 도달하면 자동 압축이 시작됩니다 — LLM이 오래된 메시지를 요약하고 최근 15개만 유지합니다.", + "step3": "에이전트의 다음 턴에서 압축된 요약 + 최근 메시지가 컨텍스트로 삽입되어, 에이전트가 과부하 없이 따라잡을 수 있습니다.", + "compactAction": "압축 — LLM 요약을 지금 수동으로 트리거합니다. 에이전트가 원시 메시지 홍수 대신 깔끔한 요약을 처리하게 하려는 경우 유용합니다.", + "clearAction": "지우기 — 그룹의 모든 버퍼링된 메시지를 영구적으로 삭제합니다. 메시지가 더 이상 관련이 없을 때 사용하세요." + }, + "columns": { + "channel": "채널", + "group": "그룹", + "messages": "메시지", + "status": "상태", + "lastActivity": "마지막 활동", + "actions": "작업" + }, + "status": { + "compacted": "압축됨", + "raw": "원시" + }, + "compact": "압축", + "compacting": "압축 중…", + "clear": "지우기", + "confirmClear": { + "title": "메시지를 지우시겠습니까?", + "description": "{{channel}} / {{key}}의 모든 메시지가 영구적으로 삭제됩니다. 이 작업은 취소할 수 없습니다.", + "cancel": "취소", + "confirm": "지우기" + }, + "dialog": { + "title": "메시지 — {{name}}", + "noMessages": "메시지가 없습니다.", + "summary": "요약" + }, + "toast": { + "compacted": "압축 완료", + "compactedSummarized": "{{count}}개 메시지로 요약됨", + "compactedDeleted": "모든 메시지 삭제됨 (LLM 공급자 없음)", + "compacting": "압축 중…", + "compactingDesc": "LLM 요약이 백그라운드에서 실행 중입니다. 목록이 자동으로 새로 고쳐집니다.", + "failedCompact": "압축 실패", + "cleared": "메시지 지워짐", + "failedClear": "메시지 지우기 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/providers.json b/ui/web/src/i18n/locales/ko/providers.json new file mode 100644 index 00000000..cb9ae95c --- /dev/null +++ b/ui/web/src/i18n/locales/ko/providers.json @@ -0,0 +1,344 @@ +{ + "title": "공급자", + "description": "LLM 공급자 관리", + "addProvider": "공급자 추가", + "searchPlaceholder": "공급자 검색...", + "emptyTitle": "공급자 없음", + "emptyDescription": "첫 번째 LLM 공급자를 추가하여 시작하세요.", + "noMatchTitle": "일치하는 공급자 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "columns": { + "name": "이름", + "type": "유형", + "apiBase": "API 기본 URL", + "apiKey": "API 키", + "status": "상태", + "actions": "작업" + }, + "apiKey": { + "oauthToken": "OAuth 토큰", + "notSet": "설정되지 않음" + }, + "card": { + "apiKeySet": "API 키 설정됨", + "authenticated": "인증됨", + "oauthAccount": "OAuth 계정", + "oauthAlias": "별칭: {{name}}", + "connected": "연결됨", + "signInNeeded": "로그인 필요", + "disabled": "비활성화됨" + }, + "quota": { + "checking": "할당량 확인 중", + "plan": "플랜", + "lastChecked": "{{value}} 확인됨", + "failure": { + "billing": { + "label": "청구", + "description": "현재 워크스페이스 청구 또는 자격 문제로 계정이 차단되었습니다." + }, + "exhausted": { + "label": "소진됨", + "description": "이 계정은 로그인되어 있지만 핵심 할당량 창 중 하나가 소진되었습니다." + }, + "reauth": { + "label": "재인증", + "description": "워크스페이스 접근을 새로 고치려면 다시 로그인하세요." + }, + "forbidden": { + "label": "금지됨", + "description": "이 계정은 업스트림 할당량 데이터를 읽을 수 없습니다." + }, + "needs_setup": { + "label": "설정 필요", + "description": "GoClaw가 ChatGPT 계정 워크스페이스 메타데이터를 복원할 수 있도록 다시 로그인하세요." + }, + "retry_later": { + "label": "나중에 재시도", + "description": "할당량 엔드포인트가 일시적으로 사용 불가하거나 속도가 제한되어 있습니다." + }, + "unavailable": { + "label": "사용 불가", + "description": "현재 이 계정의 할당량 데이터를 사용할 수 없습니다." + } + } + }, + "form": { + "createTitle": "공급자 추가", + "editTitle": "공급자 편집", + "name": "이름 *", + "namePlaceholder": "예: openrouter", + "nameHint": "소문자, 숫자, 하이픈", + "displayName": "표시 이름", + "displayNamePlaceholder": "OpenRouter", + "providerType": "공급자 유형 *", + "apiKey": "API 키", + "apiKeyPlaceholder": "sk-...", + "apiKeyEditPlaceholder": "현재 값 유지 또는 새 키 입력", + "apiKeySetHint": "API 키가 설정되어 있습니다. 지우고 새 값을 입력하여 변경하세요.", + "apiBase": "API 기본 URL", + "enabled": "활성화됨", + "cancel": "취소", + "close": "닫기", + "create": "생성", + "save": "저장", + "update": "업데이트", + "saving": "저장 중...", + "creating": "생성 중...", + "alreadyAdded": "(이미 추가됨)", + "nameFixed": "이름", + "configure": "LLM 공급자 연결을 설정합니다.", + "configureOauth": "하나의 OpenAI Codex OAuth 계정을 연결합니다.", + "oauthAlias": "계정 별칭 *", + "oauthAliasPlaceholder": "예: primary", + "oauthAliasHint": "라우팅 및 풀에서 사용되는 소문자 별칭입니다.", + "oauthDisplayNamePlaceholder": "기본 Codex 계정", + "oauthDisplayNameHint": "대시보드에 표시되는 선택적 레이블입니다.", + "lowercaseHint": "소문자, 숫자, 하이픈" + }, + "delete": { + "title": "공급자 삭제", + "description": "\"{{name}}\"을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "types": { + "anthropic_native": "Anthropic", + "openai_compat": "OpenAI 호환", + "gemini_native": "Gemini", + "openrouter": "OpenRouter", + "groq": "Groq", + "deepseek": "DeepSeek", + "mistral": "Mistral", + "xai": "xAI", + "minimax_native": "MiniMax", + "cohere": "Cohere", + "perplexity": "Perplexity", + "chatgpt_oauth": "ChatGPT 구독 (OAuth)", + "yescale": "YesScale", + "acp": "ACP" + }, + "acp": { + "description": "ACP 호환 코딩 에이전트를 서브프로세스로 조율합니다. API 키가 필요하지 않습니다.", + "binary": "바이너리", + "binaryPlaceholder": "claude", + "binaryHint": "ACP 에이전트 바이너리의 경로 또는 이름 (예: claude, codex, gemini)", + "args": "인수", + "argsPlaceholder": "--profile goclaw", + "argsHint": "바이너리에 전달되는 공백으로 구분된 인수", + "idleTTL": "유휴 TTL", + "idleTTLPlaceholder": "5m", + "idleTTLHint": "이 기간 후 유휴 프로세스를 종료합니다 (예: 5m, 1h)", + "permMode": "권한 모드", + "permModeApproveAll": "모두 승인", + "permModeApproveReads": "읽기만 승인", + "permModeDenyAll": "모두 거부", + "workDir": "작업 디렉터리", + "workDirPlaceholder": "/tmp/workspace", + "workDirHint": "에이전트 서브프로세스의 작업 디렉터리 (선택사항)" + }, + "oauth": { + "checkingStatus": "인증 상태 확인 중...", + "authSuccessful": "인증 성공!", + "authSuccessfulDesc": "이 명명된 OpenAI/Codex 계정을 사용할 준비가 되었습니다.", + "activeProvider": "계정 별칭", + "authenticated": "인증됨 — 계정", + "active": "활성", + "poolBadge": "풀 준비됨", + "roundRobinBadge": "라운드 로빈", + "modelPrefixHint": "모델 접두사 사용", + "modelPrefixExample": "에이전트 설정에서 (예: {{example}}).", + "multiAccountHint": "나중에 에이전트 풀에서 더 많은 별칭을 추가하여 풀링이나 라운드 로빈을 활성화하세요.", + "aliasRequired": "OpenAI Codex OAuth를 시작하기 전에 유효한 소문자 계정 별칭을 입력하세요.", + "removeToken": "계정 연결 해제", + "signInDesc": "ChatGPT/Codex 구독으로 로그인합니다. 별도의 API 키가 필요하지 않습니다.", + "waiting": "인증 대기 중... 열린 창에서 로그인을 완료하세요.", + "remoteVpsHint": "로그인 후 브라우저가 열리려고 시도합니다", + "remoteVpsError": "그리고 \"이 페이지에 도달할 수 없음\" 오류가 표시됩니다. 정상입니다 — 브라우저 주소 표시줄에서 전체 URL을 복사하여 아래에 붙여넣으세요.", + "pasteUrlPlaceholder": "http://localhost:1455/auth/callback?code=...&state=...", + "submit": "제출", + "signInWithChatGPT": "OpenAI 계정 연결", + "starting": "시작 중...", + "remoteVps": "원격/VPS?", + "loggedOut": "로그아웃됨", + "loggedOutDesc": "OpenAI Codex OAuth 계정 연결 해제됨", + "oauthFailed": "OAuth 실패", + "exchangeFailed": "교환 실패", + "logoutFailed": "로그아웃 실패", + "done": "완료" + }, + "cli": { + "description": "Claude CLI는 로컬", + "descriptionSuffix": "바이너리를 사용합니다. API 키가 필요하지 않습니다.", + "checkingAuth": "인증 확인 중...", + "authenticatedAs": "다음으로 인증됨", + "switchAccount": "계정을 전환하시겠습니까?", + "switchAccountInstructions": "서버 터미널에서 실행하세요:", + "switchAccountRecheck": "그런 다음 클릭하세요", + "switchAccountRecheckSuffix": "재확인하려면.", + "notAuthenticated": "인증되지 않음", + "runOnServer": "서버 터미널에서 실행하세요:", + "recheckButton": "재확인" + }, + "detail": { + "title": "공급자 세부 정보", + "advanced": "고급", + "identity": "식별", + "identityDesc": "공급자 식별", + "connection": "연결", + "connectionDesc": "API 엔드포인트 설정", + "acpConfig": "ACP 설정", + "acpConfigDesc": "에이전트 서브프로세스 설정", + "cliConfig": "Claude CLI", + "cliConfigDesc": "로컬 CLI 인증", + "oauthConfig": "ChatGPT 구독 (OAuth)", + "oauthConfigDesc": "이 명명된 OpenAI/Codex 계정의 로그인 관리", + "nameReadonly": "공급자 식별자, 변경 불가", + "oauthAliasReadonly": "OAuth 계정 별칭, 변경 불가", + "providerType": "공급자 유형", + "apiKeySection": "API 키", + "apiKeySectionDesc": "인증 자격증명", + "statusSection": "상태", + "statusSectionDesc": "공급자 가용성", + "enabledDesc": "공급자가 활성 상태이며 에이전트에서 사용 가능합니다", + "embeddingSection": "임베딩", + "oauthAccountUsage": "계정 사용", + "oauthAccountUsageDesc": "이 별칭이 공급자 소유 OpenAI Codex 풀링 내에서 작동하는 방식입니다.", + "oauthAccountUsageManagedDesc": "이 별칭은 현재 {{provider}}가 관리하는 풀 멤버입니다.", + "oauthAccountUsageOwnerDesc": "이 별칭은 현재 {{count}}개의 추가 계정이 있는 재사용 가능한 풀을 소유합니다.", + "oauthPoolRole": { + "member": "풀 멤버", + "owner": "풀 소유자", + "standalone": "독립형" + }, + "oauthAliasLabel": "계정 별칭", + "oauthAccountBadge": "ChatGPT 구독 (OAuth)", + "oauthModelPrefix": "모델 접두사", + "oauthQuotaTitle": "할당량 상태", + "oauthQuotaDescription": "이 계정의 최신 ChatGPT 워크스페이스 할당량입니다.", + "oauthModelPrefixCopied": "모델 접두사 복사됨", + "oauthPreferredHint": "에이전트의 공급자 필드를 이 별칭으로 설정하여 기본 OpenAI 별칭으로 만드세요.", + "oauthProviderDefaultHint": "아래 풀 기본값을 사용하여 이 별칭을 가리키는 모든 에이전트에 대한 재사용 가능한 OpenAI Codex 라우팅 정책을 정의하세요.", + "oauthRoutingHint": "에이전트 페이지에는 이제 해당 에이전트의 유효 풀과 이 기본값을 상속하는지 또는 커스텀 재정의를 저장하는지 여부가 표시됩니다.", + "oauthManagedByHint": "이 별칭은 공급자 {{provider}}가 관리합니다. 이 계정 대신 풀 멤버십을 편집하세요.", + "reasoningDefaultsTitle": "추론 기본값", + "reasoningDefaultsDescription": "이 공급자를 사용하는 에이전트의 기본 추론 정책을 설정합니다. 최종 런타임 노력은 각 에이전트의 선택된 모델에 따라 정규화됩니다.", + "reasoningPreset": "기본 프리셋", + "reasoningExpertMode": "전문가 기본값", + "reasoningExpertModeDesc": "자동, 없음, 최소 또는 xhigh와 같은 노력이 필요할 때 공급자 소유 고급 추론 기본값을 사용합니다.", + "reasoningPreviewDescription": "{{model}}에 대한 명시적 추론 기능 메타데이터를 미리 봅니다.", + "reasoningPreviewLabel": "기능 미리보기", + "reasoningPreviewDefault": "미리보기 모델 기본 추론: {{level}}", + "reasoningPreviewEmpty": "이 공급자에 대해 아직 명시적 추론 가능 모델이 반환되지 않았습니다.", + "reasoningRequestedEffort": "요청된 노력", + "reasoningFallbackBehavior": "폴백 동작", + "codexPoolDefaultsTitle": "풀 기본값", + "codexPoolDefaultsDescription": "이 별칭을 기본 공급자로 사용하는 에이전트를 위해 이 별칭이 소유한 재사용 가능한 OpenAI Codex 풀을 정의합니다.", + "poolManagedByDescription": "이 공급자는 {{owner}}가 소유한 풀의 멤버입니다. 풀 설정을 변경하려면 풀 소유자로 이동하세요.", + "oauthDisplayNameRecommendation": "여러 OpenAI Codex OAuth 계정이 풀에 표시될 때 더 명확한 레이블을 원하면 표시 이름을 추가하세요.", + "poolActivityTitle": "풀 활동", + "poolActivityDescription": "이 공급자의 Codex 풀을 사용하는 모든 에이전트의 집계 런타임 활동입니다.", + "poolActivityRefresh": "새로 고침", + "poolActivityTopAgents": "에이전트", + "poolActivityTopAgentsTitle": "이 풀을 사용하는 상위 에이전트", + "poolActivityRequests": "요청", + "poolActivityEmpty": "아직 활동 없음", + "poolActivityEmptyDesc": "에이전트가 이 풀을 통해 요청 라우팅을 시작하면 풀 활동이 여기에 표시됩니다." + }, + "embedding": { + "enable": "임베딩 활성화", + "enableDesc": "이 공급자가 메모리, 스킬 및 지식 그래프를 위한 텍스트 임베딩을 생성할 수 있도록 합니다", + "model": "임베딩 모델", + "dimensions": "출력 차원", + "dimensionsHint": "GoClaw 메모리는 현재 임베딩을 vector(1536)에 저장합니다. 모델이 이미 1536을 출력할 때는 비워두고, 공급자가 더 큰 기본 차원에서 잘라내기를 지원하는 경우 정확히 1536으로 설정하세요.", + "dimensionsInvalid": "GoClaw 메모리에서 현재 지원되는 값은 1536뿐입니다.", + "apiBase": "임베딩 API 기본 URL", + "apiBasePlaceholder": "(공급자와 동일)", + "apiBaseHint": "임베딩 엔드포인트가 공급자의 메인 API 기본 URL과 다른 경우 재정의", + "verify": "임베딩 확인", + "verifyFailed": "임베딩 확인 실패", + "dimensionsMismatch": "{{count}} 차원 — 필수 1536과 일치하지 않음" + }, + "reasoning": { + "off": "끄기", + "offDesc": "기본 확장 사고 없음", + "auto": "자동", + "autoDesc": "모델이 자체 기본 추론 노력을 사용하도록 요청", + "none": "없음", + "noneDesc": "고급 계약을 유지하면서 공급자 추론을 명시적으로 비활성화", + "minimal": "최소", + "minimalDesc": "없음 이상에서 가장 작은 지원 추론 노력 사용", + "low": "낮음", + "lowDesc": "~4K 토큰 예산", + "medium": "중간", + "mediumDesc": "~10-16K 토큰 예산", + "high": "높음", + "highDesc": "~32K 토큰 예산", + "xhigh": "최대", + "xhighDesc": "지원되는 최대 추론 노력 사용", + "downgrade": "다운그레이드", + "downgradeDesc": "가장 가까운 지원 낮은 수준으로 정규화하거나, 더 낮은 지원 수준이 없으면 비활성화", + "provider_default": "모델 기본값 사용", + "provider_defaultDesc": "명시적 노력을 강제하지 않고 공급자/모델이 기본값을 선택하도록 함" + }, + "list": { + "poolOwner": "풀 소유자", + "poolMember": "풀 멤버", + "poolAvailable": "풀 사용 가능", + "poolBadge": "풀", + "standalone": "독립형", + "reasoningDefault": "추론 {{level}}", + "managedBy": "{{provider}}가 관리", + "memberCount_one": "{{count}}개 멤버", + "memberCount_other": "{{count}}개 멤버", + "memberOverflow": "+{{count}}", + "strategy": { + "roundRobin": "라운드 로빈", + "priorityOrder": "우선순위 순서", + "primaryFirst": "기본 우선" + }, + "status": { + "needsSignIn": "로그인 필요", + "disabled": "비활성화됨" + } + }, + "pageHint": { + "title": "ChatGPT 구독 (OAuth) 계정", + "description": "각 별칭은 하나의 Codex 계정입니다. 풀 소유자가 여기서 멤버 계정을 관리하며, 에이전트 페이지에는 유효한 경로만 표시됩니다.", + "connected_one": "{{count}}개 연결된 계정", + "connected_other": "{{count}}개 연결된 계정", + "owners_one": "{{count}}명 풀 소유자", + "owners_other": "{{count}}명 풀 소유자", + "members_one": "{{count}}명 멤버", + "members_other": "{{count}}명 멤버" + }, + "poolCta": { + "unpooledCount": "{{count}}개 계정 풀 준비됨", + "setupPool": "풀 설정", + "dismiss": "닫기" + }, + "poolWizard": { + "title": "풀 설정", + "description": "자동 폴오버와 부하 분산을 위해 ChatGPT 계정을 결합합니다.", + "selectOwner": "풀 소유자", + "selectOwnerHint": "풀 설정을 소유하는 기본 계정입니다.", + "selectMembers": "풀 멤버", + "selectMembersHint": "풀에 포함할 계정을 선택하세요.", + "selectAll": "모두 선택", + "deselectAll": "모두 선택 해제", + "selectedCount": "{{count}}개 선택됨", + "strategy": "전략", + "createPool": "풀 생성", + "noMembers": "풀을 생성하려면 최소 하나의 멤버를 선택하세요.", + "success": "풀이 성공적으로 생성되었습니다.", + "error": "풀 생성 실패." + }, + "toast": { + "created": "공급자 생성됨", + "createdDesc": "{{name}}이 추가되었습니다", + "updated": "공급자 업데이트됨", + "deleted": "공급자 삭제됨", + "failedCreate": "공급자 생성 실패", + "failedUpdate": "공급자 업데이트 실패", + "failedDelete": "공급자 삭제 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/sessions.json b/ui/web/src/i18n/locales/ko/sessions.json new file mode 100644 index 00000000..8e41abe4 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/sessions.json @@ -0,0 +1,45 @@ +{ + "title": "세션", + "description": "대화 세션 탐색", + "searchPlaceholder": "세션 검색...", + "emptyTitle": "아직 세션 없음", + "emptyDescription": "채팅을 시작하면 여기에 세션이 나타납니다.", + "noMatchTitle": "일치하는 세션 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "columns": { + "session": "세션", + "agent": "에이전트", + "context": "컨텍스트", + "messages": "메시지", + "updated": "업데이트됨" + }, + "contextBar": { + "compacted": "{{count}}회 압축됨" + }, + "detail": { + "reset": "초기화", + "delete": "삭제", + "deleteTitle": "세션 삭제", + "deleteDescription": "이 세션의 모든 메시지가 영구적으로 삭제됩니다.", + "resetTitle": "세션 초기화", + "resetDescription": "모든 메시지가 지워지지만 세션은 유지됩니다.", + "confirmDelete": "삭제", + "confirmReset": "초기화", + "noMessages": "이 세션에 메시지가 없습니다", + "summary": "요약", + "showMore": "더 보기", + "showLess": "접기", + "showDetails": "세부 정보 보기", + "hide": "숨기기", + "systemMessage": "시스템 메시지", + "messages": "메시지" + }, + "toast": { + "deleted": "세션 삭제됨", + "deleteFailed": "세션 삭제 실패", + "reset": "세션 초기화됨", + "resetFailed": "세션 초기화 실패", + "updated": "세션 업데이트됨", + "updateFailed": "세션 업데이트 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/setup.json b/ui/web/src/i18n/locales/ko/setup.json new file mode 100644 index 00000000..8ce5f396 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/setup.json @@ -0,0 +1,117 @@ +{ + "layout": { + "subtitle": "게이트웨이를 설정하고 실행해 봅시다" + }, + "steps": { + "provider": "공급자", + "model": "모델", + "agent": "에이전트", + "channel": "채널", + "channelOptional": "(선택사항)" + }, + "complete": { + "title": "설정 완료!", + "ready": "시스템이 준비되었습니다!", + "description": "공급자, 에이전트, 채널이 설정되었습니다. 대시보드에서 언제든지 관리할 수 있습니다.", + "goToDashboard": "대시보드로 이동" + }, + "provider": { + "title": "LLM 공급자 설정", + "descriptionCli": "로컬 Claude CLI 설치를 사용하여 연결합니다. API 키가 필요하지 않습니다.", + "descriptionOauth": "하나의 OpenAI Codex OAuth 계정을 생성합니다. 지금 별칭을 지정한 후, 나중에 풀 멤버나 라운드 로빈을 위한 별칭을 추가할 수 있습니다.", + "description": "에이전트를 구동할 AI 공급자에 연결합니다. API 키가 필요합니다.", + "providerType": "공급자 유형", + "providerTypeHint": "연결할 LLM 서비스입니다. 여러 모델에 접근하려면 OpenRouter를 권장합니다.", + "name": "이름", + "nameHint": "이 공급자의 내부 식별자입니다. 공급자 유형에서 자동 생성됩니다.", + "oauthAlias": "계정 별칭", + "oauthAliasPlaceholder": "예: primary", + "oauthAliasHint": "이 OpenAI/Codex 계정에 대해 primary, work, team 같은 고유 소문자 별칭을 사용하세요. 별칭은 에이전트가 사용하는 공급자/모델 접두사가 됩니다.", + "displayName": "표시 이름 (선택사항)", + "displayNameHint": "이 OpenAI/Codex 계정의 친화적 레이블입니다. 나중에 별칭을 추가할 때 유용합니다.", + "displayNamePlaceholder": "기본 Codex 계정", + "apiKey": "API 키 *", + "apiKeyHint": "공급자의 시크릿 키입니다. 서버 측에서 암호화되며 API 응답에 노출되지 않습니다.", + "apiBase": "API 기본 URL", + "apiBaseHint": "API 요청의 엔드포인트 URL입니다. 공급자 유형에 따라 자동 입력됩니다. 커스텀 프록시를 사용하는 경우에만 변경하세요.", + "creating": "생성 중...", + "create": "공급자 생성", + "errors": { + "apiKeyRequired": "API 키가 필요합니다", + "oauthProviderNotFound": "OAuth 인증에 성공했지만 공급자를 찾을 수 없습니다. 다시 시도해 주세요.", + "failedCreate": "공급자 생성 실패" + } + }, + "model": { + "title": "모델 선택 및 확인", + "description": "모델을 선택하고 공급자 연결이 작동하는지 확인하세요.", + "provider": "공급자:", + "model": "모델 *", + "modelHint": "사용할 AI 모델입니다. 목록에서 선택하거나 목록에 없는 경우 모델 ID를 직접 입력하세요.", + "loadingModels": "모델 불러오는 중...", + "selectModel": "모델 선택 또는 모델 ID 입력", + "noModelsHint": "이 공급자는 모델 목록을 제공하지 않습니다 — 모델 ID를 직접 입력하세요.", + "verified": "확인됨", + "verify": "확인", + "verifying": "확인 중...", + "continue": "계속", + "modelVerified": "모델 확인됨", + "modelVerifiedDesc": "{{model}}이 정상적으로 작동합니다", + "verificationFailed": "확인 실패. API 키와 모델을 확인하세요." + }, + "agent": { + "title": "첫 번째 에이전트 만들기", + "description": "에이전트는 AI 어시스턴트입니다. 이름과 성격을 설정하세요.", + "provider": "공급자:", + "model": "모델:", + "displayName": "표시 이름", + "displayNameHint": "소환 중 에이전트 성격에 따라 자동 생성됩니다.", + "agentKey": "에이전트 키", + "agentKeyHint": "에이전트의 고유 식별자입니다. 소문자, 숫자, 하이픈만 사용 가능합니다.", + "agentKeyPlaceholder": "my-agent", + "personality": "에이전트 성격", + "personalityHint": "에이전트의 역할과 행동을 설명하세요. AI가 소환 중에 이를 기반으로 컨텍스트 파일을 생성합니다.", + "personalityPlaceholder": "에이전트의 성격, 목적, 행동 방식을 설명하세요...", + "personalityHintBottom": "이 프롬프트를 커스터마이즈하여 에이전트의 성격과 전문성을 설정하세요.", + "selfEvolve": "자기 진화", + "selfEvolveDesc": "에이전트가 SOUL.md를 통해 시간이 지남에 따라 커뮤니케이션 스타일을 진화시킬 수 있도록 합니다", + "creating": "생성 중...", + "create": "에이전트 생성", + "summoningFailed": "소환 실패. 설정을 조정하고 다시 시도하세요.", + "errors": { + "noProvider": "사용 가능한 공급자 없음", + "failedCreate": "에이전트 생성 실패" + } + }, + "channel": { + "title": "채널 연결", + "description": "에이전트에 메시징 플랫폼을 연결하세요. 나중에 언제든지 채널을 추가할 수 있습니다.", + "skip": "건너뛰기", + "skipFinish": "건너뛰고 완료", + "agent": "에이전트:", + "channelType": "채널 유형", + "channelTypeHint": "연결할 메시징 플랫폼입니다. 예: Telegram, Discord, Zalo.", + "name": "이름", + "nameHint": "이 채널 인스턴스의 내부 식별자입니다. 채널 유형에서 자동 생성됩니다.", + "namePlaceholder": "my-telegram", + "displayName": "표시 이름", + "displayNameHint": "UI에 표시되는 친화적 이름입니다. 선택사항.", + "displayNamePlaceholder": "판매 봇", + "credentials": "자격증명", + "credentialsHint": "서버 측에서 암호화됩니다. API 응답에 반환되지 않습니다.", + "creating": "생성 중...", + "create": "채널 생성", + "errors": { + "noAgent": "사용 가능한 에이전트 없음", + "requiredFields": "필수 항목: {{fields}}", + "failedCreate": "채널 생성 실패" + } + }, + "common": { + "back": "뒤로" + }, + "skipSetup": "설정을 건너뛰고 대시보드로 이동", + "skipSetupConfirm": "설정을 건너뛰시겠습니까? 대시보드에서 나중에 언제든지 공급자와 에이전트를 설정할 수 있습니다.", + "switchTenant": "전환", + "allTenants": "모든 테넌트" +} diff --git a/ui/web/src/i18n/locales/ko/sidebar.json b/ui/web/src/i18n/locales/ko/sidebar.json new file mode 100644 index 00000000..e04fbd56 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/sidebar.json @@ -0,0 +1,47 @@ +{ + "groups": { + "core": "핵심", + "conversations": "대화", + "connectivity": "연결", + "capabilities": "기능", + "data": "데이터", + "monitoring": "모니터링", + "system": "시스템" + }, + "nav": { + "overview": "개요", + "chat": "채팅", + "agents": "에이전트", + "agentTeams": "에이전트 링크 & 팀", + "sessions": "세션", + "pendingMessages": "대기 메시지", + "channels": "채널", + "contacts": "연락처", + "skills": "스킬", + "cron": "Cron", + "customTools": "사용자 지정 도구", + "builtinTools": "내장 도구", + "mcpServers": "MCP 서버", + "memory": "메모리", + "vault": "볼트", + "knowledgeGraph": "지식 그래프", + "traces": "추적", + "realtimeEvents": "실시간 이벤트", + "usage": "사용량", + "logs": "로그", + "storage": "스토리지", + "providers": "공급자", + "config": "설정", + "approvals": "승인", + "importExport": "가져오기 & 내보내기", + "nodes": "노드", + "tts": "TTS", + "activity": "활동", + "cliCredentials": "CLI 자격 증명", + "apiKeys": "API 키", + "apiDocs": "API 문서", + "packages": "패키지", + "tenants": "테넌트", + "backupRestore": "백업 & 복원" + } +} diff --git a/ui/web/src/i18n/locales/ko/skills.json b/ui/web/src/i18n/locales/ko/skills.json new file mode 100644 index 00000000..d92e98db --- /dev/null +++ b/ui/web/src/i18n/locales/ko/skills.json @@ -0,0 +1,123 @@ +{ + "title": "스킬", + "description": "에이전트 스킬 및 기능 관리", + "searchPlaceholder": "스킬 검색...", + "emptyTitle": "스킬 없음", + "emptyDescription": "아직 등록된 스킬이 없습니다.", + "noMatchTitle": "일치하는 스킬 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "columns": { + "name": "이름", + "description": "설명", + "source": "출처", + "author": "작성자", + "visibility": "공개 범위", + "status": "상태", + "actions": "작업" + }, + "noDescription": "설명 없음", + "visibility": { + "clickToCycle": "클릭하여 공개 범위 변경" + }, + "delete": { + "title": "스킬 삭제", + "description": "\"{{name}}\"을/를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "upload": { + "title": "스킬 업로드", + "description": "YAML 프론트매터(name, description, slug)가 있는 SKILL.md가 포함된 ZIP 파일을 업로드하세요.", + "button": "업로드", + "uploading": "업로드 중...", + "dropOrClick": ".zip 파일을 클릭하거나 끌어다 놓기", + "dropHere": ".zip 파일을 여기에 놓기", + "onlyZip": ".zip 파일만 허용됩니다", + "cancel": "취소", + "done": "완료", + "tooLarge": "파일이 20MB 제한을 초과합니다", + "invalidZip": "유효하지 않은 ZIP 파일", + "noSkillMd": "ZIP에는 루트에 SKILL.md가 있어야 합니다", + "emptySkillMd": "SKILL.md가 비어 있습니다", + "noFrontmatter": "SKILL.md에 YAML 프론트매터가 없습니다", + "nameRequired": "SKILL.md 프론트매터에 name이 필요합니다", + "invalidSlug": "유효하지 않은 슬러그 형식", + "failed": "업로드 실패", + "validating": "유효성 검사 중...", + "validCount": "{{total}}개 중 {{valid}}개 유효", + "uploadCount": "업로드 ({{count}}개)", + "successCount": "{{total}}개 중 {{success}}개 성공적으로 업로드됨", + "remove": "파일 제거" + }, + "edit": { + "title": "스킬 편집", + "name": "이름", + "description": "설명", + "visibility": "공개 범위", + "tags": "태그", + "addTag": "태그 추가...", + "add": "추가", + "cancel": "취소", + "save": "저장", + "saving": "저장 중...", + "privateOption": "비공개 (소유자만)", + "internalOption": "내부 (허가된 에이전트/사용자)", + "publicOption": "공개 (모든 에이전트)" + }, + "system": "시스템", + "tabs": { + "core": "핵심", + "custom": "사용자 지정" + }, + "toggle": { + "enable": "스킬 활성화", + "disable": "스킬 비활성화", + "disabled": "비활성화됨" + }, + "tenant": { + "enabled": "활성화됨", + "disabled": "비활성화됨", + "default": "기본값", + "overrideHint": "이 스킬의 테넌트별 재정의", + "resetDefault": "기본값으로 초기화" + }, + "deps": { + "rescan": "의존성 재검사", + "rescanning": "검사 중...", + "rescanSuccess": "{{count}}개 스킬 업데이트됨", + "missing": "없음: {{deps}}", + "install": "의존성 설치", + "installing": "설치 중...", + "installSuccess": "의존성 설치 완료", + "installPartial": "일부 의존성 설치 실패", + "installItem": "설치", + "itemSuccess": "설치됨", + "itemError": "실패", + "missingTitle": "없는 의존성", + "systemLabel": "시스템", + "pythonLabel": "Python", + "nodeLabel": "Node.js", + "statusActive": "활성", + "statusArchived": "의존성 없음", + "runtimeMissing": "런타임 전제 조건 없음", + "runtimeMissingDesc": "핵심 스킬은 GoClaw 런타임 컨테이너 내에 Python 및/또는 Node.js 런타임이 필요합니다. 호스트에 설치된 런타임은 사용되지 않습니다.", + "runtimeMissingAction": "패키지를 열어 이 컨테이너에 런타임을 확인하거나 설치하세요.", + "runtimeRequired": "먼저 컨테이너 런타임 설치" + }, + "detail": { + "title": "스킬 세부 정보", + "content": "내용", + "files": "파일", + "version": "버전:", + "current": "(현재)", + "noContent": "사용 가능한 내용이 없습니다." + }, + "toast": { + "updated": "스킬 업데이트됨", + "updateFailed": "스킬 업데이트 실패", + "deleted": "스킬 삭제됨", + "deleteFailed": "스킬 삭제 실패", + "rescanUpdated": "{{count}}개 스킬 업데이트됨", + "rescanNoChanges": "모든 스킬 최신 상태", + "rescanFailed": "의존성 재검사 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/storage.json b/ui/web/src/i18n/locales/ko/storage.json new file mode 100644 index 00000000..9d682f61 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/storage.json @@ -0,0 +1,25 @@ +{ + "title": "스토리지", + "description": "워크스페이스 파일 탐색기", + "descriptionWithPath": "{{path}} — {{size}}", + "sizeCacheInfo": "스토리지 크기는 60분간 캐시됩니다", + "unsupportedFile": "이 파일 유형은 미리보기를 지원하지 않습니다", + "download": "다운로드", + "delete": { + "fileTitle": "파일 삭제", + "folderTitle": "폴더 삭제", + "description": "{{name}}을/를 삭제하시겠습니까?", + "folderWarning": " 모든 내용이 재귀적으로 제거됩니다.", + "undone": " 이 작업은 취소할 수 없습니다.", + "deleting": "삭제 중...", + "confirmLabel": "삭제" + }, + "upload": { + "title": "스토리지에 업로드", + "description": "데이터 디렉터리에 파일 업로드" + }, + "toast": { + "deleted": "파일 삭제됨", + "deleteFailed": "파일 삭제 실패" + } +} diff --git a/ui/web/src/i18n/locales/ko/system-settings.json b/ui/web/src/i18n/locales/ko/system-settings.json new file mode 100644 index 00000000..516344e8 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/system-settings.json @@ -0,0 +1,80 @@ +{ + "title": "시스템 설정", + "save": "저장", + "cancel": "취소", + "saving": "저장 중...", + "saved": "설정 저장됨", + "loadFailed": "설정 불러오기 실패", + "saveFailed": "설정 저장 실패", + "embedding": { + "title": "임베딩", + "description": "벡터 임베딩 및 의미 검색을 위한 공급자와 모델입니다.", + "importance": "임베딩은 메모리 회수, 스킬 검색, 지식 그래프, 태스크 매칭 정확도에 중요합니다. 변경 시 전체 시스템에 영향을 줍니다.", + "provider": "임베딩 공급자", + "model": "임베딩 모델", + "providerTip": "텍스트 임베딩 생성에 사용되는 LLM 공급자입니다.", + "modelTip": "임베딩 모델 (예: text-embedding-3-small). /embeddings 엔드포인트를 지원해야 합니다.", + "providerPlaceholder": "공급자 선택", + "modelPlaceholder": "text-embedding-3-small", + "supportedProviders": "1536d 검증됨: OpenAI (text-embedding-3-small/large), Gemini (gemini-embedding-001 + dimensions), Mistral (codestral-embed), Cohere (embed-v4), DashScope (text-embedding-v3 + dimensions). 기본 차원이 1536보다 큰 모델은 공급자 설정에서 차원을 설정하세요.", + "verify": "임베딩 확인", + "verifyRequired": "저장 전에 임베딩 모델을 확인하세요.", + "verifyFailed": "확인 실패", + "dimensions": "{{count}} 차원", + "dimensionsMismatch": "{{count}} 차원 — 필수 1536과 일치하지 않음", + "maxChunkLen": "최대 청크 길이", + "maxChunkLenHint": "분할 전 메모리 청크당 최대 문자 수입니다.", + "chunkOverlap": "청크 겹침", + "chunkOverlapHint": "컨텍스트 연속성을 위한 연속 청크 간 겹침 문자 수입니다." + }, + "ux": { + "title": "UX 동작", + "description": "게이트웨이가 사용자에게 에이전트 활동을 표시하는 방식을 제어합니다.", + "toolStatus": "실행 중 도구 이름 표시", + "toolStatusHint": "에이전트 실행 중 활성 도구 이름을 표시합니다.", + "toolStatusInfo": "에이전트 실행 중 스트리밍 미리보기에 도구 이름이 표시됩니다.", + "blockReply": "도구 호출 중 중간 텍스트 표시", + "blockReplyHint": "도구 호출 중 부분 어시스턴트 텍스트를 스트리밍합니다.", + "blockReplyInfo": "도구 실행 중 사용자에게 중간 텍스트가 스트리밍됩니다.", + "intentClassify": "의도 분류", + "intentClassifyHint": "에이전트로 라우팅하기 전에 사용자 의도를 분류합니다.", + "intentClassifyInfo": "에이전트 라우팅 및 동작 최적화를 위해 메시지가 분류됩니다." + }, + "kg": { + "title": "지식 그래프", + "description": "에이전트 메모리에서 검색 가능한 지식 그래프로 엔티티와 관계를 추출합니다.", + "provider": "추출 공급자", + "model": "추출 모델", + "providerTip": "메모리에서 엔티티를 추출하는 데 사용되는 LLM 공급자입니다.", + "modelTip": "엔티티/관계 추출 모델 (예: claude-sonnet-4-20250514).", + "providerPlaceholder": "공급자 선택", + "modelPlaceholder": "모델 선택", + "minConfidence": "최소 신뢰도", + "minConfidenceHint": "추출된 엔티티의 최소 신뢰도 임계값 (0–1).", + "info": "에이전트가 메모리에 쓸 때 자동으로 엔티티와 관계를 추출합니다. 비활성화하려면 공급자를 비워두세요." + }, + "bg": { + "title": "백그라운드 작업자", + "description": "백그라운드 태스크(볼트 보강, 통합, 드리밍)를 위한 공급자와 모델입니다.", + "provider": "공급자", + "model": "모델", + "providerTip": "백그라운드 태스크용 LLM 공급자입니다. 에이전트 기본값을 사용하려면 비워두세요.", + "modelTip": "백그라운드 태스크용 모델입니다. 공급자 기본값을 사용하려면 비워두세요.", + "providerPlaceholder": "(에이전트 기본값)", + "modelPlaceholder": "(기본값)", + "info": "볼트 보강 (문서 요약), 통합 (세션 요약), 드리밍에 사용됩니다. 에이전트 기본 공급자로 대체하려면 비워두세요." + }, + "compaction": { + "title": "대기 메시지 압축", + "description": "컨텍스트 한도 내에 유지하기 위해 긴 대기 메시지 기록을 요약합니다.", + "providerPlaceholder": "(자동)", + "threshold": "임계값", + "thresholdHint": "압축이 트리거되기 전의 메시지 수입니다.", + "keepRecent": "최근 유지", + "keepRecentHint": "압축 후 보존되는 메시지 수입니다.", + "maxTokens": "최대 토큰", + "maxTokensHint": "압축된 요약의 토큰 한도입니다.", + "info": "그룹 채팅이 임계값을 초과하면 LLM이 오래된 메시지를 단일 압축 항목으로 자동 요약하여 컨텍스트를 위해 가장 최근 메시지를 유지합니다." + }, + "moreConfig": "추가 설정" +} diff --git a/ui/web/src/i18n/locales/ko/teams.json b/ui/web/src/i18n/locales/ko/teams.json new file mode 100644 index 00000000..95897e1e --- /dev/null +++ b/ui/web/src/i18n/locales/ko/teams.json @@ -0,0 +1,402 @@ +{ + "title": "팀", + "description": "에이전트 팀 관리", + "createTeam": "팀 만들기", + "searchPlaceholder": "팀 검색...", + "emptyTitle": "아직 팀 없음", + "emptyDescription": "첫 번째 팀을 만들어 시작하세요.", + "noMatchTitle": "일치하는 팀 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "viewCard": "카드 보기", + "viewList": "목록 보기", + "scope": { + "all": "모든 범위", + "label": "범위" + }, + "delete": { + "title": "팀 삭제", + "description": "\"{{name}}\"을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "detail": { + "lead": "리더", + "memberCount": "{{count}}명 멤버", + "memberCountPlural": "{{count}}명 멤버", + "more": "더 보기", + "deleteDescription": "\"{{name}}\"을 삭제하시겠습니까? 모든 멤버, 태스크 및 설정이 영구적으로 삭제됩니다.", + "tabs": { + "tasks": "태스크", + "members": "멤버", + "delegations": "위임", + "workspace": "워크스페이스", + "settings": "설정" + } + }, + "members": { + "title": "멤버", + "noMembers": "멤버 없음", + "addMember": "멤버 추가", + "addMemberTooltip": "사전 정의된 에이전트만 팀 멤버로 추가할 수 있습니다. 개방형 에이전트는 사용자별 컨텍스트를 가지며 팀 협업에 필요한 공유 컨텍스트가 없습니다.", + "selectAgent": "추가할 에이전트 선택...", + "noAvailableAgents": "사용 가능한 에이전트 없음", + "searchAgents": "에이전트 검색...", + "adding": "추가 중...", + "add": "추가", + "added": "멤버 추가됨", + "failedAdd": "멤버 추가 실패", + "removed": "멤버 제거됨", + "failedRemove": "멤버 제거 실패", + "removeMember": "멤버 제거", + "columns": { + "agent": "에이전트", + "frontmatter": "프론트매터", + "role": "역할", + "addedAt": "추가된 시간", + "actions": "작업" + } + }, + "tasks": { + "title": "태스크", + "loading": "태스크 불러오는 중...", + "noTasks": "아직 태스크 없음", + "noTasksDescription": "태스크는 팀 에이전트의 협업 중에 생성됩니다.", + "refresh": "새로 고침", + "createTask": "태스크 만들기", + "createTaskTitle": "태스크 만들기", + "subjectPlaceholder": "태스크 제목...", + "descriptionPlaceholder": "선택적 설명...", + "priorityLabel": "우선순위", + "assign": "할당", + "assignTo": "다음에 할당...", + "unassigned": "미할당", + "filters": { + "active": "활성", + "pending": "대기 중", + "inProgress": "진행 중", + "inReview": "검토 중", + "completed": "완료됨", + "all": "전체" + }, + "columns": { + "id": "ID", + "subject": "제목", + "status": "상태", + "owner": "담당자", + "priority": "우선순위", + "taskId": "태스크 ID", + "created": "생성됨", + "actions": "작업" + }, + "detail": { + "title": "태스크 상세", + "subject": "제목", + "status": "상태:", + "priority": "우선순위:", + "owner": "담당자:", + "type": "유형:", + "blockedBy": "차단 원인:", + "description": "설명", + "result": "결과", + "created": "생성됨:", + "updated": "업데이트됨:", + "taskId": "태스크 ID:", + "noDescription": "설명 없음", + "noResult": "아직 결과 없음", + "progress": "진행률", + "approve": "승인", + "reject": "거부", + "comments": "댓글", + "noComments": "아직 댓글 없음", + "commentPlaceholder": "댓글 추가...", + "addComment": "댓글", + "timeline": "타임라인", + "attachments": "첨부 파일", + "followupStatus": "응답 대기 중", + "followupMessage": "알림 메시지:", + "followupCount": "알림 발송: {{count}}회", + "followupCountMax": "알림 발송: {{count}}/{{max}}회", + "followupNext": "다음 알림:", + "followupDone": "모든 알림 발송됨", + "download": "다운로드" + }, + "delete": "삭제", + "deleteConfirm": "이 태스크를 삭제하시겠습니까? 취소할 수 없습니다.", + "selected": "{{count}}개 선택됨", + "deleteSelected": "선택 항목 삭제", + "deleteBulkTitle": "태스크 삭제", + "deleteBulkConfirm": "{{count}}개 태스크가 영구적으로 삭제됩니다. 확인하려면 \"delete\"를 입력하세요.", + "badges": { + "awaitingReply": "응답 대기 중" + } + }, + "delegations": { + "noTitle": "위임 없음", + "noDescription": "이 팀에 대한 위임 기록을 찾을 수 없습니다.", + "refresh": "새로 고침", + "columns": { + "sourceTarget": "출처 / 대상", + "task": "태스크", + "status": "상태", + "duration": "소요 시간", + "time": "시간" + } + }, + "workspace": { + "title": "워크스페이스", + "noFiles": "아직 워크스페이스 파일 없음", + "noFilesDescription": "파일은 팀 에이전트의 협업 중에 생성됩니다.", + "refresh": "새로 고침", + "delete": "삭제", + "confirmDelete": "이 파일을 삭제하시겠습니까?", + "columns": { + "fileName": "파일 이름", + "size": "크기", + "uploadedBy": "업로드한 사람", + "scope": "범위", + "updated": "업데이트됨" + }, + "detail": { + "title": "파일 내용", + "empty": "파일이 비어있거나 바이너리입니다" + }, + "upload": { + "title": "워크스페이스에 업로드", + "description": "협업 중 에이전트가 읽을 파일을 업로드합니다" + }, + "crossScopeMoveError": "다른 범위 간에 파일을 이동할 수 없습니다", + "moveFailed": "파일 이동 실패" + }, + "auditLogs": { + "title": "감사 로그", + "empty": "아직 이벤트 없음", + "loadMore": "더 불러오기", + "event": { + "created": "생성됨", + "claimed": "클레임됨", + "assigned": "할당됨", + "dispatched": "발송됨", + "completed": "완료됨", + "failed": "실패", + "cancelled": "취소됨", + "reviewed": "검토됨", + "approved": "승인됨", + "rejected": "거부됨", + "commented": "댓글 달림", + "progress": "진행 중", + "updated": "업데이트됨", + "stale": "기한 초과" + } + }, + "settings": { + "title": "팀 설정", + "name": "이름", + "displayName": "표시 이름", + "description": "설명", + "leadAgent": "리더 에이전트", + "status": "상태", + "active": "활성", + "inactive": "비활성", + "save": "설정 저장", + "saving": "저장 중...", + "saved": "저장됨", + "failedSave": "저장 실패", + "userAccessControl": "사용자 접근 제어", + "allowedUsers": "허용된 사용자", + "allowedUsersHint": "설정된 경우 이 사용자만 팀 워크플로를 트리거할 수 있습니다. 비어있으면 모두 허용.", + "deniedUsers": "차단된 사용자", + "deniedUsersHint": "항상 차단되며, 허용 목록을 재정의합니다.", + "channelRestrictions": "채널 제한", + "allowedChannels": "허용된 채널", + "allowedChannelsHint": "설정된 경우 이 채널만 팀 워크플로를 활성화할 수 있습니다. 비어있으면 모두 허용.", + "deniedChannels": "차단된 채널", + "deniedChannelsHint": "이 채널의 메시지는 항상 차단됩니다.", + "notifications": "알림", + "notifyDispatched": "태스크 발송됨", + "notifyDispatchedHint": "팀 멤버에게 태스크가 할당될 때 알림.", + "notifyProgress": "태스크 진행", + "notifyProgressHint": "멤버가 태스크 진행률을 업데이트할 때 알림.", + "notifyFailed": "태스크 실패", + "notifyFailedHint": "태스크가 실패할 때 알림.", + "notifySlowTool": "느린 도구 경고", + "notifySlowToolHint": "도구 호출이 비정상적으로 오래 걸릴 때 시스템 경고. 항상 직접 — 리더를 통하지 않음.", + "notifyMode": "전달 모드", + "notifyModeHint": "채팅 채널로 알림이 전달되는 방법입니다.", + "notifyModeDirect": "직접", + "notifyModeDirectDesc": "채팅 채널에 직접 알림을 보냅니다. 빠르고 AI 처리 없음.", + "notifyModeLeader": "리더를 통해", + "notifyModeLeaderDesc": "리더 에이전트가 사용자에게 보내기 전에 업데이트를 자연스럽게 재구성합니다.", + "notifyModeLeaderWarning": "리더 모드는 AI를 사용하여 메시지를 재구성합니다 (토큰 사용, 더 느릴 수 있음).", + "notifyCompleted": "태스크 완료 시 알림", + "notifyCommented": "태스크 댓글 시 알림", + "notifyNewTask": "새 태스크 생성 시 알림", + "memberRequests": "멤버 요청", + "memberRequestsEnabled": "멤버 요청 태스크 허용", + "memberRequestsEnabledDesc": "멤버들이 팀원에게 도움을 요청하는 요청 태스크를 만들 수 있습니다", + "memberRequestsAutoDispatch": "담당자에게 자동 발송", + "memberRequestsAutoDispatchDesc": "요청이 즉시 발송됩니다. 그렇지 않으면 리더 검토를 위해 대기 상태를 유지합니다", + "searchUsers": "사용자 검색...", + "selectChannel": "채널 선택...", + "escalationPolicy": "에스컬레이션 정책", + "escalationMode": "에스컬레이션 모드", + "escalationModeHint": "에이전트가 요청한 권한 있는 워크스페이스 작업(고정, 태그, 다른 사람의 파일 삭제, set_template)이 처리되는 방식을 제어합니다.", + "blockerEscalation": "차단 에스컬레이션", + "blockerEscalationEnabled": "차단 에스컬레이션 활성화", + "blockerEscalationHint": "멤버가 차단 요인을 표시하면 태스크가 자동으로 실패하고 리더에게 업데이트된 지시로 재시도하라는 알림이 전송됩니다.", + "escalationModeAuto": "자동 (기본값)", + "escalationModeAutoDesc": "LLM 리더가 요청을 평가합니다 — 거부하거나 검토 태스크를 생성합니다. 직접 실행하지 않습니다.", + "escalationModeReview": "검토", + "escalationModeReviewDesc": "항상 사람의 승인을 위한 대기 태스크를 생성합니다. 자동 거부 없음.", + "escalationModeReject": "거부", + "escalationModeRejectDesc": "모든 권한 있는 작업 요청을 거부합니다. 잠금 모드.", + "escalationModeNone": "없음", + "escalationModeNoneDesc": "에스컬레이션 정책 없음. 리더 에이전트가 직접 작업을 실행합니다.", + "escalationActions": "에스컬레이션 작업", + "escalationActionsHint": "에스컬레이션이 필요한 워크스페이스 작업을 선택합니다. 선택하지 않으면 모든 권한 있는 작업이 에스컬레이션됩니다.", + "followupReminders": "후속 알림", + "followupInterval": "알림 간격 (분)", + "followupIntervalHint": "각 후속 알림을 사용자에게 보내기 전 대기할 시간입니다.", + "followupMaxReminders": "최대 알림 수", + "followupMaxRemindersHint": "태스크당 최대 알림 수입니다. 0 = 무제한 (사용자가 응답할 때까지 알림).", + "workspace": "워크스페이스", + "workspaceScope": "워크스페이스 범위", + "workspaceScopeHint": "팀 워크스페이스 파일이 구성되는 방식을 제어합니다.", + "workspaceScopeIsolated": "격리됨", + "workspaceScopeIsolatedDesc": "각 대화는 자체 워크스페이스 폴더를 가집니다. 한 채팅의 파일은 다른 채팅에서 보이지 않습니다.", + "workspaceScopeShared": "공유됨", + "workspaceScopeSharedDesc": "모든 대화가 단일 워크스페이스 폴더를 공유합니다. 어떤 채팅에서든 생성된 파일은 모두에게 보입니다.", + "teamVersion": "팀 버전", + "versionBasic": "기본", + "versionAdvanced": "고급", + "versionBasicDesc": "태스크 관리 및 공유 워크스페이스.", + "versionAdvancedDesc": "모든 V1 기능과 실행 잠금, 후속 알림, 검토 워크플로, 진행률 추적, 댓글, 감사 추적, 자동 복구가 포함됩니다.", + "whatsNew": "무엇이 다른가요?", + "versionModal": { + "title": "슈퍼 팀 기능", + "feature": "기능", + "taskManagement": "태스크 관리", + "taskManagementDesc": "태스크 생성, 할당, 완료, 취소", + "sharedWorkspace": "공유 워크스페이스", + "sharedWorkspaceDesc": "파일, 버전, 팀 협업", + "executionLocking": "실행 잠금", + "executionLockingDesc": "자동 복구로 태스크 충돌 방지", + "followupReminders": "후속 알림", + "followupRemindersDesc": "사용자 응답 대기 중 자동 알림", + "reviewWorkflow": "검토 워크플로", + "reviewWorkflowDesc": "완료 전 사람 검토를 위해 제출", + "progressTracking": "진행률 추적", + "progressTrackingDesc": "실시간 백분율 및 단계 업데이트", + "commentsAudit": "댓글 & 감사", + "commentsAuditDesc": "태스크 댓글 및 전체 이벤트 기록", + "autoRecovery": "자동 복구", + "autoRecoveryDesc": "중단된 태스크가 타임아웃 후 자동 재설정", + "escalationPolicy": "차단 에스컬레이션", + "escalationPolicyDesc": "멤버가 차단 요인을 표시할 수 있습니다 — 태스크가 자동 실패하고 리더에게 재시도 알림", + "comingSoon": "준비 중", + "downgradeNote": "다운그레이드는 안전합니다 — V2 데이터가 보존되지만 숨겨집니다.", + "betaNote": "일부 기능은 현재 베타 버전입니다.", + "gotIt": "알겠습니다" + } + }, + "create": { + "title": "팀 만들기", + "name": "이름 *", + "namePlaceholder": "예: 리서치 팀", + "nameHint": "소문자, 숫자, 하이픈", + "description": "설명", + "descriptionPlaceholder": "선택적 팀 설명...", + "leadAgent": "리더 에이전트 *", + "selectLeadAgent": "리더 에이전트 선택...", + "loadingAgents": "에이전트 불러오는 중...", + "noActiveAgents": "활성 에이전트를 찾을 수 없습니다. 먼저 에이전트를 만드세요.", + "members": "멤버", + "membersTooltip": "사전 정의된 에이전트만 팀 멤버로 추가할 수 있습니다. 개방형 에이전트는 사용자별 컨텍스트를 가지며 팀 협업에 필요한 공유 컨텍스트가 없습니다.", + "needMembers": "팀에 최소 1명의 멤버를 선택하세요", + "searchMembers": "멤버 검색 및 추가...", + "displayName": "표시 이름", + "displayNamePlaceholder": "지원 팀", + "cancel": "취소", + "create": "만들기", + "creating": "생성 중..." + }, + "toast": { + "created": "팀 생성됨", + "deleted": "팀 삭제됨", + "updated": "팀 업데이트됨", + "memberAdded": "멤버 추가됨", + "memberRemoved": "멤버 제거됨", + "failedCreate": "팀 생성 실패", + "failedDelete": "팀 삭제 실패", + "failedUpdate": "팀 업데이트 실패", + "failedAddMember": "멤버 추가 실패", + "failedRemoveMember": "멤버 제거 실패", + "taskCreated": "태스크 생성됨", + "taskDeleted": "태스크 삭제됨", + "taskAssigned": "태스크 할당됨", + "taskApproved": "태스크 승인됨", + "taskRejected": "태스크 거부됨", + "tasksBulkDeleted": "태스크 삭제됨", + "failedCreateTask": "태스크 생성 실패", + "failedDeleteTask": "태스크 삭제 실패", + "failedAssignTask": "태스크 할당 실패", + "failedApproveTask": "태스크 승인 실패", + "failedRejectTask": "태스크 거부 실패", + "failedBulkDeleteTasks": "태스크 삭제 실패", + "workspaceFileDeleted": "파일 삭제됨", + "failedDeleteWorkspaceFile": "파일 삭제 실패" + }, + "board": { + "kanban": "보드", + "list": "목록", + "groupBy": "그룹화", + "groupByStatus": "상태", + "groupByOwner": "담당자", + "groupByType": "유형", + "running": "실행 중", + "locked": "에이전트가 실행 중", + "emptyColumn": "태스크 없음", + "unassigned": "미할당", + "createViaChat": "팀 에이전트와 채팅하여 태스크 생성" + }, + "sidebar": { + "members": "멤버", + "workspace": "워크스페이스", + "delegations": "위임", + "settings": "설정", + "addMember": "멤버 추가" + }, + "tabs": { + "teams": "에이전트 팀", + "board": "보드", + "links": "에이전트 링크", + "settings": "설정" + }, + "links": { + "title": "에이전트 링크", + "empty": "에이전트 링크가 설정되지 않았습니다.", + "create": "링크 만들기", + "editLink": "링크 편집", + "save": "저장", + "source": "소스 에이전트", + "target": "대상 에이전트", + "selectAgent": "에이전트 선택...", + "direction": "방향", + "outbound": "아웃바운드", + "inbound": "인바운드", + "bidirectional": "양방향", + "description": "설명", + "descriptionPlaceholder": "선택적 설명...", + "maxConcurrent": "최대 동시", + "status": "상태", + "active": "활성", + "disabled": "비활성화됨", + "deleteTitle": "링크 삭제", + "confirmDelete": "이 에이전트 링크를 삭제하시겠습니까? 취소할 수 없습니다.", + "deleted": "링크 삭제됨", + "deleteFailed": "링크 삭제 실패", + "created": "링크 생성됨", + "createFailed": "링크 생성 실패", + "updated": "링크 업데이트됨", + "updateFailed": "링크 업데이트 실패", + "sameAgentError": "소스와 대상은 다른 에이전트여야 합니다." + } +} diff --git a/ui/web/src/i18n/locales/ko/tenants.json b/ui/web/src/i18n/locales/ko/tenants.json new file mode 100644 index 00000000..daa4b11c --- /dev/null +++ b/ui/web/src/i18n/locales/ko/tenants.json @@ -0,0 +1,33 @@ +{ + "title": "테넌트", + "description": "테넌트 및 사용자 접근 관리", + "createTenant": "테넌트 만들기", + "name": "이름", + "slug": "슬러그", + "status": "상태", + "users": "사용자", + "role": "역할", + "addUser": "사용자 추가", + "removeUser": "사용자 제거", + "userId": "사용자 ID", + "active": "활성", + "suspended": "정지됨", + "archived": "보관됨", + "allTenants": "모든 테넌트", + "currentTenant": "현재 테넌트", + "noTenants": "테넌트 없음", + "confirmRemoveUser": "이 사용자를 테넌트에서 제거하시겠습니까?", + "slugHelp": "URL 안전 식별자 (소문자, 하이픈만)", + "detail": "테넌트 세부 정보", + "back": "테넌트 목록으로", + "userManagement": "사용자 관리", + "addUserTitle": "테넌트에 사용자 추가", + "selectRole": "역할 선택", + "roleOwner": "소유자", + "roleAdmin": "관리자", + "roleOperator": "운영자", + "roleMember": "멤버", + "roleViewer": "뷰어", + "noUsers": "이 테넌트에 사용자 없음", + "created": "생성됨" +} diff --git a/ui/web/src/i18n/locales/ko/tools.json b/ui/web/src/i18n/locales/ko/tools.json new file mode 100644 index 00000000..2c4372c2 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/tools.json @@ -0,0 +1,211 @@ +{ + "custom": { + "title": "커스텀 도구", + "description": "에이전트를 위한 커스텀 셸 기반 도구 관리", + "createTool": "도구 만들기", + "searchPlaceholder": "도구 검색...", + "emptyTitle": "커스텀 도구 없음", + "emptyDescription": "첫 번째 커스텀 도구를 만들어 시작하세요.", + "noMatchTitle": "일치하는 도구 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "noDescription": "설명 없음", + "columns": { + "name": "이름", + "description": "설명", + "scope": "범위", + "enabled": "활성화됨", + "timeout": "타임아웃", + "actions": "작업" + }, + "scope": { + "agent": "에이전트", + "global": "전역" + }, + "delete": { + "title": "커스텀 도구 삭제", + "description": "\"{{name}}\"을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.", + "confirmLabel": "삭제" + }, + "form": { + "createTitle": "커스텀 도구 만들기", + "editTitle": "도구 편집", + "name": "이름 *", + "namePlaceholder": "my-tool", + "nameHint": "소문자, 숫자, 하이픈만 사용", + "description": "설명", + "descriptionPlaceholder": "이 도구의 역할...", + "command": "명령 *", + "commandHint": "셸 템플릿. 매개변수 자리표시자에 {{.key}}를 사용하세요.", + "parameters": "매개변수 (JSON Schema)", + "workingDir": "작업 디렉터리", + "workingDirPlaceholder": "/path/to/dir", + "timeout": "타임아웃 (초)", + "agentId": "에이전트 ID (선택사항)", + "agentIdPlaceholder": "전역 범위로 사용하려면 비워두세요", + "enabled": "활성화됨", + "cancel": "취소", + "create": "만들기", + "update": "업데이트", + "saving": "저장 중...", + "errors": { + "nameRequired": "이름과 명령이 필요합니다", + "nameSlug": "이름은 유효한 슬러그여야 합니다 (소문자, 숫자, 하이픈만 사용)", + "invalidJson": "매개변수는 유효한 JSON이어야 합니다" + } + }, + "toast": { + "created": "도구 생성됨", + "createdDesc": "{{name}}이 추가되었습니다", + "updated": "도구 업데이트됨", + "deleted": "도구 삭제됨", + "failedCreate": "도구 생성 실패", + "failedUpdate": "도구 업데이트 실패", + "failedDelete": "도구 삭제 실패" + } + }, + "builtin": { + "title": "내장 도구", + "description": "시스템 내장 도구를 관리합니다. 전역으로 활성화/비활성화하거나 설정을 구성합니다.", + "searchPlaceholder": "도구 검색...", + "emptyTitle": "내장 도구 없음", + "emptyDescription": "아직 내장 도구가 시딩되지 않았습니다.", + "noMatchTitle": "일치하는 도구 없음", + "noMatchDescription": "다른 검색어를 사용해 보세요.", + "toolCount": "{{count}}개 도구", + "toolCountPlural": "{{count}}개 도구", + "categoryCount": "{{count}}개 카테고리", + "requires": "필요", + "requiresTooltip": "필요: {{list}}", + "deprecated": "더 이상 사용되지 않음", + "deprecatedTooltip": "이 도구는 더 이상 사용되지 않으며 사용할 수 없습니다", + "settings": "설정", + "configuredVia": "설정 페이지에서 구성됨", + "tenantOverride": "테넌트 재정의", + "tenantEnabled": "이 테넌트에서 활성화됨", + "tenantDisabled": "이 테넌트에서 비활성화됨", + "tenantDefault": "기본값 사용", + "resetToDefault": "기본값으로 재설정", + "unconfiguredWarning": "{{count}}개 도구에 에이전트가 최대 성능으로 사용하기 위한 공급자 설정이 필요합니다.", + "unconfiguredAction": "설정", + "categories": { + "filesystem": "파일 시스템", + "runtime": "런타임", + "web": "웹", + "memory": "메모리", + "media": "미디어", + "browser": "브라우저", + "sessions": "세션", + "messaging": "메시징", + "scheduling": "스케줄링", + "subagents": "에이전트", + "skills": "스킬", + "delegation": "위임", + "teams": "팀" + }, + "settingsDialog": { + "title": "설정 — {{name}}", + "cancel": "취소", + "save": "저장", + "saving": "저장 중...", + "noFields": "이 도구에 대한 구성 가능한 설정이 없습니다.", + "toast": { + "saved": "설정 저장됨", + "failed": "설정 저장 실패" + } + }, + "jsonDialog": { + "title": "설정: {{name}}", + "description": "도구별 설정을 JSON으로 편집합니다. 저장 후 즉시 적용됩니다.", + "formatJson": "JSON 포맷", + "invalidJsonSyntax": "잘못된 JSON 구문", + "invalidJson": "잘못된 JSON", + "cannotFormat": "포맷 불가: 잘못된 JSON", + "cancel": "취소", + "save": "저장", + "saving": "저장 중..." + }, + "kgSettings": { + "title": "지식 그래프 설정", + "description": "메모리 쓰기에서 엔티티 추출을 구성합니다. 구조화된 JSON 출력을 지원하는 공급자/모델이 필요합니다.", + "extractionProvider": "추출 공급자", + "extractionModel": "추출 모델", + "providerTip": "텍스트에서 엔티티와 관계를 추출하는 데 사용되는 LLM 공급자입니다.", + "modelTip": "추출 모델 ID입니다. 구조화된 JSON 출력을 지원해야 합니다.", + "minConfidence": "최소 신뢰도", + "minConfidenceHint": "이 신뢰도 미만의 엔티티는 삭제됩니다 (0.0–1.0).", + "autoExtract": "메모리 쓰기 시 자동 추출", + "autoExtractHint": "에이전트가 메모리 파일에 쓸 때 자동으로 엔티티를 추출합니다.", + "cancel": "취소", + "save": "저장", + "saving": "저장 중..." + }, + "extractorChain": { + "title": "웹 가져오기 — 추출기 체인", + "description": "콘텐츠 추출기의 순서 목록입니다. 각 URL은 품질 있는 콘텐츠를 반환할 때까지 위에서 아래로 시도됩니다.", + "timeout": "타임아웃", + "baseUrl": "기본 URL", + "save": "저장", + "saving": "저장 중…", + "cancel": "취소", + "extractors": { + "defuddle": "Defuddle (Cloudflare Worker)", + "defuddleDesc": "Defuddle 라이브러리를 사용하여 fetch.goclaw.sh를 통해 깨끗한 마크다운을 추출합니다.", + "html-to-markdown": "내장 HTML→Markdown", + "html-to-markdownDesc": "숨겨진 요소 감지 기능이 있는 인-프로세스 DOM 기반 변환기입니다." + } + }, + "mediaChain": { + "providerChainSuffix": "— 공급자 체인", + "description": "공급자 폴백을 구성하고 순서를 지정합니다. 드래그하여 순서 변경 — 활성화된 첫 번째 공급자가 먼저 시도됩니다.", + "newProvider": "새 공급자", + "provider": "공급자", + "model": "모델", + "selectProvider": "공급자 선택", + "loadingModels": "불러오는 중...", + "selectModel": "모델 선택", + "timeout": "타임아웃", + "retries": "재시도", + "settings": "설정", + "noProviders": "공급자가 설정되지 않았습니다. 아래에서 추가하세요.", + "addProvider": "공급자 추가", + "cancel": "취소", + "save": "저장", + "saving": "저장 중..." + }, + "toast": { + "toggled": "도구 업데이트됨", + "failedToggle": "도구 업데이트 실패" + }, + "descriptions": { + "read_file": "경로를 기준으로 에이전트의 워크스페이스에서 파일 내용을 읽습니다", + "write_file": "워크스페이스의 파일에 내용을 쓰고, 필요 시 디렉터리를 생성합니다", + "list_files": "워크스페이스 내 지정된 경로의 파일과 디렉터리를 나열합니다", + "edit": "전체 파일을 다시 쓰지 않고 기존 파일에 대상 검색-교체 편집을 적용합니다", + "exec": "워크스페이스에서 셸 명령을 실행하고 stdout/stderr를 반환합니다", + "web_search": "검색 엔진(Brave 또는 DuckDuckGo)을 사용하여 웹에서 정보를 검색합니다", + "web_fetch": "웹 페이지나 API 엔드포인트를 가져와 텍스트 내용을 추출합니다", + "memory_search": "의미 유사성을 사용하여 에이전트의 장기 메모리를 검색합니다", + "memory_get": "파일 경로로 특정 메모리 문서를 검색합니다", + "knowledge_graph_search": "에이전트의 지식 그래프에서 엔티티, 관계, 관찰을 검색합니다", + "read_image": "비전 가능 LLM 공급자를 사용하여 이미지를 분석합니다", + "read_document": "문서 가능 LLM 공급자를 사용하여 문서(PDF, Word, Excel, PowerPoint, CSV 등)를 분석합니다", + "create_image": "이미지 생성 공급자를 사용하여 텍스트 프롬프트에서 이미지를 생성합니다", + "read_audio": "오디오 가능 LLM 공급자를 사용하여 오디오 파일(음성, 음악, 사운드)을 분석합니다", + "read_video": "비디오 가능 LLM 공급자를 사용하여 비디오 파일을 분석합니다", + "create_video": "AI를 사용하여 텍스트 설명에서 비디오를 생성합니다", + "create_audio": "AI를 사용하여 텍스트 설명에서 음악이나 음향 효과를 생성합니다", + "tts": "텍스트를 자연스러운 음성 오디오로 변환합니다", + "browser": "브라우저 상호작용 자동화: 페이지 탐색, 요소 클릭, 양식 입력, 스크린샷 촬영", + "sessions_list": "모든 채널의 활성 채팅 세션을 나열합니다", + "session_status": "특정 채팅 세션의 현재 상태와 메타데이터를 가져옵니다", + "sessions_history": "특정 채팅 세션의 메시지 기록을 검색합니다", + "sessions_send": "에이전트를 대신하여 활성 채팅 세션에 메시지를 보냅니다", + "message": "연결된 채널(Telegram, Discord 등)의 사용자에게 선제적 메시지를 보냅니다", + "cron": "cron 표현식, at-time 또는 간격을 사용하여 반복 작업을 예약하거나 관리합니다", + "spawn": "백그라운드에서 태스크를 처리하기 위해 서브에이전트를 생성합니다", + "skill_search": "키워드나 설명으로 사용 가능한 스킬을 검색하여 관련 기능을 찾습니다", + "use_skill": "스킬을 활성화하여 전문화된 기능을 사용합니다 (추적 마커)", + "team_tasks": "팀 태스크 보드의 태스크를 조회, 생성, 업데이트, 완료합니다" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/topbar.json b/ui/web/src/i18n/locales/ko/topbar.json new file mode 100644 index 00000000..94fd2b0a --- /dev/null +++ b/ui/web/src/i18n/locales/ko/topbar.json @@ -0,0 +1,35 @@ +{ + "expandSidebar": "사이드바 펼치기", + "collapseSidebar": "사이드바 접기", + "openMenu": "메뉴 열기", + "systemSettings": "시스템 설정", + "toggleTheme": "테마 전환", + "logout": "로그아웃", + "logoutConfirm": "정말 로그아웃하시겠습니까?", + "language": "언어", + "timezone": "시간대", + "pairingRequests": "페어링 요청", + "pendingPairingRequest": "{{count}}개 페어링 요청 대기 중", + "pendingPairingRequests": "{{count}}개 페어링 요청 대기 중", + "apiKeys": "API 키", + "documents": "문서", + "about": { + "menuItem": "정보", + "title": "GoClaw 정보", + "version": "버전", + "sourceCode": "소스 코드", + "license": "라이선스", + "documentation": "문서", + "reportBug": "버그 신고", + "upToDate": "최신 버전", + "updateAvailable": "업데이트 가능: {{version}}", + "viewRelease": "릴리스 노트 보기 →", + "releaseNotes": "릴리스 노트" + }, + "languages": { + "en": "English", + "vi": "Tiếng Việt", + "zh": "中文", + "ko": "한국어" + } +} diff --git a/ui/web/src/i18n/locales/ko/traces.json b/ui/web/src/i18n/locales/ko/traces.json new file mode 100644 index 00000000..b094cdc8 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/traces.json @@ -0,0 +1,84 @@ +{ + "title": "추적", + "description": "LLM 호출 추적 및 성능 데이터", + "filterPlaceholder": "에이전트 ID로 필터...", + "filter": "필터", + "allAgents": "모든 에이전트", + "allChannels": "모든 채널", + "emptyTitle": "추적 없음", + "emptyDescription": "추적이 없습니다. 에이전트가 요청을 처리하면 기록됩니다.", + "columns": { + "name": "이름", + "status": "상태", + "duration": "소요 시간", + "tokens": "토큰", + "spans": "스팬", + "time": "시간" + }, + "source": { + "direct": "직접", + "group": "그룹", + "cron": "Cron", + "team": "팀", + "ws": "웹", + "unknown": "기타" + }, + "unnamed": "이름 없음", + "stopRun": "실행 중지", + "cached": "캐시됨", + "detail": { + "title": "추적 세부 정보", + "copyTraceId": "추적 ID 복사", + "notFound": "추적을 찾을 수 없습니다.", + "name": "이름:", + "status": "상태:", + "duration": "소요 시간:", + "channel": "채널:", + "tokens": "토큰:", + "spans": "스팬:", + "started": "시작됨:", + "delegatedFrom": "위임 출처:", + "createdAt": "생성됨:", + "input": "입력", + "output": "출력", + "copy": "복사", + "spansCount": "스팬 ({{count}}개)", + "llmCalls": "LLM", + "toolCalls": "도구", + "export": "추적 내보내기", + "stopRun": "실행 중지" + }, + "span": { + "model": "모델:", + "tokens": "토큰:", + "reasoning": "추론:", + "source": "소스", + "requested": "요청됨", + "effective": "실효", + "fallback": "대체", + "modelDefault": "모델 기본값", + "supportedLevels": "지원됨:", + "sourceValue": { + "provider_default": "공급자 기본값", + "reasoning": "에이전트 고급", + "thinking_level": "레거시 사고 레벨", + "unset": "미설정" + }, + "createdAt": "생성됨:", + "input": "입력:", + "output": "출력:", + "copy": "복사", + "startTime": "시작:", + "endTime": "종료:", + "cacheRead": "읽기", + "cacheWrite": "쓰기", + "thinking": "사고 중", + "cached": "캐시됨" + }, + "toast": { + "failedLoad": "추적 로드 실패", + "abortSent": "실행 중지됨", + "abortFailed": "실행 중지 실패", + "abortNotFound": "실행이 이미 완료되었거나 찾을 수 없습니다" + } +} diff --git a/ui/web/src/i18n/locales/ko/tts.json b/ui/web/src/i18n/locales/ko/tts.json new file mode 100644 index 00000000..6aeedf06 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/tts.json @@ -0,0 +1,71 @@ +{ + "title": "텍스트 음성 변환", + "description": "TTS 공급자 및 자동 적용 설정", + "save": "저장", + "saving": "저장 중...", + "saveChanges": "변경사항 저장", + "status": { + "title": "상태", + "configured": "설정됨", + "disabled": "사용 안 함", + "noProvider": "설정된 TTS 공급자 없음", + "activeProvider": "기본 공급자: {{provider}}, 자동: {{auto}}" + }, + "general": { + "title": "일반 설정", + "primaryProvider": "기본 공급자", + "autoApplyMode": "자동 적용 모드", + "replyMode": "답장 모드", + "maxTextLength": "최대 텍스트 길이", + "timeout": "제한 시간 (ms)" + }, + "providers": { + "none": "없음 (사용 안 함)", + "openai": "OpenAI", + "elevenlabs": "ElevenLabs", + "edge": "Edge (무료)", + "minimax": "MiniMax" + }, + "autoModes": { + "off": "끄기", + "offDesc": "에이전트가 TTS 도구를 수동으로 사용할 수 있음", + "always": "항상", + "alwaysDesc": "모든 답장에 오디오 적용", + "inbound": "수신", + "inboundDesc": "사용자가 음성/오디오를 보낼 때만", + "tagged": "태그됨", + "taggedDesc": "답장에 [[tts]] 태그가 있을 때만" + }, + "replyModes": { + "final": "최종만", + "finalDesc": "최종 답장만", + "all": "전체", + "allDesc": "도구/블록 포함 모든 답장" + }, + "providerSettings": "{{provider}} 설정", + "openai": { + "apiKey": "API 키", + "apiBase": "API 기본 URL", + "model": "모델", + "voice": "음성" + }, + "elevenlabs": { + "apiKey": "API 키", + "baseUrl": "기본 URL", + "voiceId": "음성 ID", + "modelId": "모델 ID" + }, + "edge": { + "voice": "음성", + "speechRate": "발화 속도", + "hint": "Edge TTS는 무료이며 API 키가 필요 없습니다. 설치 명령: pip install edge-tts" + }, + "minimax": { + "apiKey": "API 키", + "groupId": "그룹 ID *", + "groupIdPlaceholder": "MiniMax에 필요", + "apiBase": "API 기본", + "model": "모델", + "voiceId": "음성 ID" + } +} diff --git a/ui/web/src/i18n/locales/ko/usage.json b/ui/web/src/i18n/locales/ko/usage.json new file mode 100644 index 00000000..00e80d0b --- /dev/null +++ b/ui/web/src/i18n/locales/ko/usage.json @@ -0,0 +1,97 @@ +{ + "title": "사용량", + "description": "에이전트별 토큰 사용량 및 비용", + "emptyTitle": "사용량 데이터 없음", + "emptyDescription": "에이전트가 요청을 처리하면 여기에 사용량 데이터가 나타납니다.", + "summary": { + "sessions": "{{count}}개 세션", + "inputTokens": "입력 토큰", + "outputTokens": "출력 토큰", + "total": "합계" + }, + "recentRecords": "최근 기록", + "columns": { + "agent": "에이전트", + "model": "모델", + "provider": "공급자", + "input": "입력", + "output": "출력", + "total": "합계", + "channel": "채널", + "cost": "비용", + "status": "상태" + }, + "analytics": { + "title": "사용량 분석", + "period24h": "24시간", + "period7d": "7일", + "period30d": "30일", + "periodCustom": "사용자 지정", + "allAgents": "모든 에이전트", + "allProviders": "모든 공급자", + "allChannels": "모든 채널", + "activeFilters": "활성 필터", + "clearAll": "전체 지우기", + "exportCsv": "CSV 내보내기", + "requests": "요청", + "tokens": "토큰", + "cost": "비용", + "errors": "오류", + "uniqueUsers": "고유 사용자", + "llmCalls": "LLM 호출", + "toolCalls": "도구 호출", + "trendUp": "+{{value}}%", + "trendDown": "{{value}}%", + "vsPrevious": "이전 기간 대비", + "configurePricing": "비용 추적을 위한 모델 가격 설정", + "noData": "선택한 기간의 데이터 없음", + "tokenChart": { + "title": "시간별 토큰 사용량", + "input": "입력 토큰", + "output": "출력 토큰", + "cache": "캐시 읽기 토큰", + "thinking": "사고 토큰", + "total": "합계" + }, + "requestChart": { + "title": "요청 수량 & 오류", + "requests": "요청", + "errors": "오류", + "errorRate": "오류율" + }, + "distribution": { + "provider": "공급자 분포", + "model": "모델 분포", + "channel": "채널 분포", + "other": "기타", + "calls": "호출" + }, + "durationChart": { + "title": "소요 시간 & 성능", + "avgDuration": "평균 소요 시간", + "errorRate": "오류율 %" + }, + "knowledgeChart": { + "title": "메모리 & 지식 그래프 증가", + "memoryDocs": "메모리 문서", + "memoryChunks": "메모리 청크", + "kgEntities": "KG 엔티티", + "kgRelations": "KG 관계" + }, + "topModels": { + "title": "상위 모델", + "model": "모델", + "provider": "공급자", + "llmCalls": "LLM 호출", + "inputTokens": "입력 토큰", + "outputTokens": "출력 토큰", + "avgDuration": "평균 소요 시간", + "cost": "비용" + }, + "tooltip": { + "date": "날짜", + "total": "합계", + "errorRate": "오류율 {{value}}%" + } + } +} diff --git a/ui/web/src/i18n/locales/ko/v3-capabilities.json b/ui/web/src/i18n/locales/ko/v3-capabilities.json new file mode 100644 index 00000000..c2d64563 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/v3-capabilities.json @@ -0,0 +1,56 @@ +{ + "title": "에이전트 기능 V3", + "subtitle": "에이전트 지능을 구동하는 핵심 시스템", + "note": "v3 에이전트에서는 모든 기능이 항상 활성화됩니다.", + "tabs": { + "pipeline": "파이프라인", + "memory": "메모리", + "knowledge": "지식", + "orchestration": "오케스트레이션" + }, + "pipeline": { + "title": "8단계 실행 파이프라인", + "description": "모든 메시지는 3개 단계의 8개 구조화된 단계를 거칩니다.", + "setup": "설정", + "setupDesc": "에이전트 설정, 워크스페이스 메타데이터, 사용자 기록, 과거 세션의 자동 삽입 메모리로 컨텍스트를 보강합니다.", + "iteration": "반복 루프", + "iterationDesc": "태스크가 완료되거나 최대 반복 횟수에 도달할 때까지 반복합니다.", + "think": "사고", + "thinkDesc": "전체 컨텍스트로 LLM 추론", + "prune": "정리", + "pruneDesc": "토큰 관리 및 압축", + "tools": "도구", + "toolsDesc": "LLM의 도구 호출 실행", + "observe": "관찰", + "observeDesc": "출력 캡처 및 유효성 검사", + "checkpoint": "체크포인트", + "checkpointDesc": "중간 상태 저장", + "finalize": "완료", + "finalizeDesc": "메타데이터 저장, 메모리 통합을 위한 이벤트 발생, 실행 정리." + }, + "memory": { + "title": "3계층 메모리 시스템", + "description": "대화에서 장기 지식까지 단계적 메모리.", + "l0Title": "L0 작업 메모리", + "l0Desc": "토큰 기반 자동 압축이 있는 세션 기록. 기록이 컨텍스트 창 임계값을 초과하면 오래된 메시지가 LLM에 의해 요약되고 잘립니다. 메모리 플러시는 압축 전에 핵심 사실을 영구 파일로 추출합니다.", + "l1Title": "L1 에피소딕 메모리", + "l1Desc": "각 대화 실행 후 생성되는 세션 요약. 각각 빠른 삽입을 위한 L0 추상화(~50 토큰)를 가집니다. 90일 TTL이 있는 하이브리드 FTS + 벡터 검색. 관련 추상화는 매 턴마다 시스템 프롬프트에 자동 삽입됩니다.", + "l2Title": "L2 의미 메모리", + "l2Desc": "LLM으로 추출된 엔티티와 관계가 있는 지식 그래프 (신뢰도 임계값 0.75). 자동 중복 제거로 유사한 엔티티를 병합합니다. 드리밍은 5개 이상의 에피소딕 항목을 메모리 도구로 검색 가능한 장기 사실 문서로 통합합니다.", + "eventFlow": "이벤트 기반: session.completed가 L1 생성을 트리거하고, 이는 L2 추출과 드리밍을 트리거합니다." + }, + "knowledge": { + "kgTitle": "지식 그래프", + "kgDesc": "세션 요약에서 LLM을 통해 사람, 프로젝트, 기술 등의 엔티티와 관계가 추출됩니다. 시간적 버전 관리로 사실이 유효한 시기를 추적합니다. 최대 5단계 다중 홉 순회로 knowledge_graph_search 도구를 통해 검색 가능합니다.", + "vaultTitle": "지식 볼트", + "vaultDesc": "[[위키링크]] 해석이 있는 문서 레지스트리. 통합 검색은 볼트 문서(40%), 에피소딕 메모리(30%), KG 엔티티(30%)를 단일 순위 결과로 혼합합니다. SHA-256 해시로 콘텐츠 변경을 감지하여 증분 인덱싱합니다.", + "dreamingTitle": "드리밍", + "dreamingDesc": "5개 이상의 세션 요약이 누적되면 LLM이 장기 사실을 합성합니다: 사용자 선호도, 프로젝트 아키텍처, 반복 패턴, 근거가 있는 핵심 결정. 검색 가능한 메모리 문서로 저장됩니다. 에이전트당 10분 간격으로 디바운스됩니다." + }, + "orchestration": { + "delegateTitle": "에이전트 위임", + "delegateDesc": "에이전트는 권한 확인을 통해 agent_links로 연결된 에이전트에 태스크를 위임합니다. 동기 모드는 설정 가능한 제한 시간까지 결과를 기다립니다. 비동기 모드는 즉시 실행되고 완료 시 메시지 버스를 통해 결과를 알립니다.", + "evolutionTitle": "자기 진화", + "evolutionDesc": "주간 사이클로 도구 사용 및 검색 메트릭을 추적합니다. 세 가지 패턴을 감지합니다: 낮은 검색 사용률 (< 20%), 높은 도구 실패율 (< 10% 성공), 반복 도구 패턴 (> 100회/주). 가드레일 보호 자동 적용 및 롤백이 있는 설정 조정을 제안합니다." + } +} diff --git a/ui/web/src/i18n/locales/ko/vault.json b/ui/web/src/i18n/locales/ko/vault.json new file mode 100644 index 00000000..1d8cab47 --- /dev/null +++ b/ui/web/src/i18n/locales/ko/vault.json @@ -0,0 +1,109 @@ +{ + "title": "지식 볼트", + "description": "위키링크 및 의미 검색이 있는 문서 레지스트리", + "search": "검색", + "searchPlaceholder": "문서 검색...", + "filterAgent": "에이전트", + "allAgents": "모든 에이전트", + "allTypes": "전체", + "noDocuments": "볼트에 문서 없음", + "noResults": "검색 결과 없음", + "searchFailed": "검색 실패", + "create": "만들기", + "createDoc": "문서 만들기", + "edit": "편집", + "save": "저장", + "saving": "저장 중...", + "cancel": "취소", + "delete": "삭제", + "confirmDelete": "이 문서를 삭제하시겠습니까?", + "yes": "예", + "no": "아니오", + "createLink": "링크 추가", + "addLink": "링크 추가", + "deleteLink": "링크 삭제", + "columns": { + "title": "제목", + "agent": "에이전트", + "path": "경로", + "type": "유형", + "scope": "범위", + "updated": "업데이트됨" + }, + "detail": { + "metadata": "메타데이터", + "outlinks": "나가는 링크", + "backlinks": "백링크", + "noLinks": "링크 없음", + "contentPreview": "내용 미리보기", + "fileNotFound": "파일을 찾을 수 없거나 접근할 수 없습니다", + "emptyContent": "사용 가능한 내용 없음", + "binaryFile": "바이너리 파일 — 미리보기 불가" + }, + "fields": { + "title": "제목", + "titlePlaceholder": "문서 제목", + "path": "경로", + "pathPlaceholder": "예: notes/my-doc.md", + "docType": "유형", + "scope": "범위", + "fromDoc": "출처", + "toDoc": "대상 문서", + "selectDoc": "문서 선택...", + "linkType": "링크 유형", + "linkContext": "컨텍스트", + "linkContextPlaceholder": "이 링크의 선택적 컨텍스트" + }, + "scope": { + "personal": "개인", + "team": "팀", + "shared": "공유" + }, + "type": { + "context": "컨텍스트", + "memory": "메모리", + "note": "노트", + "skill": "스킬", + "episodic": "에피소딕", + "media": "미디어", + "document": "문서" + }, + "rescanTooltip": "워크스페이스 재검사", + "enriching": "보강 중", + "enrichComplete": "보강 완료", + "rescanNew": "{{count}}개 새로운", + "rescanUpdated": "{{count}}개 업데이트됨", + "rescanUnchanged": "{{count}}개 변경 없음", + "rescanTruncated": "검사 중단됨 (제한 도달)", + "rescanNoFiles": "새 파일을 찾을 수 없습니다", + "rescanBusy": "재검사가 이미 진행 중입니다", + "rescanError": "재검사 실패", + "upload": { + "title": "볼트에 업로드", + "destination": "대상", + "shared": "공유", + "agent": "에이전트", + "team": "팀", + "selectAgent": "에이전트 선택...", + "selectTeam": "팀 선택...", + "dropzone": "여기에 파일을 놓거나 클릭하여 찾아보기", + "dropzoneHint": "텍스트 파일만 (.md, .txt, .json, .yaml, .csv, ...)", + "files": "파일 ({{count}}개)", + "uploading": "업로드 중...", + "upload": "업로드" + }, + "toast": { + "uploadSuccess": "{{count}}개 파일 업로드됨", + "uploadFailed": "업로드 실패", + "docCreated": "문서 생성됨", + "docCreateFailed": "문서 생성 실패", + "docUpdated": "문서 업데이트됨", + "docUpdateFailed": "문서 업데이트 실패", + "docDeleted": "문서 삭제됨", + "docDeleteFailed": "문서 삭제 실패", + "linkCreated": "링크 생성됨", + "linkCreateFailed": "링크 생성 실패", + "linkDeleted": "링크 삭제됨", + "linkDeleteFailed": "링크 삭제 실패" + } +} diff --git a/ui/web/src/lib/constants.ts b/ui/web/src/lib/constants.ts index 580ce751..b312c027 100644 --- a/ui/web/src/lib/constants.ts +++ b/ui/web/src/lib/constants.ts @@ -20,11 +20,12 @@ export const LOCAL_STORAGE_KEYS = { TIMEZONE: "goclaw:timezone", } as const; -export const SUPPORTED_LANGUAGES = ["en", "vi", "zh"] as const; +export const SUPPORTED_LANGUAGES = ["en", "vi", "zh", "ko"] as const; export type Language = (typeof SUPPORTED_LANGUAGES)[number]; export const LANGUAGE_LABELS: Record = { en: "English", vi: "Tiếng Việt", zh: "中文", + ko: "한국어", };