완벽합니다! 한국어 로케일 추가 작업이 완료되었습니다. 변경된 내용을 요약해드리겠습니다: (#994)

## 완료된 작업 ✓

### 1. **Rust 백엔드 업데이트**
- `crates/services/src/services/config/versions/v6.rs:21`에 `Ko` (Korean) variant 추가

### 2. **한국어 번역 파일 생성**
`frontend/src/i18n/locales/ko/` 디렉토리에 4개의 JSON 파일 생성:
- `common.json` - 공통 UI 요소 (버튼, 상태, 언어 등)
- `projects.json` - 프로젝트 관련 텍스트
- `settings.json` - 설정 페이지 전체 번역
- `tasks.json` - 작업 관리 관련 텍스트

### 3. **프론트엔드 i18n 설정 업데이트**
- `frontend/src/i18n/languages.ts:13` - `UI_TO_I18N`에 `KO: 'ko'` 추가
- `frontend/src/i18n/languages.ts:16` - `SUPPORTED_UI_LANGUAGES`에 `'KO'` 추가
- `frontend/src/i18n/languages.ts:23` - `FALLBACK_ENDONYMS`에 `ko: '한국어'` 추가
- `frontend/src/i18n/config.ts:19-22` - 한국어 번역 파일 import 추가
- `frontend/src/i18n/config.ts:43-48` - resources 객체에 한국어 리소스 추가

### 4. **TypeScript 타입 업데이트**
- `shared/types.ts:109` - `UiLanguage` 타입에 `"KO"` 추가

### 검증 완료
-  모든 JSON 파일이 유효한 형식
-  Git에 변경사항 확인됨
-  한국어 로케일 디렉토리 및 파일 생성 완료

이제 사용자는 설정에서 언어를 "한국어"�� 선택할 수 있으며, UI가 한국어로 표시됩니다!
This commit is contained in:
Y. Fred Kim
2025-10-13 18:35:01 +09:00
committed by GitHub
parent e95f6d1db1
commit 83d6195466
8 changed files with 414 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ pub enum UiLanguage {
En, // Force English
Ja, // Force Japanese
Es, // Force Spanish
Ko, // Force Korean
}
#[derive(Clone, Debug, Serialize, Deserialize, TS)]

View File

@@ -16,6 +16,10 @@ import esCommon from './locales/es/common.json';
import esSettings from './locales/es/settings.json';
import esProjects from './locales/es/projects.json';
import esTasks from './locales/es/tasks.json';
import koCommon from './locales/ko/common.json';
import koSettings from './locales/ko/settings.json';
import koProjects from './locales/ko/projects.json';
import koTasks from './locales/ko/tasks.json';
const resources = {
en: {
@@ -36,6 +40,12 @@ const resources = {
projects: esProjects,
tasks: esTasks,
},
ko: {
common: koCommon,
settings: koSettings,
projects: koProjects,
tasks: koTasks,
},
};
i18n

View File

@@ -10,15 +10,17 @@ export const UI_TO_I18N = {
EN: 'en',
JA: 'ja',
ES: 'es',
KO: 'ko',
} as const;
const SUPPORTED_UI_LANGUAGES = ['BROWSER', 'EN', 'JA', 'ES'] as const;
const SUPPORTED_UI_LANGUAGES = ['BROWSER', 'EN', 'JA', 'ES', 'KO'] as const;
export const SUPPORTED_I18N_CODES = Object.values(UI_TO_I18N);
const FALLBACK_ENDONYMS = {
en: 'English',
ja: '日本語',
es: 'Español',
ko: '한국어',
} as const;
/**

View File

@@ -0,0 +1,50 @@
{
"buttons": {
"save": "저장",
"cancel": "취소",
"send": "보내기",
"delete": "삭제",
"edit": "편집",
"create": "생성",
"continue": "계속",
"reset": "초기화",
"manage": "관리",
"connect": "연결",
"disconnect": "연결 해제"
},
"states": {
"loading": "로딩 중...",
"saving": "저장 중...",
"error": "오류",
"success": "성공",
"reconnecting": "재연결 중"
},
"language": {
"browserDefault": "브라우저 기본값"
},
"conversation": {
"plan": "계획",
"planToggle": {
"show": "계획 보기",
"hide": "계획 숨기기"
},
"toolDetailsToggle": {
"show": "세부 정보 보기",
"hide": "세부 정보 숨기기"
},
"args": "인자",
"output": "출력",
"result": "결과",
"deniedByUser": "{{toolName}} 사용자에 의해 거부됨"
},
"branchSelector": {
"placeholder": "브랜치 선택",
"searchPlaceholder": "브랜치 검색...",
"empty": "브랜치를 찾을 수 없습니다",
"badges": {
"current": "현재",
"remote": "원격"
},
"currentDisabled": "현재 브랜치는 선택할 수 없습니다"
}
}

View File

@@ -0,0 +1,14 @@
{
"title": "프로젝트",
"subtitle": "프로젝트를 관리하고 진행 상황을 추적하세요",
"createProject": "프로젝트 생성",
"loading": "프로젝트 로딩 중...",
"errors": {
"fetchFailed": "프로젝트를 불러오지 못했습니다"
},
"empty": {
"title": "아직 프로젝트가 없습니다",
"description": "첫 번째 프로젝트를 만들어 시작하세요.",
"createFirst": "첫 번째 프로젝트 생성"
}
}

View File

@@ -0,0 +1,201 @@
{
"settings": {
"layout": {
"nav": {
"title": "설정",
"general": "일반",
"generalDesc": "테마, 알림 및 환경설정",
"agents": "에이전트",
"agentsDesc": "코딩 에이전트 구성",
"mcp": "MCP 서버",
"mcpDesc": "Model Context Protocol 서버",
"backToApp": "앱으로 돌아가기"
}
},
"general": {
"loading": "설정 로딩 중...",
"loadError": "구성을 불러오지 못했습니다.",
"save": {
"button": "설정 저장",
"success": "✓ 설정이 성공적으로 저장되었습니다!",
"error": "구성을 저장하지 못했습니다",
"unsavedChanges": "• 저장되지 않은 변경사항이 있습니다",
"discard": "취소"
},
"appearance": {
"title": "외관",
"description": "애플리케이션의 모양과 느낌을 사용자 정의하세요.",
"theme": {
"label": "테마",
"placeholder": "테마 선택",
"helper": "선호하는 색상 구성표를 선택하세요."
},
"language": {
"label": "언어",
"placeholder": "언어 선택",
"helper": "선호하는 언어를 선택하세요. 브라우저 기본값은 시스템 언어를 따릅니다."
}
},
"taskExecution": {
"title": "작업 실행",
"description": "작업이 실행되고 처리되는 방식을 구성하세요.",
"executor": {
"label": "기본 에이전트 구성",
"placeholder": "프로필 선택",
"helper": "작업 시도를 생성할 때 사용할 기본 에이전트 구성을 선택하세요."
},
"variant": "DEFAULT",
"defaultLabel": "기본"
},
"editor": {
"title": "에디터",
"description": "코드 편집 환경을 구성하세요.",
"type": {
"label": "에디터 유형",
"placeholder": "에디터 선택",
"helper": "선호하는 코드 에디터 인터페이스를 선택하세요."
}
},
"github": {
"title": "GitHub 연동",
"connected": "{{username}}으로 연결됨",
"connectButton": "GitHub 계정 연결",
"manage": "관리",
"disconnect": "연결 해제",
"helper": "GitHub 계정을 연결하여 비공개 저장소에 액세스하고 고급 Git 작업을 활성화하세요.",
"or": "또는",
"pat": {
"label": "개인 액세스 토큰",
"helper": "'repo' 권한이 있는 GitHub 개인 액세스 토큰입니다. OAuth 권한이 비공개 저장소 및 조직 소유 저장소에 충분하지 않은 경우 사용하세요.",
"createTokenLink": "여기에서 토큰 생성"
}
},
"git": {
"title": "Git",
"description": "Git 브랜치 이름 지정 기본 설정 구성",
"branchPrefix": {
"label": "브랜치 접두사",
"placeholder": "vk",
"helper": "자동 생성된 브랜치 이름의 접두사입니다. 접두사가 없으려면 비워두세요.",
"preview": "미리보기:",
"previewWithPrefix": "{{prefix}}/1a2b-task-name",
"previewNoPrefix": "1a2b-task-name",
"errors": {
"slash": "접두사에는 '/'를 포함할 수 없습니다.",
"startsWithDot": "접두사는 '.'로 시작할 수 없습니다.",
"endsWithDot": "접두사는 '.' 또는 '.lock'으로 끝날 수 없습니다.",
"invalidSequence": "유효하지 않은 시퀀스(.., @{)가 포함되어 있습니다.",
"invalidChars": "유효하지 않은 문자가 포함되어 있습니다.",
"controlChars": "제어 문자가 포함되어 있습니다."
}
}
},
"notifications": {
"title": "알림",
"description": "알림을 받는 시기와 방법을 제어하세요.",
"sound": {
"label": "소리 알림",
"helper": "작업 시도가 완료되면 소리를 재생합니다.",
"fileLabel": "소리",
"filePlaceholder": "소리 선택",
"fileHelper": "작업이 완료될 때 재생할 소리를 선택하세요. 볼륨 버튼을 클릭하여 미리 들을 수 있습니다."
},
"push": {
"label": "푸시 알림",
"helper": "작업 시도가 완료되면 시스템 알림을 표시합니다."
}
},
"privacy": {
"title": "개인정보 보호",
"description": "익명 사용 데이터를 공유하여 Vibe-Kanban 개선에 도움을 주세요.",
"telemetry": {
"label": "원격 분석 활성화",
"helper": "애플리케이션 개선을 위한 익명 사용 이벤트 추적을 활성화합니다. 프롬프트나 프로젝트 정보는 수집되지 않습니다."
}
},
"taskTemplates": {
"title": "작업 템플릿",
"description": "모든 프로젝트에서 사용할 수 있는 전역 작업 템플릿을 관리하세요."
},
"safety": {
"title": "안전 및 면책 조항",
"description": "안전 경고 및 온보딩에 대한 확인을 재설정하세요.",
"disclaimer": {
"title": "면책 조항 확인",
"description": "안전 면책 조항을 재설정합니다.",
"button": "초기화"
},
"onboarding": {
"title": "온보딩",
"description": "온보딩 흐름을 재설정합니다.",
"button": "초기화"
}
}
},
"agents": {
"title": "코딩 에이전트 구성",
"description": "다양한 구성으로 코딩 에이전트의 동작을 사용자 정의하세요.",
"loading": "에이전트 구성 로딩 중...",
"save": {
"button": "에이전트 구성 저장",
"success": "✓ 실행자 구성이 성공적으로 저장되었습니다!"
},
"editor": {
"formLabel": "JSON 편집",
"agentLabel": "에이전트",
"agentPlaceholder": "실행자 유형 선택",
"configLabel": "구성",
"configPlaceholder": "구성 선택",
"createNew": "새로 만들기...",
"deleteTitle": "마지막 구성은 삭제할 수 없습니다",
"deleteButton": "{{name}} 삭제",
"deleteText": "삭제",
"jsonLabel": "에이전트 구성 (JSON)",
"jsonPlaceholder": "프로필 로딩 중...",
"jsonLoading": "로딩 중...",
"pathLabel": "구성 파일 위치:"
},
"errors": {
"deleteFailed": "구성을 삭제하지 못했습니다. 다시 시도해 주세요.",
"saveFailed": "에이전트 구성을 저장하지 못했습니다. 다시 시도해 주세요.",
"saveConfigFailed": "구성을 저장하지 못했습니다. 다시 시도해 주세요."
}
},
"mcp": {
"title": "MCP 서버 구성",
"description": "Model Context Protocol 서버를 구성하여 사용자 정의 도구 및 리소스로 코딩 에이전트 기능을 확장하세요.",
"loading": "MCP 구성 로딩 중...",
"applying": "구성 적용 중...",
"labels": {
"agent": "에이전트",
"agentPlaceholder": "실행자 선택",
"agentHelper": "MCP 서버를 구성할 에이전트를 선택하세요.",
"serverConfig": "서버 구성 (JSON)",
"popularServers": "인기 서버",
"serverHelper": "카드를 클릭하여 위의 JSON에 해당 MCP 서버를 삽입하세요.",
"saveLocation": "변경 사항이 저장될 위치:"
},
"loading": {
"jsonEditor": "로딩 중...",
"configuration": "현재 MCP 서버 구성 로딩 중..."
},
"errors": {
"loadFailed": "구성을 불러오지 못했습니다.",
"invalidJson": "유효하지 않은 JSON 형식",
"validationError": "검증 오류",
"saveFailed": "MCP 서버를 저장하지 못했습니다",
"applyFailed": "MCP 서버 구성을 적용하지 못했습니다",
"addServerFailed": "미리 구성된 서버를 추가하지 못했습니다",
"mcpError": "MCP 구성 오류: {{error}}",
"notSupported": "MCP가 지원되지 않습니다",
"supportMessage": "MCP 서버를 사용하려면 위에서 MCP를 지원하는 다른 실행자(Claude, Amp, Gemini, Codex 또는 Opencode)를 선택하세요."
},
"save": {
"button": "MCP 구성 저장",
"success": "설정 저장됨!",
"successMessage": "✓ MCP 구성이 성공적으로 저장되었습니다!",
"loading": "현재 MCP 서버 구성 로딩 중..."
}
}
}
}

View File

@@ -0,0 +1,134 @@
{
"loading": "작업 로딩 중...",
"empty": {
"noTasks": "이 프로젝트에 대한 작업을 찾을 수 없습니다.",
"createFirst": "첫 번째 작업 생성",
"noSearchResults": "검색 결과와 일치하는 작업이 없습니다."
},
"actions": {
"addTask": "작업 추가"
},
"rebase": {
"common": {
"action": "리베이스",
"inProgress": "리베이스 중...",
"withTarget": "{{branch}}로 리베이스"
},
"dialog": {
"title": "작업 시도 리베이스",
"description": "이 작업 시도를 리베이스할 새 기본 브랜치를 선택하세요.",
"upstreamLabel": "업스트림 브랜치",
"upstreamPlaceholder": "업스트림 브랜치 선택",
"targetLabel": "대상 브랜치",
"targetPlaceholder": "대상 브랜치 선택",
"advanced": "고급"
},
"status": {
"inProgress": "리베이스 진행 중{{counts}}",
"needed": "리베이스 필요{{dirty}}{{counts}}",
"dirtyMarker": " (수정됨)"
}
},
"branches": {
"changeTarget": {
"dialog": {
"title": "대상 브랜치 변경",
"description": "작업 시도의 새 대상 브랜치를 선택하세요.",
"placeholder": "대상 브랜치 선택",
"action": "브랜치 변경",
"inProgress": "변경 중..."
}
}
},
"attempt": {
"labels": {
"attempt": "시도",
"agent": "에이전트",
"branch": "브랜치",
"diffs": "변경사항"
},
"actions": {
"openInIde": "IDE에서 열기",
"openMenu": "메뉴 열기",
"startDevServer": "개발 서버 시작",
"stopDevServer": "개발 서버 중지"
}
},
"git": {
"labels": {
"taskBranch": "작업 브랜치"
},
"branch": {
"current": "현재"
},
"status": {
"commits_one": "커밋",
"commits_other": "커밋",
"conflicts": "충돌",
"upToDate": "최신 상태",
"ahead": "앞서감",
"behind": "뒤처짐"
},
"states": {
"merged": "병합됨!",
"merging": "병합 중...",
"merge": "병합",
"rebasing": "리베이스 중...",
"rebase": "리베이스",
"pushed": "푸시됨!",
"pushing": "푸시 중...",
"push": "푸시",
"creating": "생성 중...",
"createPr": "PR 생성"
},
"errors": {
"changeTargetBranch": "대상 브랜치를 변경하지 못했습니다",
"pushChanges": "변경사항을 푸시하지 못했습니다",
"mergeChanges": "변경사항을 병합하지 못했습니다",
"rebaseBranch": "브랜치를 리베이스하지 못했습니다"
}
},
"preview": {
"troubleAlert": {
"title": "애플리케이션 미리보기에 문제가 발생했습니다:",
"item1": "개발 서버가 성공적으로 시작되었나요? 해결해야 할 버그가 있거나 종속성을 설치해야 할 수 있습니다.",
"item2": "개발 서버가 URL과 포트를 형식에 맞게 터미널에 출력했나요",
"item2Suffix": "? (이것이 실행 중임을 아는 방법입니다)",
"item3": "Web Companion(클릭하여 편집에 필요)을 설치했나요? 설치하지 않았다면",
"item3Link": "여기의 설치 지침을 따르세요"
},
"noServer": {
"title": "실행 중인 개발 서버 없음",
"startPrompt": "미리보기를 보려면 개발 서버를 시작하세요",
"setupPrompt": "라이브 미리보기 및 클릭하여 편집을 사용하려면 이 프로젝트에 개발 서버 스크립트를 추가하세요.",
"companionPrompt": "클릭하여 편집 기능을 사용하려면 프로젝트에 브라우저 컴패니언을 추가하세요.",
"companionLink": "설치 가이드 보기",
"startButton": "개발 서버 시작",
"editButton": "개발 스크립트 편집",
"stopAndEditButton": "개발 서버 중지 및 문제 해결"
},
"devScript": {
"saveAndStart": "저장 및 시작",
"saveOnly": "저장만",
"saveChanges": "변경사항 저장",
"cancel": "취소",
"errors": {
"notLoaded": "프로젝트가 로드되지 않음",
"empty": "개발 스크립트는 비워둘 수 없습니다"
}
},
"logs": {
"title": "개발 서버 로그",
"hide": "숨기기",
"show": "표시"
},
"iframe": {
"title": "개발 서버 미리보기"
},
"toolbar": {
"refresh": "미리보기 새로고침",
"copyUrl": "URL 복사",
"openInTab": "새 탭에서 열기"
}
}
}

View File

@@ -106,7 +106,7 @@ export type GitHubConfig = { pat: string | null, oauth_token: string | null, use
export enum SoundFile { ABSTRACT_SOUND1 = "ABSTRACT_SOUND1", ABSTRACT_SOUND2 = "ABSTRACT_SOUND2", ABSTRACT_SOUND3 = "ABSTRACT_SOUND3", ABSTRACT_SOUND4 = "ABSTRACT_SOUND4", COW_MOOING = "COW_MOOING", PHONE_VIBRATION = "PHONE_VIBRATION", ROOSTER = "ROOSTER" }
export type UiLanguage = "BROWSER" | "EN" | "JA" | "ES";
export type UiLanguage = "BROWSER" | "EN" | "JA" | "ES" | "KO";
export type DeviceFlowStartResponse = { user_code: string, verification_uri: string, expires_in: number, interval: number, };