feat(i18n): add Korean (ko-KR) localization

- Add complete Korean locale across all 7 i18n namespaces
- All translation keys match the English baseline 1:1
- Register ko-KR in SUPPORTED_LOCALES and i18n-check validation

Refs siddharthvaddem/openscreen#406
This commit is contained in:
kwakseongjae
2026-04-10 16:00:25 +09:00
parent e7d5f51740
commit d512f59826
9 changed files with 427 additions and 2 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ import path from "node:path";
const LOCALES_DIR = path.resolve("src/i18n/locales");
const BASE_LOCALE = "en";
const COMPARE_LOCALES = ["zh-CN", "es", "tr"];
const COMPARE_LOCALES = ["zh-CN", "es", "tr", "ko-KR"];
function getKeys(obj, prefix = "") {
const keys = [];
+1 -1
View File
@@ -1,5 +1,5 @@
export const DEFAULT_LOCALE = "en" as const;
export const SUPPORTED_LOCALES = ["en", "zh-CN", "es", , "fr", "tr"] as const;
export const SUPPORTED_LOCALES = ["en", "zh-CN", "es", "fr", "tr", "ko-KR"] as const;
export const I18N_NAMESPACES = [
"common",
"dialogs",
+29
View File
@@ -0,0 +1,29 @@
{
"actions": {
"cancel": "취소",
"save": "저장",
"delete": "삭제",
"close": "닫기",
"share": "공유",
"done": "완료",
"open": "열기",
"upload": "업로드",
"export": "내보내기",
"file": "파일",
"edit": "편집",
"view": "보기",
"window": "창",
"quit": "종료",
"stopRecording": "녹화 중지"
},
"playback": {
"play": "재생",
"pause": "일시정지",
"fullscreen": "전체화면",
"exitFullscreen": "전체화면 종료"
},
"locale": {
"name": "한국어",
"short": "KO"
}
}
+70
View File
@@ -0,0 +1,70 @@
{
"export": {
"complete": "내보내기 완료",
"yourFormatReady": "{{format}} 파일이 준비되었습니다",
"showInFolder": "폴더에서 보기",
"finalizingVideo": "비디오 내보내기 마무리 중...",
"compilingGifProgress": "GIF 생성 중... {{progress}}%",
"compilingGifWait": "GIF 생성 중... 잠시 시간이 걸릴 수 있습니다",
"takeMoment": "잠시 기다려 주세요...",
"failed": "내보내기 실패",
"tryAgain": "다시 시도해 주세요",
"finalizingVideoTitle": "비디오 마무리 중",
"compilingGif": "GIF 생성 중",
"exportingFormat": "{{format}} 내보내는 중",
"compiling": "생성 중...",
"renderingFrames": "프레임 렌더링 중",
"processing": "처리 중...",
"finalizing": "마무리 중...",
"compilingStatus": "생성 중...",
"status": "상태",
"format": "형식",
"frames": "프레임",
"cancelExport": "내보내기 취소",
"savedSuccessfully": "{{format}} 저장이 완료되었습니다!"
},
"tutorial": {
"triggerLabel": "트리밍 사용법",
"title": "트리밍 사용법",
"description": "비디오에서 불필요한 부분을 잘라내는 방법을 알아보세요.",
"explanationBefore": "트림 도구는 제거할 구간을",
"remove": "지정",
"explanationMiddle": "하는 방식으로 동작합니다 —",
"covered": "빨간 트림 구간으로 덮인",
"explanationAfter": "부분은 내보낼 때 잘려나갑니다.",
"visualExample": "화면 예시",
"removed": "제거됨",
"kept": "유지됨",
"part1": "파트 1",
"part2": "파트 2",
"part3": "파트 3",
"finalVideo": "최종 비디오",
"step1Title": "1. 트림 추가",
"step1DescriptionBefore": "",
"step1DescriptionAfter": "키를 누르거나 가위 아이콘을 클릭해 제거할 구간을 표시하세요.",
"step2Title": "2. 조정",
"step2Description": "빨간 구간의 가장자리를 드래그해 잘라낼 범위를 설정하세요."
},
"unsavedChanges": {
"title": "저장되지 않은 변경 사항",
"message": "저장되지 않은 변경 사항이 있습니다.",
"detail": "닫기 전에 프로젝트를 저장하시겠습니까?",
"saveAndClose": "저장 후 닫기",
"discardAndClose": "저장하지 않고 닫기",
"loadProject": "프로젝트 불러오기...",
"saveProject": "프로젝트 저장...",
"saveProjectAs": "다른 이름으로 프로젝트 저장..."
},
"fileDialogs": {
"saveGif": "내보낸 GIF 저장",
"saveVideo": "내보낸 비디오 저장",
"selectVideo": "비디오 파일 선택",
"saveProject": "OpenScreen 프로젝트 저장",
"openProject": "OpenScreen 프로젝트 열기",
"gifImage": "GIF 이미지",
"mp4Video": "MP4 비디오",
"videoFiles": "비디오 파일",
"openscreenProject": "OpenScreen 프로젝트",
"allFiles": "모든 파일"
}
}
+41
View File
@@ -0,0 +1,41 @@
{
"newRecording": {
"title": "녹화로 돌아가기",
"description": "현재 세션이 저장되었습니다.",
"cancel": "취소",
"confirm": "확인"
},
"errors": {
"noVideoLoaded": "불러온 비디오가 없습니다",
"videoNotReady": "비디오가 준비되지 않았습니다",
"unableToDetermineSourcePath": "소스 비디오 경로를 확인할 수 없습니다",
"failedToSaveGif": "GIF 저장에 실패했습니다",
"gifExportFailed": "GIF 내보내기에 실패했습니다",
"failedToSaveVideo": "비디오 저장에 실패했습니다",
"exportFailed": "내보내기에 실패했습니다",
"exportFailedWithError": "내보내기 실패: {{error}}",
"failedToSaveExport": "내보낸 파일 저장에 실패했습니다",
"failedToSaveExportedVideo": "내보낸 비디오 저장에 실패했습니다",
"failedToRevealInFolder": "폴더에서 파일 표시 오류: {{error}}"
},
"export": {
"canceled": "내보내기가 취소되었습니다",
"exportedSuccessfully": "{{format}} 내보내기가 완료되었습니다"
},
"project": {
"saveCanceled": "프로젝트 저장이 취소되었습니다",
"failedToSave": "프로젝트 저장에 실패했습니다",
"savedTo": "프로젝트가 {{path}}에 저장되었습니다",
"failedToLoad": "프로젝트 불러오기에 실패했습니다",
"invalidFormat": "유효하지 않은 프로젝트 파일 형식입니다",
"loadedFrom": "{{path}}에서 프로젝트를 불러왔습니다"
},
"recording": {
"failedCameraAccess": "카메라 접근 권한 요청에 실패했습니다.",
"cameraBlocked": "카메라 접근이 차단되어 있습니다. 시스템 설정에서 권한을 허용해 주세요.",
"systemAudioUnavailable": "시스템 오디오를 사용할 수 없습니다. 시스템 오디오 없이 녹화합니다.",
"microphoneDenied": "마이크 접근이 거부되었습니다. 오디오 없이 녹화를 계속합니다.",
"cameraDenied": "카메라 접근이 거부되었습니다. 웹캠 없이 녹화를 계속합니다.",
"permissionDenied": "녹화 권한이 거부되었습니다. 화면 녹화를 허용해 주세요."
}
}
+37
View File
@@ -0,0 +1,37 @@
{
"tooltips": {
"hideHUD": "HUD 숨기기",
"closeApp": "앱 닫기",
"restartRecording": "녹화 다시 시작",
"cancelRecording": "녹화 취소",
"pauseRecording": "녹화 일시정지",
"resumeRecording": "녹화 재개",
"openVideoFile": "비디오 파일 열기",
"openProject": "프로젝트 열기"
},
"audio": {
"enableSystemAudio": "시스템 오디오 활성화",
"disableSystemAudio": "시스템 오디오 비활성화",
"enableMicrophone": "마이크 활성화",
"disableMicrophone": "마이크 비활성화",
"defaultMicrophone": "기본 마이크"
},
"webcam": {
"enableWebcam": "웹캠 활성화",
"disableWebcam": "웹캠 비활성화",
"defaultCamera": "기본 카메라",
"searching": "검색 중...",
"noneFound": "카메라를 찾을 수 없음",
"unavailable": "카메라를 사용할 수 없음"
},
"sourceSelector": {
"loading": "소스 불러오는 중...",
"screens": "화면 ({{count}}개)",
"windows": "창 ({{count}}개)",
"defaultSourceName": "화면"
},
"recording": {
"selectSource": "녹화할 소스를 선택해 주세요"
},
"language": "언어"
}
+162
View File
@@ -0,0 +1,162 @@
{
"zoom": {
"level": "줌 레벨",
"selectRegion": "조정할 줌 구간을 선택하세요",
"deleteZoom": "줌 삭제",
"focusMode": {
"title": "포커스 모드",
"manual": "수동",
"auto": "자동",
"autoDescription": "녹화된 커서 위치를 따라 카메라가 이동합니다"
}
},
"speed": {
"playbackSpeed": "재생 속도",
"selectRegion": "조정할 속도 구간을 선택하세요",
"deleteRegion": "속도 구간 삭제",
"customPlaybackSpeed": "재생 속도 직접 입력",
"maxSpeedError": "속도는 16×를 초과할 수 없습니다"
},
"trim": {
"deleteRegion": "트림 구간 삭제"
},
"layout": {
"title": "레이아웃",
"preset": "프리셋",
"selectPreset": "프리셋 선택",
"pictureInPicture": "화면 속 화면",
"verticalStack": "세로 배치",
"webcamShape": "카메라 모양",
"webcamSize": "웹캠 크기"
},
"effects": {
"title": "비디오 효과",
"blurBg": "배경 흐림",
"motionBlur": "모션 블러",
"off": "끄기",
"shadow": "그림자",
"roundness": "모서리 둥글기",
"padding": "여백"
},
"background": {
"title": "배경",
"image": "이미지",
"color": "색상",
"gradient": "그라디언트",
"uploadCustom": "직접 업로드",
"gradientLabel": "그라디언트 {{index}}"
},
"crop": {
"title": "자르기",
"cropVideo": "비디오 자르기",
"dragInstruction": "각 면을 드래그해 자르기 영역을 조정하세요",
"ratio": "비율",
"free": "자유",
"done": "완료",
"lockAspectRatio": "화면 비율 고정",
"unlockAspectRatio": "화면 비율 해제"
},
"exportFormat": {
"mp4": "MP4",
"gif": "GIF",
"mp4Video": "MP4 비디오",
"mp4Description": "고화질 비디오 파일",
"gifAnimation": "GIF 애니메이션",
"gifDescription": "공유용 애니메이션 이미지"
},
"exportQuality": {
"title": "내보내기 품질",
"low": "낮음",
"medium": "보통",
"high": "높음"
},
"gifSettings": {
"frameRate": "GIF 프레임 속도",
"size": "GIF 크기",
"loop": "GIF 반복"
},
"project": {
"save": "프로젝트 저장",
"load": "프로젝트 불러오기"
},
"export": {
"videoButton": "비디오 내보내기",
"gifButton": "GIF 내보내기",
"chooseSaveLocation": "저장 위치 선택"
},
"links": {
"reportBug": "버그 신고",
"starOnGithub": "GitHub에 Star 남기기"
},
"imageUpload": {
"invalidFileType": "지원하지 않는 파일 형식입니다",
"jpgOnly": "JPG 또는 JPEG 이미지 파일을 업로드해 주세요.",
"uploadSuccess": "커스텀 이미지가 성공적으로 업로드되었습니다!",
"failedToUpload": "이미지 업로드에 실패했습니다",
"errorReading": "파일을 읽는 중 오류가 발생했습니다."
},
"annotation": {
"title": "주석 설정",
"active": "활성",
"typeText": "텍스트",
"typeImage": "이미지",
"typeArrow": "화살표",
"textContent": "텍스트 내용",
"textPlaceholder": "텍스트를 입력하세요...",
"fontStyle": "폰트 스타일",
"selectStyle": "스타일 선택",
"size": "크기",
"customFonts": "커스텀 폰트",
"textColor": "텍스트 색상",
"background": "배경",
"none": "없음",
"color": "색상",
"clearBackground": "배경 지우기",
"uploadImage": "이미지 업로드",
"supportedFormats": "지원 형식: JPG, PNG, GIF, WebP",
"arrowDirection": "화살표 방향",
"strokeWidth": "선 두께: {{width}}px",
"arrowColor": "화살표 색상",
"deleteAnnotation": "주석 삭제",
"shortcutsAndTips": "단축키 및 팁",
"tipMovePlayhead": "재생 헤드를 주석 구간으로 옮겨 항목을 선택하세요.",
"tipTabCycle": "Tab 키로 겹치는 항목을 순환할 수 있습니다.",
"tipShiftTabCycle": "Shift+Tab으로 역방향 순환할 수 있습니다.",
"invalidImageType": "지원하지 않는 파일 형식입니다",
"imageFormatsOnly": "JPG, PNG, GIF 또는 WebP 이미지 파일을 업로드해 주세요.",
"imageUploadSuccess": "이미지가 성공적으로 업로드되었습니다!",
"failedImageUpload": "이미지 업로드에 실패했습니다"
},
"fontStyles": {
"classic": "클래식",
"editor": "에디터",
"strong": "강조",
"typewriter": "타자기",
"deco": "데코",
"simple": "심플",
"modern": "모던",
"clean": "클린"
},
"customFont": {
"dialogTitle": "Google 폰트 추가",
"urlLabel": "Google Fonts 가져오기 URL",
"urlPlaceholder": "https://fonts.googleapis.com/css2?family=Roboto&display=swap",
"urlHelp": "Google Fonts에서 폰트 선택 → \"폰트 가져오기\" 클릭 → @import URL 복사",
"nameLabel": "표시 이름",
"namePlaceholder": "내 커스텀 폰트",
"nameHelp": "폰트 선택기에서 표시될 이름입니다",
"addButton": "폰트 추가",
"addingButton": "추가 중...",
"errorEmptyUrl": "Google Fonts 가져오기 URL을 입력해 주세요",
"errorInvalidUrl": "유효한 Google Fonts URL을 입력해 주세요",
"errorEmptyName": "폰트 이름을 입력해 주세요",
"errorExtractFailed": "URL에서 폰트 패밀리를 추출할 수 없습니다",
"successMessage": "\"{{fontName}}\" 폰트가 성공적으로 추가되었습니다",
"failedToAdd": "폰트 추가에 실패했습니다",
"errorTimeout": "폰트 로딩 시간이 초과되었습니다. URL을 확인하고 다시 시도해 주세요.",
"errorLoadFailed": "폰트를 불러올 수 없습니다. Google Fonts URL이 올바른지 확인해 주세요."
},
"language": {
"title": "언어"
}
}
+36
View File
@@ -0,0 +1,36 @@
{
"title": "키보드 단축키",
"customize": "사용자 지정",
"configurable": "변경 가능",
"fixed": "고정",
"pressKey": "키를 누르세요...",
"clickToChange": "클릭해서 변경",
"pressEscToCancel": "Esc를 눌러 취소",
"helpText": "단축키를 클릭한 후 새 키 조합을 누르세요. 취소하려면 Esc를 누르세요.",
"resetToDefaults": "기본값으로 초기화",
"alreadyUsedBy": "이미 {{action}}에서 사용 중입니다",
"swap": "교체",
"reservedShortcut": "이 단축키는 \"{{label}}\"에 예약되어 있어 변경할 수 없습니다.",
"savedToast": "키보드 단축키가 저장되었습니다",
"resetToast": "기본 단축키로 초기화되었습니다 — 저장을 클릭해 적용하세요",
"actions": {
"addZoom": "줌 추가",
"addTrim": "트림 추가",
"addSpeed": "속도 추가",
"addAnnotation": "주석 추가",
"addKeyframe": "키프레임 추가",
"deleteSelected": "선택 항목 삭제",
"playPause": "재생 / 일시정지"
},
"fixedActions": {
"undo": "실행 취소",
"redo": "다시 실행",
"cycleAnnotationsForward": "주석 앞으로 순환",
"cycleAnnotationsBackward": "주석 뒤로 순환",
"deleteSelectedAlt": "선택 항목 삭제 (대체)",
"panTimeline": "타임라인 이동",
"zoomTimeline": "타임라인 확대/축소",
"frameBack": "이전 프레임",
"frameForward": "다음 프레임"
}
}
+50
View File
@@ -0,0 +1,50 @@
{
"buttons": {
"addZoom": "줌 추가 (Z)",
"suggestZooms": "커서 기반 줌 제안",
"addTrim": "트림 추가 (T)",
"addAnnotation": "주석 추가 (A)",
"addSpeed": "속도 추가 (S)"
},
"hints": {
"pressZoom": "Z를 눌러 줌 추가",
"pressTrim": "T를 눌러 트림 추가",
"pressAnnotation": "A를 눌러 주석 추가",
"pressSpeed": "S를 눌러 속도 추가"
},
"labels": {
"pan": "이동",
"zoom": "줌",
"zoomItem": "줌 {{index}}",
"trimItem": "트림 {{index}}",
"speedItem": "속도 {{index}}",
"annotationItem": "주석",
"imageItem": "이미지",
"emptyText": "빈 텍스트"
},
"emptyState": {
"noVideo": "불러온 비디오 없음",
"dragAndDrop": "비디오를 드래그 앤 드롭해서 편집을 시작하세요"
},
"errors": {
"cannotPlaceZoom": "이 위치에 줌을 추가할 수 없습니다",
"zoomExistsAtLocation": "이 위치에 이미 줌이 있거나 공간이 부족합니다.",
"zoomSuggestionUnavailable": "줌 제안 기능을 사용할 수 없습니다",
"noCursorTelemetry": "커서 데이터가 없습니다",
"noCursorTelemetryDescription": "커서 기반 제안을 생성하려면 먼저 화면을 녹화해 주세요.",
"noUsableTelemetry": "사용 가능한 커서 데이터가 없습니다",
"noUsableTelemetryDescription": "녹화에 충분한 커서 이동 데이터가 포함되어 있지 않습니다.",
"noDwellMoments": "명확한 커서 정지 구간을 찾을 수 없습니다",
"noDwellMomentsDescription": "중요한 동작에서 커서를 천천히 멈추며 녹화해 보세요.",
"noAutoZoomSlots": "자동 줌 슬롯이 없습니다",
"noAutoZoomSlotsDescription": "감지된 정지 지점이 기존 줌 구간과 겹칩니다.",
"cannotPlaceTrim": "이 위치에 트림을 추가할 수 없습니다",
"trimExistsAtLocation": "이 위치에 이미 트림이 있거나 공간이 부족합니다.",
"cannotPlaceSpeed": "이 위치에 속도를 추가할 수 없습니다",
"speedExistsAtLocation": "이 위치에 이미 속도 구간이 있거나 공간이 부족합니다."
},
"success": {
"addedZoomSuggestions": "커서 기반 줌 제안 {{count}}개가 추가되었습니다",
"addedZoomSuggestionsPlural": "커서 기반 줌 제안 {{count}}개가 추가되었습니다"
}
}