From e472761acfebb08e333d85abee3c2c73dcde59f3 Mon Sep 17 00:00:00 2001 From: yangroro Date: Sun, 25 Oct 2026 00:14:50 +0900 Subject: [PATCH] feat(i18n): add Korean (ko) locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Korean as a UI locale alongside zh/en/it/ru. The dictionary mirrors dict/en's per-domain split and covers every English entry plus all template, sound and music data names. Untranslated keys fall back to English (then Chinese), matching Italian. - locale: ko type, system-language detection, , agent response language, top bar label 한 - dictRegistry: lazy ko chunk with EN/EN_DATA fallbacks - server: ui-locale accepts ko (English fallback); the phone upload page gets Korean copy - verify: ko/coverage.verify.ts (EN key coverage, placeholder parity, data names) in verify:i18n; ko cases in locale, dictRegistry, systemPromptOrder and mobile-upload verifies Co-Authored-By: Claude Opus 5.5 --- package.json | 2 +- scripts/verify-gate-coverage.verify.mjs | 1 + server/mobile-upload-service.ts | 8 +- server/mobile-upload-service.verify.ts | 5 + server/plugins/mobile-upload.ts | 6 +- server/plugins/mobile-upload.verify.ts | 10 +- server/ui-locale.ts | 9 +- src/agent/systemPromptOrder.verify.ts | 2 + src/components/TopBar.tsx | 5 +- src/i18n/dict/ko/audio.ts | 55 +++ src/i18n/dict/ko/captions.ts | 161 +++++++ src/i18n/dict/ko/chat.ts | 393 ++++++++++++++++++ src/i18n/dict/ko/components.ts | 359 ++++++++++++++++ src/i18n/dict/ko/coverage.verify.ts | 29 ++ src/i18n/dict/ko/editor.ts | 29 ++ src/i18n/dict/ko/exportPanel.ts | 199 +++++++++ src/i18n/dict/ko/fx.ts | 144 +++++++ src/i18n/dict/ko/index.ts | 22 + src/i18n/dict/ko/library.ts | 177 ++++++++ src/i18n/dict/ko/media.ts | 227 ++++++++++ src/i18n/dict/ko/review.ts | 19 + src/i18n/dict/ko/settings.ts | 531 ++++++++++++++++++++++++ src/i18n/dict/ko/templates-data.ts | 312 ++++++++++++++ src/i18n/dict/ko/timeline.ts | 251 +++++++++++ src/i18n/dict/ko/topbar.ts | 20 + src/i18n/dict/ko/transcript.ts | 87 ++++ src/i18n/dictRegistry.ts | 13 +- src/i18n/dictRegistry.verify.ts | 22 +- src/i18n/locale.ts | 13 +- src/i18n/locale.verify.ts | 3 + 30 files changed, 3090 insertions(+), 24 deletions(-) create mode 100644 src/i18n/dict/ko/audio.ts create mode 100644 src/i18n/dict/ko/captions.ts create mode 100644 src/i18n/dict/ko/chat.ts create mode 100644 src/i18n/dict/ko/components.ts create mode 100644 src/i18n/dict/ko/coverage.verify.ts create mode 100644 src/i18n/dict/ko/editor.ts create mode 100644 src/i18n/dict/ko/exportPanel.ts create mode 100644 src/i18n/dict/ko/fx.ts create mode 100644 src/i18n/dict/ko/index.ts create mode 100644 src/i18n/dict/ko/library.ts create mode 100644 src/i18n/dict/ko/media.ts create mode 100644 src/i18n/dict/ko/review.ts create mode 100644 src/i18n/dict/ko/settings.ts create mode 100644 src/i18n/dict/ko/templates-data.ts create mode 100644 src/i18n/dict/ko/timeline.ts create mode 100644 src/i18n/dict/ko/topbar.ts create mode 100644 src/i18n/dict/ko/transcript.ts diff --git a/package.json b/package.json index 5e3721641..b032d8764 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "desktop:dist:win": "npm run build && npm run desktop:build:main && npm run desktop:prebundle && tsx desktop/prepare-target.mts win32-x64 && node -e \"const {spawnSync}=require('node:child_process');const result=spawnSync(process.execPath,['node_modules/electron-builder/cli.js','--config','config/electron-builder.config.mjs','--win','nsis','--x64','--publish','never'],{stdio:'inherit',env:{...process.env,CC_EB_TARGET:'win32-x64'}});if(result.error)throw result.error;process.exit(result.status??1)\"", "desktop:dist:linux": "npm run build && npm run desktop:build:main && npm run desktop:prebundle && tsx desktop/prepare-target.mts linux-x64 && CC_EB_TARGET=linux-x64 electron-builder --config config/electron-builder.config.mjs --linux AppImage --x64 --publish never", "verify:shortcuts": "tsx src/shortcuts/catalog.verify.ts && tsx src/shortcuts/keymap.verify.ts && tsx src/shortcuts/shortcutScope.verify.ts && tsx src/shortcuts/native-copy.verify.ts", - "verify:i18n": "node scripts/check-i18n.mjs && tsx src/i18n/locale.verify.ts && tsx src/i18n/dict/it/settingsCoverage.verify.ts && tsx src/i18n/dict/it/mediaCoverage.verify.ts && tsx src/components/settings/transcription-language.verify.ts", + "verify:i18n": "node scripts/check-i18n.mjs && tsx src/i18n/locale.verify.ts && tsx src/i18n/dict/it/settingsCoverage.verify.ts && tsx src/i18n/dict/it/mediaCoverage.verify.ts && tsx src/i18n/dict/ko/coverage.verify.ts && tsx src/components/settings/transcription-language.verify.ts", "verify:editor": "tsx src/editor/storeCommandBuilder.verify.ts && tsx src/editor/timelineFrameRate.verify.ts && tsx src/editor/projectFrameRate.verify.ts && tsx src/editor/keyframes.verify.ts && tsx src/editor/flexCrop.verify.ts && tsx src/editor/multiSelect.verify.ts && tsx src/editor/professionalTimeline.verify.ts && tsx src/editor/proposal.verify.ts && tsx src/editor/ripple-fade.verify.ts && tsx src/editor/ripple.verify.ts && tsx src/editor/split.verify.ts && tsx src/editor/transitionPreview.verify.ts && tsx src/editor/captionReferences.verify.ts && tsx src/editor/zoom.verify.ts && tsx src/editor/keyframes-check.verify.ts && tsx src/editor/audio-transcript-guard.verify.ts && tsx src/editor/caption-overlay-visibility.verify.ts && tsx src/editor/motionGraphicTime.verify.ts", "verify:captions": "tsx src/captions/captionCueMenu.verify.ts && tsx src/captions/captionIdentity.verify.ts && tsx src/captions/exportCaptions.verify.ts && tsx src/captions/presetStore.verify.ts && tsx src/captions/renderStyles.verify.ts && tsx src/captions/segmenter.verify.ts && tsx src/captions/styles.verify.ts && tsx src/transcript/edit.verify.ts && tsx src/transcript/transcribe-jobs.verify.ts && tsx src/transcript/variants.verify.ts && tsx src/audio/loudness.verify.ts && tsx src/audio/vad.verify.ts && tsx src/audio/vadPreference.verify.ts && tsx src/transcript/transcribe-jobs-check.verify.ts && tsx src/audio/loudnessBatch.verify.ts && tsx src/transcript/projection.verify.ts", "verify:agent-tools": "tsx src/agent/external-edit-session-apply.verify.ts && tsx src/agent/external-edit-session-cancellation.verify.ts && tsx src/agent/external-edit-session-core.verify.ts && tsx src/agent/external-edit-session-projection.verify.ts && tsx src/agent/external-edit-session-runtime.verify.ts && tsx src/agent/external-tool-policy.verify.ts && tsx src/agent/progress/job-model.verify.ts && tsx src/agent/progress/track-progress-targets.verify.ts && tsx src/agent/selection-refs.verify.ts && tsx src/agent/skills/plugin-skills.verify.ts && tsx src/agent/skills/skills-catalog.verify.ts && tsx src/agent/tools/agent-gap-p3.verify.ts && tsx src/agent/tools/audio-assets.verify.ts && tsx src/agent/tools/auto-grade-tools.verify.ts && tsx src/agent/tools/captions-lanes.verify.ts && tsx src/agent/tools/captions-tools.verify.ts && tsx src/agent/tools/design-tools.verify.ts && tsx src/agent/tools/edit-asset-tools.verify.ts && tsx src/agent/tools/edit-item-authored.verify.ts && tsx src/agent/tools/edit-item-generic.verify.ts && tsx src/agent/tools/edit-item-source-range.verify.ts && tsx src/agent/tools/edit-item-pool-replacement.verify.ts && tsx src/agent/tools/timeline-import-tools.verify.ts && tsx src/agent/tools/timeline-import-fcpxml.verify.ts && tsx src/agent/tools/timeline-import-edl.verify.ts && tsx src/agent/tools/edit-item-volume-hint.verify.ts && tsx src/agent/tools/export-tools.verify.ts && tsx src/agent/tools/followup-tools.verify.ts && tsx src/agent/tools/font-tools.verify.ts && tsx src/agent/tools/frames-tool.verify.ts && tsx src/agent/tools/renderSnapshotMedia.verify.ts && tsx src/agent/tools/friction-tools.verify.ts && tsx src/agent/tools/generate-rerun.verify.ts && tsx src/agent/tools/highlight-tool.verify.ts && tsx src/agent/tools/markers-tools.verify.ts && tsx src/agent/tools/media-pool-favorite-delete.verify.ts && tsx src/agent/tools/media-pool-relink.verify.ts && tsx src/agent/tools/media-pool-tools.verify.ts && tsx src/agent/tools/mg-code-tools.verify.ts && tsx src/agent/tools/mg-video-tools.verify.ts && tsx src/agent/tools/probe-tools.verify.ts && tsx src/agent/toolFailureNote.verify.ts && tsx src/agent/tools/project-tools.verify.ts && tsx src/agent/tools/followup-tools-check.verify.ts && tsx src/agent/tools/probe-tools-check.verify.ts && tsx src/agent/tools/read-project-tools-check.verify.ts && tsx src/agent/tools/stock-tools-check.verify.ts && tsx src/agent/tools/stock-tools-probe.verify.ts && tsx src/agent/tools/template-tools-check.verify.ts && node scripts/run-check.mjs src/agent/tools/effect-tools.verify.ts && node scripts/run-check.mjs src/agent/tools/library-edit-item.verify.ts && tsx src/agent/tools/read-project-tools.verify.ts && tsx src/agent/tools/shader-tools.verify.ts && tsx src/agent/tools/skill-tools.verify.ts && tsx src/agent/tools/transcript-clear-edits.verify.ts && tsx src/agent/tools/transcript-tools.verify.ts && tsx src/agent/tools/version-tools.verify.ts && tsx src/agent/tools/web-tools.verify.ts", diff --git a/scripts/verify-gate-coverage.verify.mjs b/scripts/verify-gate-coverage.verify.mjs index 47692d0e3..99565a5ab 100644 --- a/scripts/verify-gate-coverage.verify.mjs +++ b/scripts/verify-gate-coverage.verify.mjs @@ -96,6 +96,7 @@ assert.equal(renderStep['continue-on-error'], undefined); const dataModules = new Set([ 'src/i18n/dict/ru/index.ts', // Translation dictionary data, no application logic. 'src/i18n/dict/en/settings.ts', // Translation dictionary data, no application logic. + 'src/i18n/dict/ko/settings.ts', // Translation dictionary data, no application logic. ]); const sourceFiles = [...new Set(execFileSync('git', [ 'ls-files', '--cached', '--others', '--exclude-standard', '-z', diff --git a/server/mobile-upload-service.ts b/server/mobile-upload-service.ts index 2c5a99094..a55e5053f 100644 --- a/server/mobile-upload-service.ts +++ b/server/mobile-upload-service.ts @@ -51,7 +51,7 @@ interface MobileUploadSession extends MobileUploadSessionSnapshot { activeUploads: Set>; } -export type MobilePageLocale = 'zh' | 'en' | 'it' | 'ru'; +export type MobilePageLocale = 'zh' | 'en' | 'it' | 'ru' | 'ko'; interface MobileUploadServiceOptions { bindHost?: string; @@ -172,6 +172,12 @@ function mobilePage(locale: MobilePageLocale): string { choose: '选择素材', multiple: '支持多选,页面保持打开直到全部完成', waiting: '等待上传', sent: '已发送', failed: '上传失败', interrupted: '网络中断', }, + ko: { + pageTitle: '휴대폰에서 업로드', title: 'OpenChatCut으로 미디어 보내기', + hint: '휴대폰에서 동영상, 이미지 또는 오디오를 선택하세요. 두 기기를 같은 로컬 네트워크에 연결해 두세요.', + choose: '미디어 선택', multiple: '여러 파일을 선택할 수 있습니다. 모든 업로드가 끝날 때까지 이 페이지를 열어 두세요.', + waiting: '업로드 대기 중', sent: '전송됨', failed: '업로드 실패', interrupted: '네트워크 연결 끊김', + }, }[copyLocale]; const scriptCopy = JSON.stringify({ waiting: copy.waiting, sent: copy.sent, failed: copy.failed, interrupted: copy.interrupted }); return ` diff --git a/server/mobile-upload-service.verify.ts b/server/mobile-upload-service.verify.ts index 823ad153f..7c408b535 100644 --- a/server/mobile-upload-service.verify.ts +++ b/server/mobile-upload-service.verify.ts @@ -82,6 +82,10 @@ try { assert.match(await (await fetch(italianSession.urls[0]!)).text(), /Send media to OpenChatCut/); const russianSession = await service.createSession('ru'); assert.match(await (await fetch(russianSession.urls[0]!)).text(), /Отправить медиафайлы в OpenChatCut/); + const koreanSession = await service.createSession('ko'); + const koreanPage = await (await fetch(koreanSession.urls[0]!)).text(); + assert.match(koreanPage, //); + assert.match(koreanPage, /OpenChatCut으로 미디어 보내기/); const tooLarge = await fetch(`${session.urls[0]}/upload?name=large.mp4`, { method: 'POST', @@ -99,6 +103,7 @@ try { assert.equal(service.getSession(englishSession.id), null); assert.equal(service.getSession(italianSession.id), null); assert.equal(service.getSession(russianSession.id), null); + assert.equal(service.getSession(koreanSession.id), null); } finally { await service.stop(); await rm(tempDir, { recursive: true, force: true }); diff --git a/server/plugins/mobile-upload.ts b/server/plugins/mobile-upload.ts index 3d7beaeb1..a9f29aaf9 100644 --- a/server/plugins/mobile-upload.ts +++ b/server/plugins/mobile-upload.ts @@ -1,7 +1,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http'; import type { Plugin } from 'vite'; import { editorCredentialAuthorized, trustedEditorRequest } from '../editor-auth.ts'; -import { MobileUploadService } from '../mobile-upload-service.ts'; +import { MobileUploadService, type MobilePageLocale } from '../mobile-upload-service.ts'; import { putUploadFile } from '../r2.ts'; import { maxUploadBytes } from './upload.ts'; @@ -14,8 +14,8 @@ function sendJson(res: ServerResponse, status: number, body: unknown): void { type MobileUploadControls = Pick; -function mobilePageLocale(value: string | null): 'zh' | 'en' | 'it' | 'ru' { - return value === 'en' || value === 'it' || value === 'ru' ? value : 'zh'; +function mobilePageLocale(value: string | null): MobilePageLocale { + return value === 'en' || value === 'it' || value === 'ru' || value === 'ko' ? value : 'zh'; } function mobileUploadControlAuthorized(req: IncomingMessage, res: ServerResponse): boolean { diff --git a/server/plugins/mobile-upload.verify.ts b/server/plugins/mobile-upload.verify.ts index da929ea40..1c8910478 100644 --- a/server/plugins/mobile-upload.verify.ts +++ b/server/plugins/mobile-upload.verify.ts @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import { createServer } from 'node:http'; -import type { MobileUploadSessionSnapshot } from '../mobile-upload-service'; +import type { MobilePageLocale, MobileUploadSessionSnapshot } from '../mobile-upload-service'; import { handleMobileUploadControl } from './mobile-upload'; const snapshot: MobileUploadSessionSnapshot = { @@ -14,7 +14,7 @@ let reads = 0; let deletes = 0; const createdLocales: string[] = []; const controls = { - async createSession(locale: 'zh' | 'en' | 'it' | 'ru' = 'zh') { + async createSession(locale: MobilePageLocale = 'zh') { creates += 1; createdLocales.push(locale); return snapshot; @@ -107,7 +107,11 @@ try { method: 'POST', headers: { origin }, }); assert.equal(italian.status, 201); - assert.deepEqual(createdLocales, ['en', 'ru', 'it']); + const korean = await fetch(`${origin}/sessions?locale=ko`, { + method: 'POST', headers: { origin }, + }); + assert.equal(korean.status, 201); + assert.deepEqual(createdLocales, ['en', 'ru', 'it', 'ko']); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); } diff --git a/server/ui-locale.ts b/server/ui-locale.ts index 8873469a2..1ff8138ec 100644 --- a/server/ui-locale.ts +++ b/server/ui-locale.ts @@ -7,9 +7,9 @@ // here instead of guessing. Unset means the app's original Chinese. import { getKey } from './keystore.ts'; -export type UiLocale = 'zh' | 'en' | 'it' | 'ru'; +export type UiLocale = 'zh' | 'en' | 'it' | 'ru' | 'ko'; -const LOCALES: ReadonlySet = new Set(['zh', 'en', 'it', 'ru']); +const LOCALES: ReadonlySet = new Set(['zh', 'en', 'it', 'ru', 'ko']); export function parseUiLocale(value: unknown): UiLocale | null { const tag = typeof value === 'string' ? value.trim().toLowerCase() : ''; @@ -20,10 +20,11 @@ export function uiLocale(): UiLocale { return parseUiLocale(getKey('UI_LOCALE')) ?? 'zh'; } -/** Pick the variant for the current interface language; Italian falls back to English when not provided. */ -export function localized(variants: { zh: T; en: T; ru?: T; it?: T }, locale: UiLocale = uiLocale()): T { +/** Pick the variant for the current interface language; Italian, Russian and Korean fall back to English when not provided. */ +export function localized(variants: { zh: T; en: T; ru?: T; it?: T; ko?: T }, locale: UiLocale = uiLocale()): T { if (locale === 'zh') return variants.zh; if (locale === 'ru') return variants.ru ?? variants.en; if (locale === 'it') return variants.it ?? variants.en; + if (locale === 'ko') return variants.ko ?? variants.en; return variants.en; } diff --git a/src/agent/systemPromptOrder.verify.ts b/src/agent/systemPromptOrder.verify.ts index 623255cdb..c404a53f8 100644 --- a/src/agent/systemPromptOrder.verify.ts +++ b/src/agent/systemPromptOrder.verify.ts @@ -55,6 +55,8 @@ const commonPrefixLength = (a: string, b: string): number => { assert.match(agentLanguagePrompt('it'), /in Italian/); assert.match(agentLanguagePrompt('ru'), /interface language is Russian/); assert.match(agentLanguagePrompt('ru'), /in Russian/); + assert.match(agentLanguagePrompt('ko'), /interface language is Korean/); + assert.match(agentLanguagePrompt('ko'), /in Korean/); } // ── Public product identity must override stale names in workflows or conversation memory ── diff --git a/src/components/TopBar.tsx b/src/components/TopBar.tsx index 6bc7e8cb9..618fbbca9 100644 --- a/src/components/TopBar.tsx +++ b/src/components/TopBar.tsx @@ -18,7 +18,8 @@ const McpGuideDialog = lazy(() => loadMcpGuideDialog().then((m) => ({ default: m // Language switching: The text pill displays the current language; clicking // cycles through the supported locales. First run defaults to the -// system language (or English) — see i18n/locale.ts. +// system language (or English) — see i18n/locale.ts. Chinese and Korean show +// their own script; the others show the locale code. export function LocaleToggle() { const t = useT(); const locale = getLocale(); @@ -32,7 +33,7 @@ export function LocaleToggle() { style={{ minWidth: 30, height: 22, background: 'none', border: `0.5px solid ${theme.border}`, borderRadius: 4, cursor: 'pointer', padding: '0 5px', fontSize: 11, fontWeight: 600, letterSpacing: 0.3, color: theme.textDim, display: 'grid', placeItems: 'center' }} onMouseEnter={(e) => { e.currentTarget.style.color = theme.text; e.currentTarget.style.background = theme.panelAlt; }} onMouseLeave={(e) => { e.currentTarget.style.color = theme.textDim; e.currentTarget.style.background = 'none'; }}> - {locale === 'zh' ? '中' : locale.toUpperCase()} + {locale === 'zh' ? '中' : locale === 'ko' ? '한' : locale.toUpperCase()} ); } diff --git a/src/i18n/dict/ko/audio.ts b/src/i18n/dict/ko/audio.ts new file mode 100644 index 000000000..1427b3a58 --- /dev/null +++ b/src/i18n/dict/ko/audio.ts @@ -0,0 +1,55 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '此浏览器不支持录音': '이 브라우저는 녹음을 지원하지 않습니다', + '麦克风权限被拒绝': '마이크 권한이 거부되었습니다', + '无法访问麦克风': '마이크에 접근할 수 없습니다', + 'UI 与动效反馈': 'UI 및 모션 피드백', + '转场与强调': '전환 및 강조', + '设备与质感': '기기 및 질감', + '反应与情绪': '반응 및 분위기', + '音乐分析': '음악 분석', + '音乐分析:{name},{status}': '음악 분석: {name}, {status}', + '{name} 的音乐分析': '{name} 음악 분석', + '检查模型': '모델 확인 중', + '模型未安装': '모델이 설치되지 않음', + '分析音乐': '음악 분석', + '重新分析': '다시 분석', + '重试分析': '분석 재시도', + '排队中': '대기 중', + '分析失败': '분석 실패', + '解码音频': '오디오 디코딩 중', + '分析节拍': '리듬 분석 중', + '理解音乐内容': '음악 이해 중', + '已加入本地分析队列。': '로컬 분석 대기열에 추가되었습니다.', + '分析失败:{message}': '분석 실패: {message}', + '尚未安装所需模型包。请在本地 AI 设置中分别下载节拍与音乐语义模型;这里不会自动下载。': '필요한 모델 팩이 설치되어 있지 않습니다. 로컬 AI 설정에서 리듬 모델과 음악 의미 분석 모델을 각각 다운로드하세요. 여기서는 자동으로 다운로드하지 않습니다.', + '已显示缓存结果;重新分析需要先安装模型包。': '캐시된 결과를 표시하고 있습니다. 다시 분석하려면 먼저 모델 팩을 설치하세요.', + '正在检查本地模型…': '로컬 모델 확인 중…', + '在本机分析节拍、结构和音乐语义。音频不会上传。': '이 기기에서 리듬, 구조, 음악적 의미를 분석합니다. 오디오는 업로드되지 않습니다.', + '速度': '속도', + '拍号': '박자', + '置信度': '신뢰도', + '节奏详情': '리듬 세부 정보', + '{beats} 个节拍 · {downbeats} 个重拍': '비트 {beats}개 · 다운비트 {downbeats}개', + '节拍时间点': '비트 타임스탬프', + '重拍时间点': '다운비트 타임스탬프', + '另有 {count} 个时间点': '타임스탬프 {count}개 더 있음', + '音乐标签': '음악 태그', + '流派': '장르', + '情绪': '분위기', + '乐器': '악기', + '用途': '용도', + '未知': '알 수 없음', + '段落': '구간', + '能量': '에너지', + '边界': '경계', + '未识别到明确段落': '뚜렷한 구간이 감지되지 않았습니다', + '前奏': '인트로', + '推进': '빌드업', + '高潮': '절정', + '间奏': '브레이크', + '平稳': '안정', + '尾奏': '아웃트로', + '自动分析新导入的音视频': '새로 가져온 오디오 및 비디오 자동 분석', + '需要先在本地 AI 设置中单独下载模型包;开启此选项不会自动下载。': '먼저 로컬 AI 설정에서 모델 팩을 별도로 다운로드하세요. 이 옵션을 켜도 다운로드가 시작되지 않습니다.', +} as Record; diff --git a/src/i18n/dict/ko/captions.ts b/src/i18n/dict/ko/captions.ts new file mode 100644 index 000000000..b97d047a7 --- /dev/null +++ b/src/i18n/dict/ko/captions.ts @@ -0,0 +1,161 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '拖到预览画面任意位置新建字幕': '미리보기로 드래그하여 원하는 위치에 자막 만들기', + '可拖到预览画面任意位置新建并编辑字幕': '미리보기로 드래그하여 원하는 위치에 자막을 만들고 편집할 수 있습니다', + '双击编辑字幕': '더블클릭하여 자막 편집', + '文A': '가A', + '字': '자', + '简洁白字': '깔끔한 흰색', + '影院白字': '시네마 흰색', + '清爽高亮': '산뜻한 하이라이트', + '短视频撞色': '펀치 팝', + '故事黄高亮': '스토리 노랑', + '粗描边': '굵은 외곽선', + '工作室白底': '스튜디오 카드', + '白卡片': '흰색 카드', + '杂志黄标': '매거진 태그', + '气泡大字': '버블 타이포', + '绿底堆叠': '그린 스택', + '黑白堆叠': '모노 스택', + '黄字大标题': '큰 노란 제목', + '霓虹大写': '네온 대문자', + '灰调衬线': '차분한 세리프', + '奢华金': '럭스 골드', + '暗夜红': '누아르 레드', + '工坊红底': '아틀리에 레드', + '产品绿标': '프로덕트 그린', + '信号青': '시그널 시안', + '得意黑': 'Smiley Sans', + '白字无底,适合口播': '배경 없는 흰 글자 — 내레이션에 적합', + '轻阴影,像正片字幕': '부드러운 그림자, 영화 자막 느낌', + '青底高亮当前词,中文友好': '현재 단어를 시안색으로 강조, CJK 친화적', + '粉红高亮,适合竖屏': '핫핑크 강조, 세로 영상용', + '白字 + 黄高亮': '흰 글자 + 노란 강조', + '强描边,远看也清晰': '굵은 외곽선, 멀리서도 잘 보임', + '深字浅底,干净': '밝은 카드 위 어두운 글자, 깔끔함', + '灰字白底卡片': '흰색 카드 위 회색 글자', + '黑字黄高亮,文艺': '검은 글자, 노란 강조, 감성적', + '大号撞色,强调词': '강렬한 대비 색상으로 핵심 단어 강조', + '绿色高亮、可堆叠': '초록 강조, 여러 줄 쌓기 가능', + '黑字白底,堆叠两行': '흰 바탕 검은 글자, 두 줄 쌓기', + '超大字 + 黄高亮': '초대형 글자 + 노란 강조', + '全大写 + 彩边光': '전체 대문자 + 컬러 글로우', + '灰字,偏设计感': '디자인 감각의 회색 글자', + '金色字,典雅': '금색 글자, 우아함', + '暗调 + 红高亮': '어두운 톤 + 빨간 강조', + '深字红底高亮': '빨간 강조 위 어두운 글자', + '青白字 + 荧光绿': '차가운 흰 글자 + 네온 그린', + '科技风青绿高亮': '테크 느낌의 청록 강조', + '中文展示字体': '중국어 디스플레이 서체', + '字幕': '자막', + '收起': '접기', + '展开': '펼치기', + '生成字幕': '자막 생성', + '手动添加字幕': '수동으로 자막 추가', + '从文字稿打开「字幕样式」,或在这里手动添加独立字幕。': '전사 텍스트에서 ‘자막 스타일’을 열거나 여기에서 독립 자막을 수동으로 추가하세요.', + '先在上方完成「转写」,再生成字幕。': '먼저 위에서 ‘전사’를 완료한 다음 자막을 생성하세요.', + '预览中显示字幕': '미리보기에 자막 표시 중', + '字幕已隐藏': '자막 숨김', + '显示': '표시', + '隐藏': '숨기기', + '从工程里移除字幕': '프로젝트에서 자막 제거', + '移除': '제거', + '字幕已关闭,预览/导出都不会烧录。再点「显示」或勾选即可恢复。': '자막이 꺼져 있습니다. 미리보기와 내보내기 모두 자막이 입혀지지 않습니다. ‘표시’를 클릭하거나 체크박스를 선택하면 다시 켜집니다.', + '样式外观': '스타일', + '字幕样式': '자막 스타일', + '显示节奏': '표시 속도', + '按句/短语': '문장/구 단위', + '一次显示一句话,适合纪录片口播': '한 번에 한 문장씩 표시 — 다큐멘터리 내레이션에 적합', + '逐词高亮': '단어별 강조', + '当前说到的词会变色,像卡拉 OK': '말하는 단어가 노래방처럼 강조됩니다', + '字幕动效': '자막 모션', + '无动效': '없음', + '淡入上浮': '페이드 업', + '弹性入场': '팝 인', + '逐词弹出': '단어 팝', + '卡拉 OK 脉冲': '노래방 펄스', + '动效按时间线帧计算,预览与导出保持一致。': '모션은 타임라인 프레임 기준으로 계산되므로 미리보기와 내보내기가 일치합니다.', + '手动字幕': '수동 자막', + '({n} 车道)': ' ({n}개 레인)', + '手动字幕车道': '수동 자막 레인', + '新建车道': '새 레인', + '删除车道': '레인 삭제', + '新建手动字幕车道后,可在播放头位置添加字幕,不需要先转写或调用 AI。': '수동 자막 레인을 만든 후 전사나 AI 없이 재생 헤드 위치에 자막을 추가할 수 있습니다.', + '输入字幕文字': '자막 텍스트 입력', + '开始': '시작', + '时长': '길이', + '取播放头': '재생 헤드 위치 사용', + '添加字幕': '자막 추가', + '开始秒数': '시작 시간(초)', + '结束秒数': '종료 시간(초)', + '字幕文字': '자막 텍스트', + '删除': '삭제', + '复制': '복제', + '粘贴': '붙여넣기', + '添加到 AI 对话框': 'AI 입력창에 추가', + '无法复制字幕,请检查剪贴板权限': '자막을 복사할 수 없습니다. 클립보드 권한을 확인하세요.', + '无法读取剪贴板,请检查剪贴板权限': '클립보드를 읽을 수 없습니다. 클립보드 권한을 확인하세요.', + '剪贴板里没有可粘贴的文字': '클립보드에 붙여넣을 텍스트가 없습니다.', + '字幕翻译没有返回文字': '자막 번역 결과로 반환된 텍스트가 없습니다.', + '字幕语言(文本变体)': '자막 언어(텍스트 변형)', + '原文(source)': '원문(source)', + '切换主字幕行显示的语言。译文只换文本,词的时间/帧位仍取自源。': '기본 자막 줄의 언어를 전환합니다. 번역은 텍스트만 바꾸며, 단어 타이밍/프레임은 원본을 그대로 따릅니다.', + '双语第二行(可选)': '이중 언어 두 번째 줄(선택 사항)', + '第一行仍是原文(中文口播)。第二行是': '첫 번째 줄은 원문(중국어 내레이션)으로 유지됩니다. 두 번째 줄은 ', + '翻译': '번역', + ',请选目标语言(不要选中文)。': '입니다. 대상 언어를 선택하세요(중국어 제외).', + '英文': '영어', + '日文': '일본어', + '西班牙文': '스페인어', + '法文': '프랑스어', + '韩文': '한국어', + '翻译中…': '번역 중…', + '重新翻译': '다시 번역', + '生成翻译': '번역 생성', + '显示翻译第二行({lang})': '번역된 두 번째 줄 표시({lang})', + '原文时间已改变,翻译行仍停留在旧位置,建议重新翻译。': '원문 타이밍이 변경되었지만 번역 줄은 이전 위치에 남아 있습니다. 다시 번역하여 맞추세요.', + '样式': '스타일', + '我的样式': '내 스타일', + '删除此预设': '이 프리셋 삭제', + '预设名称': '프리셋 이름', + '保存': '저장', + '取消': '취소', + '把当前模板/覆盖样式保存为用户预设': '현재 템플릿/스타일 재정의를 사용자 프리셋으로 저장', + '请先启用字幕': '먼저 자막을 활성화하세요', + '+ 保存当前样式...': '+ 현재 스타일 저장...', + '翻译中...': '번역 중...', + '翻译字幕': '자막 번역', + '该轨道还没有可用文字稿': '이 트랙에는 아직 사용할 수 있는 전사 텍스트가 없습니다', + '请先启用字幕并选择样式': '먼저 자막을 활성화하고 스타일을 선택하세요', + '保存样式失败': '스타일을 저장하지 못했습니다', + '删除样式失败': '스타일을 삭제하지 못했습니다', + '该轨道还没有可翻译的文字稿,请先完成转写': '이 트랙에는 아직 번역할 전사 텍스트가 없습니다. 먼저 전사를 완료하세요', + '字幕翻译失败': '자막 번역 실패', + '黑底白字': '자막 바', + '整句黑底条,经典字幕(默认)': '전체 줄 검은 바 — 클래식 자막(기본값)', + '点击选中字幕,双击直接改文字': '클릭하여 자막 선택, 더블클릭하여 텍스트 편집', + '点击选中字幕;拖动移动位置;双击直接改文字': '클릭하여 선택, 드래그하여 위치 이동, 더블클릭하여 텍스트 편집', + '文字颜色': '텍스트 색상', + '自定义颜色': '사용자 지정 색상', + '自定义': '사용자 지정', + '让 AI 改写这句': 'AI에게 이 줄 다시 쓰기 요청', + 'AI 编辑': 'AI 편집', + '编辑文字': '텍스트 편집', + '文字': '텍스트', + '缩小字号': '글자 작게', + '放大字号': '글자 크게', + '优化这句字幕({time} 处,保持时间不变):「{text}」': '이 자막 줄을 개선해 주세요({time} 위치, 타이밍 유지): ‘{text}’', + '逐句编辑': '줄 편집', + '({n} 句)': ' ({n}줄)', + '转写字幕车道请在对话里修改;手动车道可在上方「手动字幕」中直接编辑。': '전사 기반 레인은 채팅에서 편집하세요. 수동 레인은 위의 ‘수동 자막’에서 직접 편집할 수 있습니다.', + '还没有可编辑的字幕句(先转写并生成字幕)。': '편집할 자막 줄이 아직 없습니다(먼저 전사하고 자막을 생성하세요).', + '点时间码跳到对应画面;点句子文字直接改,清空文字=删掉这句。改动可撤销(⌘Z)。': '타임코드를 클릭하면 해당 위치로 이동하고, 텍스트를 클릭하면 편집할 수 있습니다. 텍스트를 지우면 해당 줄이 삭제됩니다. ⌘Z로 실행 취소할 수 있습니다.', + '跳到这句': '이 줄로 이동', + '点击编辑这句字幕': '클릭하여 이 자막 줄 편집', + '这句不再显示(词与时间线不受影响)': '이 줄 숨기기(전사 단어와 타임라인은 변경되지 않음)', + '删除这句': '줄 삭제', + '请先创建字幕轨道': '먼저 자막 트랙을 만드세요', + '字幕文件没有可用内容': '자막 파일에 사용할 수 있는 내용이 없습니다', + '无法创建字幕轨道': '자막 트랙을 만들 수 없습니다', + '读取字幕文件失败': '자막 파일을 읽지 못했습니다', +} as Record; diff --git a/src/i18n/dict/ko/chat.ts b/src/i18n/dict/ko/chat.ts new file mode 100644 index 000000000..da630d96d --- /dev/null +++ b/src/i18n/dict/ko/chat.ts @@ -0,0 +1,393 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '请按“{name}”工作流处理当前工程:{summary}。先检查素材和时间线,再执行并检查成片。': '현재 프로젝트에 ‘{name}’ 워크플로를 적용하세요: {summary}. 먼저 미디어와 타임라인을 검토한 다음 실행하고 결과를 확인하세요.', + '展开 OpenChatCut Agent': 'OpenChatCut Agent 펼치기', + '收起 OpenChatCut Agent': 'OpenChatCut Agent 접기', + '清空对话': '대화 지우기', + 'Agent 仍在运行中,无法清空对话。请先等待运行结束或停止当前运行,再试一次。': '에이전트가 아직 실행 중이라 대화를 지울 수 없습니다. 실행이 끝날 때까지 기다리거나 먼저 중지한 후 다시 시도하세요.', + 'Agent 工作台': '에이전트 작업 공간', + '聊天滚动快捷操作': '채팅 스크롤 바로가기', + '快速到顶部': '맨 위로 이동', + '快速到底部': '맨 아래로 이동', + '从这里开工': '여기서 시작', + '从一个剪辑目标开始': '편집 목표로 시작하기', + '选择工作流,或直接描述你想得到的成片。': '워크플로를 선택하거나 원하는 완성 영상을 설명하세요.', + '思考中…': '생각 중…', + '描述你想要创建的内容...': '만들고 싶은 내용을 설명하세요...', + '告诉 AI 要做哪些修改 - @ 引用素材': 'AI에게 변경할 내용을 알려 주세요 — @로 미디어 참조', + '已忽略不支持的文件(仅支持 视频 / 图片 / 音频 / GIF / SVG)': '지원되지 않는 파일은 무시되었습니다(비디오 / 이미지 / 오디오 / GIF / SVG만 지원)', + '已忽略不支持的文件(仅支持 视频 / 图片 / 音频 / GIF / SVG / md / txt / srt / csv / docx / pdf)': '지원되지 않는 파일은 무시되었습니다(비디오 / 이미지 / 오디오 / GIF / SVG / md / txt / srt / csv / docx / pdf만 지원)', + '文档大小不能超过 10 MB': '문서 크기는 10 MB 이하여야 합니다', + 'PDF 页数不能超过 100 页': 'PDF 문서는 최대 100페이지까지 가능합니다', + '文档文本不能超过 100,000 个字符': '문서 텍스트는 최대 100,000자까지 가능합니다', + '一次最多读取 8 个文档': '한 번에 최대 8개 문서까지 읽을 수 있습니다', + '文档文本总量不能超过 200,000 个字符': '문서 텍스트 합계는 최대 200,000자까지 가능합니다', + '文档解析失败': '문서 분석 실패', + '导入失败': '가져오기 실패', + 'Agent 修改记录': '에이전트 변경 기록', + '项操作': '개 작업', + '恢复到这次 Agent 修改前': '이 에이전트 세션 이전으로 프로젝트 복원', + '工程后来已有其他修改': '프로젝트에 이후 변경 사항이 있습니다', + '重新发送请求': '이 요청 다시 보내기', + '重新发送': '다시 보내기', + '重试请求': '이 요청 재시도', + '重试': '재시도', + 'Agent 运行检查器': '에이전트 실행 검사기', + '服务端运行事件': '서버 측 실행 이벤트', + '没有服务端事件': '서버 측 이벤트 없음', + '服务端': '서버 측', + '运行中': '실행 중', + '等待确认': '승인 대기 중', + '等待回复': '응답 대기 중', + '已完成': '완료됨', + '失败': '실패', + '已取消': '취소됨', + '已中断': '중단됨', + '未知状态': '알 수 없는 상태', + '上下文与工具': '컨텍스트 및 도구', + '输入': '입력', + '输出': '출력', + '系统': '시스템', + '历史': '기록', + '缓存读': '캐시 읽기', + '缓存写': '캐시 쓰기', + '未缓存': '캐시 안 됨', + '活跃工具': '활성 도구', + '工具 Schema': '도구 스키마', + 'Schema 字符': '스키마 문자 수', + '最近一次模型请求': '최근 모델 요청', + '本次运行累计': '실행 합계', + '模型请求': '모델 요청', + '累计输入': '총 입력', + '新鲜输入': '신규 입력', + '累计输出': '총 출력', + '缓存命中率': '캐시 적중률', + '累计重试': '재시도 횟수', + '图片输入': '이미지 입력', + '缓存诊断': '캐시 진단', + '已命中缓存': '캐시 적중', + '首次请求': '첫 요청', + '模型已变化': '모델 변경됨', + '系统提示已变化': '시스템 프롬프트 변경됨', + '工具面已变化': '도구 구성 변경됨', + '缓存已过期': '캐시 만료됨', + '未确认原因': '확인되지 않은 원인', + '上下文检查点': '컨텍스트 체크포인트', + '上下文接近上限,发送后可能自动压缩较早对话。': '컨텍스트가 한도에 가까워졌습니다. 전송 시 이전 대화가 압축될 수 있습니다.', + '无摘要': '요약 없음', + '源消息 {count} 条': '소스 메시지 {count}개', + '成功': '성공', + '校验失败': '검증 실패', + '已拒绝': '거부됨', + '副作用前已中止': '상태 변경 작업 전에 중단됨', + '已过期': '만료됨', + '可重试失败': '재시도 가능한 실패', + '结果未知': '결과 알 수 없음', + '终止失败': '최종 실패', + '未知结果': '알 수 없는 결과', + '工具结果': '도구 결과', + '没有工具结果': '도구 결과 없음', + '未知工具': '알 수 없는 도구', + '待决定': '대기 중', + '已允许': '허용됨', + '审批': '승인', + '真实工具确认': '실제 도구 실행 확인', + '提案审核': '제안 검토', + '字节': '바이트', + '参数摘要': '인수 요약', + '已脱敏': '가려짐', + '已省略二进制': '바이너리 생략됨', + '没有审批记录': '승인 기록 없음', + '归档结果': '보관된 결과', + '字符': '자', + '正在读取运行记录…': '실행 기록 불러오는 중…', + '无法读取运行记录': '실행 기록을 불러올 수 없습니다', + '还没有运行记录': '아직 실행 기록이 없습니다', + '发送消息后可在这里查看运行状态;中断的操作不会自动重放。': '메시지를 보내면 여기에 실행 세부 정보가 표시됩니다. 중단된 작업은 자동으로 다시 실행되지 않습니다.', + '未知后端': '알 수 없는 백엔드', + '未知模型': '알 수 없는 모델', + '全部对话:{runs} 轮 · 累计 {requests} 次模型请求': '총 {runs}회 실행 · 누적 모델 요청 {requests}회', + '未记录请求摘要': '요청 요약이 기록되지 않았습니다.', + '这次运行被意外中断,系统不会自动继续或重放副作用。请先检查外部任务状态,再决定是否重试。': '이 실행이 예기치 않게 중단되었습니다. 자동으로 계속하거나 다시 실행하지 않습니다. 재시도하기 전에 외부 작업 상태를 확인하세요.', + '只读诊断,不会执行或恢复任何操作。': '읽기 전용 진단입니다. 어떤 작업도 실행하거나 재개하지 않습니다.', + '工具确认未保存,请重试:{message}': '도구 확인을 저장하지 못했습니다. 다시 시도하세요: {message}', + '原任务': '원래 작업', + '操作 ID': '작업 ID', + '操作': '동작', + '命令': '명령', + '输入路径': '입력 경로', + '目标路径': '대상 경로', + '输入网址': '입력 URL', + '输出目标': '출력 대상', + '源网址': '소스 URL', + '样式 ID': '스타일 ID', + '样式名称': '스타일 이름', + '网址': 'URL', + '文件路径': '파일 경로', + '路径': '경로', + '输出名称': '출력 이름', + '仓库': '저장소', + '安装目录': '설치 디렉터리', + '技能': '스킬', + '资源 ID': '미디어 ID', + '服务商': '공급자', + '工程 ID': '프로젝트 ID', + '技能 ID': '스킬 ID', + '模板 ID': '템플릿 ID', + '版本 ID': '버전 ID', + '请求内容': '프롬프트', + '格式': '형식', + '编码': '코덱', + '分辨率': '해상도', + '输出目录': '출력 디렉터리', + '外部 Agent 请求执行真实工程操作': '외부 에이전트가 실제 프로젝트 작업을 요청했습니다', + '工具 {tool} 将作用于当前工程。确认仅绑定下方参数;修改参数后必须重新确认。': '도구 {tool}이(가) 현재 프로젝트에 적용됩니다. 승인은 아래 매개변수에만 적용되며, 매개변수가 바뀌면 다시 승인해야 합니다.', + '音频 / 音乐生成': '오디오 / 음악 생성', + '长时 GPU 任务': '장시간 GPU 작업', + '不可逆导出': '되돌릴 수 없는 내보내기', + '快速操作': '빠른 작업', + '快速操作…': '빠른 작업…', + '删除填充词': '군더더기 말 제거', + '删除静音': '무음 제거', + '跳切': '점프 컷', + '生成字幕': '자막 생성', + '响度标准化': '음량 정규화', + '横转竖': '가로를 세로로', + '删除当前口播中的填充词,并保持字幕与画面同步': '현재 토킹헤드 편집에서 군더더기 말을 제거하고 자막과 영상을 동기화된 상태로 유지합니다', + '删除当前时间线中的静音停顿,并收紧空隙': '현재 타임라인에서 무음 구간을 제거하고 빈 공간을 메웁니다', + '把当前口播剪成节奏紧凑的跳切版本': '현재 토킹헤드 편집을 빠른 템포의 점프 컷 버전으로 만듭니다', + '为当前口播生成并应用同步字幕': '현재 토킹헤드 편집에 동기화된 자막을 생성하고 적용합니다', + '将当前时间线中的人声音量标准化': '현재 타임라인의 대사 음량을 정규화합니다', + '将当前工程转换为 9:16 竖屏,并调整主要画面构图': '현재 프로젝트를 9:16 세로로 변환하고 주요 화면 구도를 다시 잡습니다', + '口播净剪': '토킹헤드 깔끔 편집', + '去停顿、赘词并同步字幕': '멈춤과 군더더기 말을 제거하고 자막 동기화', + '动态包装': '모션 패키지', + '标题、数据卡与转场动效': '타이틀, 정보 카드, 전환 효과', + '长片拆条': '긴 영상 하이라이트', + '提炼高光并重排为短视频': '하이라이트를 찾아 쇼츠로 재구성', + '产品故事': '제품 스토리', + '围绕卖点组织脚本和镜头': '핵심 장점을 중심으로 스크립트와 샷 구성', + 'AI 影像': 'AI 영상', + '从概念生成镜头与声音': '콘셉트에서 샷과 사운드 개발', + '知识成片': '지식 영상', + '把主题整理成清晰讲解': '주제를 명확한 설명으로 정리', + '精剪当前口播:去掉无效停顿和赘词,并生成同步字幕': '현재 토킹헤드 영상을 다듬어 주세요: 불필요한 공백과 군더더기 말을 제거한 뒤 동기화된 자막을 생성해 주세요', + '为当前内容设计动态包装,包含标题、信息卡和转场动效': '현재 콘텐츠에 타이틀, 정보 카드, 전환 효과를 포함한 모션 패키지를 디자인해 주세요', + '从当前长视频中提炼高光,重排成适合发布的短视频': '현재 긴 영상에서 하이라이트를 찾아 바로 게시할 수 있는 쇼츠로 재구성해 주세요', + '围绕产品卖点组织脚本和镜头,制作一支产品宣传短片': '제품 장점을 중심으로 스크립트와 샷 구성을 만든 뒤 홍보 영상을 제작해 주세요', + '根据我的概念策划一支 AI 影像,补全镜头、声音和节奏': '제 콘셉트로 AI 영상을 기획하고 샷, 사운드, 페이싱을 구체화해 주세요', + '把主题整理成结构清晰、带字幕和视觉提示的讲解视频': '주제를 자막과 시각적 단서가 포함된 구조화된 설명 영상으로 만들어 주세요', + '拉焦中': '포커스 당기는 중', + '推轨道车': '달리 미는 중', + '检查片门': '게이트 확인 중', + '打板儿': '슬레이트 치는 중', + '同期声走起': '사운드 롤링', + '走位走位': '동선 맞추는 중', + '卡点卡点': '비트 맞추는 중', + '架灯架灯': '조명 설치 중', + '找感觉': '감 잡는 중', + '推翻重来': '테이크 투', + '勘景去': '로케이션 헌팅 중', + '摇一个': '패닝 중', + '推推推': '푸시 인', + '跟上跟上': '따라가는 중', + '甩一个': '휩 팬 중', + '手持走起': '핸드헬드로 전환', + '摇臂升': '크레인 업', + '拉远点': '와이드로 빼는 중', + '给个全景': '와이드 샷', + '怼近点': '펀치 인', + '跳切跳切': '점프 컷 중', + '硬切': '컷', + '叠化过渡': '크로스 디졸브 중', + '匹配剪辑': '매치 컷 중', + '交叉来': '교차 편집 중', + '蒙太奇一下': '몽타주 타임', + 'L切走起': 'L컷 들어가는 중', + '接胶片': '필름 이어 붙이는 중', + '模式': '모드', + '代理模式': '에이전트 모드', + '可编辑时间线,改动可撤销': '타임라인을 편집할 수 있으며 변경 사항은 실행 취소할 수 있습니다', + '模型': '모델', + '选择模型': '모델 선택', + '当前模型:{name}': '현재 모델: {name}', + '本条对话使用的模型': '이 채팅에 사용되는 모델', + '上下文:{used} / {limit}': '컨텍스트: {used} / {limit}', + '系统 {system} · 工具 {tools}({toolCount} 个)· 历史 {history}': '시스템 {system} · 도구 {tools}({toolCount}개) · 기록 {history}', + '缓存读取 {tokens}': '캐시 읽기 {tokens}', + '请先在设置中配置一个模型厂商。': '먼저 설정에서 모델 공급자를 하나 이상 구성하세요.', + '正在读取模型配置…': '모델 구성 불러오는 중…', + '服务端运行': '서버 측 실행', + 'Agent 在本地服务端执行,刷新页面不会中断正在进行的任务。': '에이전트는 로컬 서버에서 실행되므로 페이지를 새로 고쳐도 진행 중인 작업이 중단되지 않습니다.', + '设置': '설정', + 'Ask 模式': 'Ask 모드', + 'YOLO 模式': 'YOLO 모드', + 'Ask 模式:时间线提案等待你应用;工具直接执行,关键选项仍会询问。': 'Ask 모드: 타임라인 제안은 직접 적용할 때까지 대기합니다. 도구는 바로 실행되며, 중요한 선택은 계속 확인을 요청합니다.', + 'YOLO 模式:提案自动应用,工具直接执行;仅在缺少关键信息时询问。': 'YOLO 모드: 제안이 자동으로 적용되고 도구가 바로 실행됩니다. 중요한 정보가 없을 때만 질문합니다.', + 'MG 质量': 'MG 품질', + '速度': '속도', + '均衡': '균형', + '质量': '품질', + '速度=最快出活 / 均衡 / 质量=打磨动效细节。': '속도 = 가장 빠른 출력 / 균형 / 품질 = 정교한 모션 디테일', + '缓存时长': '캐시 기간', + '短对话': '짧은 세션', + '长对话': '긴 세션', + '短对话使用默认缓存;长对话在支持的模型厂商上请求 1 小时缓存。': '짧은 세션은 기본 캐시를 사용하고, 긴 세션은 지원되는 공급자에게 1시간 캐시를 요청합니다.', + '计划模式': '계획 모드', + '先出编号计划,确认后再动手。': '먼저 번호가 매겨진 계획을 제시하고, 확인 후 실행합니다.', + '自主验收': '자율 검수', + '修改后主动读取最新工程并检查结果,最多': '편집 후 최신 프로젝트 상태를 검사합니다. 최대', + '自主验收最大轮次': '최대 자율 검수 반복 횟수', + '轮': '회', + '自主验收:{status} · 第 {iteration}/{max} 轮': '자율 검수: {status} · {iteration}/{max}회차', + '检查中': '검사 중', + '等待补充信息': '입력 대기 중', + '已通过': '통과', + '未通过': '통과하지 못함', + '选择模式:点片段 / 拖画布 / 选文字稿作为引用': '선택 모드: 클립 클릭 / 캔버스 드래그 / 전사 텍스트 선택으로 참조 추가', + '引用媒体池素材': '미디어 풀의 미디어 참조', + '媒体池暂无素材': '미디어 풀에 아직 미디어가 없습니다', + '引用模板库': '템플릿 라이브러리 참조', + '引用': '참조', + '时间线': '타임라인', + '时间线暂无片段': '타임라인에 아직 클립이 없습니다', + '暂无模板': '아직 템플릿이 없습니다', + '创作模式': '크리에이티브 모드', + '创作模式:{name}': '크리에이티브 모드: {name}', + '选择创作工作流': '크리에이티브 워크플로 선택', + '工作流会约束 Agent 的规划与工具调用。': '워크플로는 에이전트의 계획과 도구 사용 방향을 안내합니다.', + '自由创作': '자유 형식', + '不限定工作流,根据当前目标灵活执行。': '고정된 워크플로 없이 현재 목표에 따라 유연하게 작업합니다.', + '专业工作流': '전문 워크플로', + '自定义': '사용자 지정', + '增强中…': '개선 중…', + '增强提示词': '프롬프트 개선', + '停止': '중지', + '发送 (Enter)': '보내기 (Enter)', + '发送时以 chat_context_entry 结构化注入': '전송 시 구조화된 chat_context_entry로 주입됩니다', + '移除引用': '참조 제거', + '导入素材中…': '미디어 가져오는 중…', + '请等待附件导入完成。': '첨부 파일 가져오기가 끝날 때까지 기다리세요.', + '关闭': '닫기', + '技能命令补全': '스킬 명령 자동 완성', + '创作工作流': '크리에이티브 워크플로', + '技能命令': '스킬 명령', + '没有匹配“{query}”的创作工作流': '‘{query}’와(과) 일치하는 크리에이티브 워크플로가 없습니다', + '未知技能“{query}”,按 / 查看全部创作工作流': '알 수 없는 스킬 ‘{query}’ — /를 입력하면 모든 크리에이티브 워크플로를 볼 수 있습니다', + 'Tab / Enter 补全并激活 · Esc 退出': 'Tab / Enter 완성 및 활성화 · Esc 종료', + '把一条长播客、访谈、课程或直播剪成适合社媒发布的短视频和高光。': '긴 팟캐스트, 인터뷰, 강의 또는 라이브 방송을 소셜 미디어용 쇼츠와 하이라이트로 편집합니다.', + '把产品、活动、旅行或游戏素材剪成适合社媒发布的 Reels。': '제품, 이벤트, 여행 또는 게임 플레이 영상을 소셜 미디어용 릴스로 만듭니다.', + '规划并制作 AI 电影感短片,覆盖故事、镜头、提示词、连续性和最终检查。': '스토리, 샷, 프롬프트, 연속성, 최종 점검을 포함해 AI 시네마틱 단편을 기획하고 제작합니다.', + '把产品或页面转成广告角度、开头钩子、分镜、字幕、CTA 和视觉方向。': '제품이나 페이지를 바탕으로 광고의 소구점, 훅, 스토리보드, 자막, CTA와 비주얼 방향을 구성합니다.', + '把主题、脚本、配音、产品逻辑或数据做成完整解说视频。': '주제, 스크립트, 내레이션, 제품 로직 또는 데이터를 완성된 설명 영상으로 만듭니다.', + '在合适时机添加动效,强化表达且不遮挡内容。': '콘텐츠를 가리지 않으면서 메시지를 강화하도록 적절한 순간에 모션 그래픽을 추가합니다.', + '逐镜拆解镜头语言,并生成分镜参考图。': '샷별로 촬영 언어를 분석하고 스토리보드 참고 이미지를 생성합니다.', + '基于视频内容和真实画面生成适合平台的封面图。': '영상 콘텐츠와 실제 프레임으로 플랫폼에 맞는 썸네일을 생성합니다.', + '请分析当前长视频,挑选最有传播力的高光片段,剪成节奏紧凑的竖屏短视频,并完成字幕、标题和发布前检查。': '현재 긴 영상을 분석해 가장 공유하기 좋은 순간을 골라 빠른 템포의 세로 쇼츠로 편집하고, 자막, 제목, 게시 전 QA까지 마무리해 주세요.', + '请梳理当前素材,选出最有表现力的镜头,按钩子、推进、高潮和收尾重组为一支竖屏 Reels,并完成配乐与节奏优化。': '현재 미디어를 검토해 가장 좋은 샷을 고르고, 훅·전개·클라이맥스·엔딩 구조의 세로 릴스로 구성한 뒤 음악과 페이싱을 다듬어 주세요.', + '请根据当前主题规划一支电影感短片,先确定故事结构和视觉风格,再生成连贯镜头,完成声音、节奏和成片检查。': '현재 주제로 시네마틱 단편을 기획해 주세요. 스토리와 비주얼 스타일을 정하고, 일관된 샷을 생성한 뒤 사운드, 페이싱, 최종 QA를 마무리해 주세요.', + '请提炼产品核心卖点和目标人群,设计有吸引力的开头、分镜、字幕与行动引导,并整理成可直接制作的短视频脚本。': '제품의 핵심 가치와 타깃 고객을 도출한 뒤, 강력한 훅, 스토리보드, 자막, CTA와 바로 제작 가능한 숏폼 스크립트를 만들어 주세요.', + '请把当前主题或资料整理成清晰的解说视频,完成内容结构、旁白、画面匹配、字幕与节奏设计,并检查信息是否准确。': '현재 주제나 자료를 구성, 내레이션, 매칭된 화면, 자막, 페이싱, 사실 확인을 갖춘 명확한 설명 영상으로 만들어 주세요.', + '请分析当前时间线,在不遮挡主体和字幕的前提下,为重点信息添加克制的标题、强调动效与转场,并统一节奏和视觉风格。': '현재 타임라인을 검토해 피사체나 자막을 가리지 않도록 절제된 타이틀, 강조 모션, 전환 효과를 추가하고 페이싱과 스타일을 일관되게 유지해 주세요.', + '请逐镜分析参考视频的构图、景别、运镜、节奏和转场,整理成可复用的分镜表,并为关键镜头生成清晰的画面参考。': '참고 영상의 구도, 프레이밍, 카메라 움직임, 페이싱, 전환을 샷별로 분석한 다음 재사용 가능한 스토리보드와 핵심 샷 참고 이미지를 만들어 주세요.', + '请根据当前视频内容筛选真实高质量画面,设计适合发布平台的封面构图、标题和视觉层级,并输出可直接使用的封面方案。': '현재 영상에서 좋은 실제 프레임을 골라 명확한 구도, 제목, 시각적 위계를 갖춘 플랫폼용 커버를 디자인하고 바로 쓸 수 있는 결과물로 만들어 주세요.', + '收起思考过程': '사고 과정 접기', + '展开思考过程': '사고 과정 펼치기', + '思考过程': '사고 과정', + '已复制': '복사됨', + '复制文本': '복사', + '有帮助': '도움이 됨', + '没帮助': '도움이 안 됨', + '编辑提案': '편집 제안', + '待确认': '검토 대기 중', + '影响范围': '영향 범위', + '将执行': '적용 예정', + '/ {total} 项': '/ {total}개 작업', + '全选': '모두 선택', + '清空': '지우기', + '在预览窗查看提案结果(不改正式时间线)': '플레이어에서 결과 미리보기 (실제 타임라인은 변경되지 않음)', + '预览中': '미리 보는 중', + '预览结果': '결과 미리보기', + '拒绝': '거부', + '应用': '적용', + '收起': '접기', + '展开全部': '모두 펼치기', + '{n} 次': '{n}회 호출', + '必选': '필수', + '可选': '선택', + '其他…': '기타…', + '请输入': '여기에 입력', + '已提交': '제출됨', + '选择后提交,Agent 会按你的选择继续': '선택 후 제출하세요 — 에이전트가 선택한 내용으로 계속 진행합니다', + '提交': '제출', + '拖动调整输入框高度': '드래그하여 입력창 크기 조절', + '上下拖动调整输入框高度': '위아래로 드래그하여 입력창 크기 조절', + '已连续执行 {n} 轮工具,先停一下确认方向。': '도구를 {n}턴 연속 실행했습니다 — 방향을 확인하기 위해 잠시 멈춥니다.', + '本轮有 {n} 个工具调用失败,模型已据此作答:{details}': '이번 실행에서 도구 호출 {n}개가 실패했으며, 모델은 이를 반영해 답변했습니다: {details}', + '继续': '계속', + 'AI 请求运行生成技能:{name}': 'AI가 생성 스킬을 실행하려고 합니다: {name}', + '本工程不再询问': '이 프로젝트에서 항상 허용', + '所有工程不再询问': '모든 프로젝트에서 항상 허용', + '图像生成': '이미지 생성', + 'MG 动画生成': '모션 그래픽 생성', + '正在编写参数…': '인수 작성 중…', + '正在执行…': '실행 중…', + '工程已在提案生成后发生变化:直接应用可能落错位置。': '이 제안이 생성된 후 프로젝트가 변경되었습니다 — 그대로 적용하면 편집이 잘못된 위치에 들어갈 수 있습니다.', + '仍然应用': '그래도 적용', + '重新提案': '다시 제안', + '外部 Agent:{message}': '외부 에이전트: {message}', + '工程已在其他窗口编辑或版本已变化,请关闭其他窗口后手动刷新页面。': '이 프로젝트가 다른 편집기에서 열려 있거나 버전이 변경되었습니다. 다른 창을 닫은 후 이 페이지를 직접 새로 고치세요.', + '工程正在其他窗口编辑,无法注册。请关闭其他窗口后重试。': '이 프로젝트를 다른 창에서 편집 중이어서 등록하지 못했습니다. 다른 창을 닫고 다시 시도하세요.', + '工程正在其他窗口编辑,连接已中断。请关闭其他窗口后重试。': '이 프로젝트를 다른 창에서 편집 중이어서 연결이 끊어졌습니다. 다른 창을 닫고 다시 시도하세요.', + '工程正在其他窗口编辑,结果未能送达。请关闭其他窗口后重试。': '이 프로젝트를 다른 창에서 편집 중이어서 결과를 전달하지 못했습니다. 다른 창을 닫고 다시 시도하세요.', + '无法清空上下文与运行记录。': '컨텍스트와 실행 기록을 지울 수 없습니다.', + '运行 {runId}({status})仍在进行。请先停止该运行,确认检查器中没有活动任务后再重试。': '실행 {runId}({status})이(가) 아직 진행 중입니다. 실행을 중지하고 검사기에 활성 작업이 없는지 확인한 후 다시 시도하세요.', + '请确认没有其他 Agent 正在运行,并重试。': '실행 중인 다른 에이전트가 없는지 확인한 후 다시 시도하세요.', + '加载更早消息': '이전 메시지 불러오기', + '更多工具': '도구 더 보기', + '选择引用': '참조 선택', + '工程后来已有其他修改,回滚前会再次确认': '프로젝트에 이후 편집 내용이 있습니다. 롤백 전에 확인을 요청합니다.', + '工程后来已有其他修改,继续回滚会覆盖后续修改。确定继续吗?': '프로젝트에 이후 편집 내용이 있습니다. 롤백하면 해당 내용을 덮어씁니다. 계속하시겠습니까?', + '取消创作模式': '크리에이티브 모드 종료', + '回滚此会话': '이 세션 롤백', + '当前创作工作流,随消息发送': '현재 크리에이티브 워크플로 (메시지와 함께 전송됨)', + '确认': '확인', + '缓存': '캐시', + '工具': '도구', + '命中率': '적중률', + '诊断': '진단', + '工具定义': '도구 스키마', + '输入 token:最近一次模型请求的输入量(提示词+工具结果)': '최근 모델 요청의 입력 토큰(프롬프트 + 도구 결과)입니다.', + '输出 token:最近一次模型请求返回的文本量': '최근 모델 요청이 반환한 출력 토큰입니다.', + '系统提示词占用的输入 token': '시스템 프롬프트가 사용한 입력 토큰입니다.', + '对话历史占用的输入 token': '대화 기록이 사용한 입력 토큰입니다.', + '缓存读:本次命中缓存的输入 token 数;命中越多越省': '캐시 읽기: 이번 요청에서 기존 캐시로 처리된 입력 토큰입니다.', + '缓存写:本次写入缓存的 token 数(仅部分模型支持)': '캐시 쓰기: 이번 요청에서 캐시에 기록된 입력 토큰입니다(일부 모델만 지원).', + '未缓存:本次未命中缓存、需重新计算的输入 token': '미캐시: 캐시되지 않아 새로 계산해야 했던 입력 토큰입니다.', + '本次运行累计的缓存命中比例': '이번 실행에서 전체 입력 중 캐시로 처리된 비율입니다.', + '上次缓存未命中的原因,用于判断为何没省到缓存': '마지막 캐시 미스 원인으로, 비용이 절감되지 않은 이유를 확인할 수 있습니다.', + '本次请求向模型开放可调用的工具数量': '최근 요청에서 모델이 호출할 수 있었던 도구 수입니다.', + '随请求一起发送给模型的工具 Schema 数量': '요청과 함께 모델에 전송된 도구 스키마 수입니다.', + '本次运行累计发起的模型请求次数': '이번 실행에서 지금까지 보낸 모델 요청 총수입니다.', + '本次运行所有模型请求的输入 token 之和': '이번 실행의 모든 모델 요청 입력 토큰 합계입니다.', + '未命中任何缓存、真正新计算的输入 token 之和': '이번 실행에서 캐시 적중 없이 새로 계산된 입력 토큰입니다.', + '本次运行所有模型请求的输出 token 之和': '이번 실행의 모든 모델 요청 출력 토큰 합계입니다.', + '本次运行因临时错误自动重试的次数': '이번 실행에서 일시적 오류 후 모델 요청을 자동 재시도한 횟수입니다.', + '本次发送给模型的图片数量': '이번 실행에서 모델에 전송된 이미지 수입니다.', + '全部工具 Schema 的字符数,衡量工具面大小': '모든 도구 스키마의 총 문자 수로, 도구 범위 크기를 대략 나타냅니다.', + '本次运行与最近一次模型请求的 token 用量、缓存与工具面信息': '이번 실행과 최근 모델 요청의 토큰 사용량, 캐시 및 도구 범위 정보입니다.', + '长对话被压缩后的摘要检查点,用于追溯上下文如何被裁剪': '긴 대화가 압축될 때 저장된 요약 체크포인트로, 컨텍스트가 어떻게 축소되었는지 보여 줍니다.', + '最近调用的工具及其执行结果(只列最近 8 条)': '최근 호출된 도구와 결과입니다(최근 8개만).', + '本次运行涉及的确认/审批记录(只列前 6 条)': '이번 실행의 확인/승인 기록입니다(처음 6개만).', + '本次运行归档的产物记录(只列前 6 条)': '이번 실행에서 보관된 결과물입니다(처음 6개만).', + '以下能力未配置,相关功能暂不可用:': '다음 기능이 구성되지 않아 관련 기능을 사용할 수 없습니다: ', + '去设置配置': '설정 열기', + '去设置安装': '설정에서 설치', + '当前请求的上下文超出了模型限制,系统已自动压缩并重试但仍放不下。换个更短的问法或新开一个聊天继续即可。': '현재 요청이 모델 컨텍스트 한도를 초과합니다. 자동 압축 및 재시도를 이미 실행했지만 여전히 한도를 넘습니다. 더 짧은 프롬프트를 사용하거나 새 채팅에서 계속하세요.', + '转写': '전사 텍스트', + '图片生成': '이미지 생성', + '语音合成': '음성', + '视频生成': '동영상 생성', + '音乐生成': '음악', + '音效生成': '효과음 생성', +} as Record; diff --git a/src/i18n/dict/ko/components.ts b/src/i18n/dict/ko/components.ts new file mode 100644 index 000000000..6500702a1 --- /dev/null +++ b/src/i18n/dict/ko/components.ts @@ -0,0 +1,359 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '背景颜色': '배경 색상', + '透明度': '불투명도', + '字体样式': '글꼴 스타일', + '间距与排版': '간격 및 타이포그래피', + '字间距': '자간', + '行高': '줄 높이', + '文字背景': '텍스트 배경', + '启用背景': '배경 사용', + '胶囊形状': '알약 모양', + '水平内边距': '가로 안쪽 여백', + '垂直内边距': '세로 안쪽 여백', + '背景模糊': '배경 흐림', + '细体': '가늘게', + '中等': '중간', + '斜体': '기울임꼴', + '默认系统字体': '기본 시스템 글꼴', + '当前字体': '현재 글꼴', + '用户安装字体': '사용자 설치 글꼴', + '自定义字体': '사용자 지정 글꼴', + 'Google 字体': 'Google 글꼴', + '内置字体': '내장 글꼴', + '系统字体': '시스템 글꼴', + '输入自定义字体名称…': '사용자 지정 글꼴 이름 입력…', + '扫描并刷新已安装字体': '설치된 글꼴 검색 및 새로 고침', + '输入字体名称,例如 JetBrains Mono': '글꼴 이름(예: JetBrains Mono)', + '自定义字体名称': '사용자 지정 글꼴 이름', + '发现 OpenChatCut 新版本 {latest},当前版本 {current}。请前往项目仓库查看更新。': 'OpenChatCut {latest} 버전을 사용할 수 있습니다. 현재 버전: {current}. 프로젝트 저장소에서 업데이트를 확인하세요.', + '当前已是最新版本 {version}': '최신 버전({version})을 사용 중입니다.', + '暂时无法检查更新,请稍后重试': '업데이트를 확인할 수 없습니다. 잠시 후 다시 시도하세요.', + '发现 OpenChatCut 新版本 {latest},当前版本 {current}。可以直接下载并安装。': 'OpenChatCut {latest} 버전을 사용할 수 있습니다. 현재 버전: {current}. 바로 다운로드하여 설치할 수 있습니다.', + '正在下载 OpenChatCut {latest}:{percent}%': 'OpenChatCut {latest} 다운로드 중: {percent}%', + 'OpenChatCut {latest} 已下载,重启后完成安装。': 'OpenChatCut {latest} 다운로드가 완료되었습니다. 다시 시작하면 설치가 완료됩니다.', + '正在重启并安装 OpenChatCut…': 'OpenChatCut을 설치하기 위해 다시 시작하는 중…', + '下载更新失败,请重试': '업데이트 다운로드에 실패했습니다. 다시 시도하세요.', + '安装更新失败,请重试': '업데이트 설치에 실패했습니다. 다시 시도하세요.', + '下载更新': '업데이트 다운로드', + '查看发布页': '릴리스 보기', + '下载中 {percent}%': '다운로드 중 {percent}%', + '重启并安装': '다시 시작 및 설치', + '正在重启…': '다시 시작하는 중…', + '重试下载': '다운로드 재시도', + '重试安装': '설치 재시도', + '重新检查': '다시 확인', + '加载工程…': '프로젝트 불러오는 중…', + '加载编辑器…': '편집기 불러오는 중…', + '加载中…': '불러오는 중…', + '工程不存在,返回…': '프로젝트를 찾을 수 없습니다. 돌아가는 중…', + '工程数据暂时无法读取': '프로젝트 데이터를 일시적으로 읽을 수 없습니다', + '为避免覆盖已保存的内容,已停止打开该工程。数据仍保留在本机存储中,可稍后重试。': '저장된 작업을 덮어쓰지 않도록 프로젝트 열기를 중단했습니다. 데이터는 로컬 저장소에 그대로 있으니 잠시 후 다시 시도하세요.', + '编辑器需要通过 localhost 或 HTTPS 访问': '편집기는 localhost 또는 HTTPS에서만 사용할 수 있습니다', + '当前地址不是浏览器认可的安全上下文,编辑器依赖的 Web Crypto、WebCodecs 视频解码和剪贴板等能力在这里被禁用。请在运行 OpenChatCut 的电脑上打开 http://localhost 或 http://127.0.0.1,或通过 HTTPS 提供服务。': '이 주소는 보안 컨텍스트가 아니므로 브라우저가 편집기에 필요한 Web Crypto, WebCodecs 동영상 디코딩, 클립보드 등의 기능을 비활성화합니다. OpenChatCut을 실행 중인 컴퓨터에서 http://localhost 또는 http://127.0.0.1을 열거나 HTTPS로 제공하세요.', + '当前地址:{origin}': '현재 주소: {origin}', + '编辑器出现错误': '편집기에서 오류가 발생했습니다', + '重新加载': '다시 불러오기', + '已导出「{name}」;{n} 个素材两端都取不到,未随包': '‘{name}’을(를) 내보냈습니다. 미디어 {n}개는 양쪽 모두에서 찾을 수 없어 포함되지 않았습니다', + '已导出「{name}」(含 {n} 个素材)': '‘{name}’을(를) 내보냈습니다(미디어 {n}개 포함)', + '导入失败:{error}': '가져오기 실패: {error}', + '已导入「{name}」;缺 {n} 个素材({list})': '‘{name}’을(를) 가져왔습니다. 미디어 {n}개 누락({list})', + '已导入「{name}」(素材 {a}/{b})': '‘{name}’을(를) 가져왔습니다(미디어 {a}/{b})', + '参考模板「{name}」,用 create_motion_graphic 生成一个类似风格的动画: @{name} ': '템플릿 ‘{name}’을(를) 스타일 참고로 삼아 create_motion_graphic으로 비슷한 애니메이션을 생성하세요: @{name} ', + '工程保存失败。请重试;在保存成功前不会关闭或切换工程。': '프로젝트 저장에 실패했습니다. 프로젝트를 닫거나 전환하기 전에 다시 시도하세요.', + '工程仍未保存,已阻止离开。请继续编辑以重试保存。': '프로젝트가 아직 저장되지 않아 이동이 차단되었습니다. 계속 편집하면 저장을 다시 시도합니다.', + '刚刚': '방금 전', + '{n} 分钟前': '{n}분 전', + '{n} 小时前': '{n}시간 전', + '{n} 天前': '{n}일 전', + '生成任务': '생성 작업', + '旧版参数摘要(不可安全重跑)': '이전 버전 매개변수 요약(안전하게 다시 실행할 수 없음)', + '参数快照不可用': '매개변수 스냅샷을 사용할 수 없음', + '刷新后仍可继续检查、下载或重跑': '새로 고침 후에도 작업 확인, 다운로드, 다시 실행을 계속할 수 있습니다', + '恢复中…': '재개하는 중…', + '继续任务': '작업 재개', + '正在读取任务…': '작업 불러오는 중…', + '暂无生成任务': '생성 작업 없음', + 'Provider 任务': '공급자 작업', + '打开结果': '결과 열기', + '重试可恢复任务': '복구 가능한 작업 재시도', + '检查进度': '진행 상황 확인', + '等待中': '대기 중', + '进行中': '실행 중', + '已完成': '완료됨', + '失败': '실패', + '未找到': '찾을 수 없음', + '可重试下载': '다운로드 재시도 가능', + '可重试生成': '생성 재시도 가능', + '重启后可恢复': '다시 시작 후 복구 가능', + '不可重试': '재시도 불가', + '旧任务状态未知': '이전 작업 상태 알 수 없음', + '· 我的工程': '· 내 프로젝트', + '示例工程': '예제 프로젝트', + '设置 · API 密钥': '설정 · API 키', + '联系作者': '개발자에게 연락', + 'GitHub 仓库': 'GitHub 저장소', + '配置模型后开始使用 Agent': '에이전트를 사용하려면 모델을 구성하세요', + '配置任一云端或本地模型,即可在编辑器中使用对话式剪辑。': '클라우드 또는 로컬 모델을 구성하면 편집기에서 대화형 편집을 사용할 수 있습니다.', + '配置模型': '모델 구성', + '处理中…': '처리 중…', + '失败:{error}': '실패: {error}', + '工程': '프로젝트', + '清理所有工程都不引用的上传素材(测试/已删工程残留)': '어떤 프로젝트에서도 참조하지 않는 업로드 미디어 정리(테스트/삭제된 프로젝트의 잔여 파일)', + '清理素材': '미디어 정리', + '导入 .ccproj 工程文件(兼容旧 .ccproj.json)': '.ccproj 프로젝트 파일 가져오기(이전 .ccproj.json도 지원)', + '导入工程': '프로젝트 가져오기', + '{n} 个': '총 {n}개', + '{n} / {total} 个': '{n} / {total}개', + '搜索工程': '프로젝트 검색', + '清除搜索': '검색 지우기', + '没有找到匹配“{query}”的工程': '‘{query}’와(과) 일치하는 프로젝트가 없습니다', + '新建工程': '새 프로젝트', + '打开 {name}': '{name} 열기', + '双击重命名': '두 번 클릭하여 이름 바꾸기', + '彻底删除工程,并清掉只有它引用的素材文件': '이 프로젝트를 영구 삭제하고 이 프로젝트만 참조하는 미디어도 제거합니다', + '确认删除': '삭제 확인', + '已永久删除「{name}」': '‘{name}’을(를) 영구 삭제했습니다', + '重命名': '이름 바꾸기', + '复制': '복제', + '导出为流式 .ccproj(含素材,可在桌面版/其它机器导入)': '스트리밍 .ccproj로 내보내기(미디어 포함, 다른 컴퓨터에서 가져오기 가능)', + '删除': '삭제', + '导出历史': '내보내기 기록', + '关闭': '닫기', + '还没有导出记录': '아직 내보내기 기록이 없습니다', + '打开文件夹': '폴더 열기', + '清空历史': '기록 지우기', + '历史版本': '버전 기록', + '还没有保存过版本': '아직 저장된 버전이 없습니다', + '恢复': '복원', + '删除此版本': '이 버전 삭제', + '版本名称': '버전 이름', + '确定': '확인', + '取消': '취소', + '保存当前版本': '현재 버전 저장', + '预览': '미리보기', + '时间线悬停预览': '타임라인 호버 미리보기', + '选择模式:在画面上拖框选区作为引用': '선택 모드: 화면에서 상자를 드래그하여 해당 영역을 참조로 사용', + '切换标题/动作安全区参考框(竖屏成片构图辅助)': '타이틀/액션 안전 영역 가이드 전환(세로 영상 구도 보조)', + '安全框': '안전 영역', + '预览画质': '미리보기 화질', + '自动': '자동', + '高清': '고화질', + '流畅': '부드럽게', + '高清:显示原始素材,画质最好,可能更吃性能': '고화질: 원본 미디어 표시(최고 화질, CPU/GPU를 더 많이 사용할 수 있음)', + '流畅:使用轻量副本,播放更流畅': '부드럽게: 가벼운 사본을 사용해 원활하게 재생', + '自动:跟随画质策略(画质优先=高清,均衡=流畅)': '자동: 화질 정책을 따름(화질 우선=고화질, 균형=부드럽게)', + '正在导入媒体…': '미디어 가져오는 중…', + '拖拽媒体到这里': '여기에 미디어를 놓으세요', + '拖拽框选画面区域作为引用': '드래그하여 화면 영역을 참조로 선택', + '拖动调整大小': '드래그하여 크기 조절', + '(预览)': '(미리보기)', + '视频 URL 或 /media/uploads/…': '동영상 URL 또는 /media/uploads/…', + '图片 URL 或 /media/uploads/…': '이미지 URL 또는 /media/uploads/…', + '上一关键帧': '이전 키프레임', + '下一关键帧': '다음 키프레임', + '更新播放头处的关键帧': '재생 헤드 위치의 키프레임 업데이트', + '在播放头打关键帧': '재생 헤드 위치에 키프레임 추가', + '删除播放头处的关键帧': '재생 헤드 위치의 키프레임 삭제', + '缓动(此关键帧到下一帧的曲线)': '이징(이 키프레임에서 다음 키프레임까지의 곡선)', + '线性': '선형', + '缓入': '이즈 인', + '缓出': '이즈 아웃', + '缓入出': '이즈 인-아웃', + '贝塞尔': '베지어', + '缩放比例': '배율', + '横向缩放': '가로 배율', + '纵向缩放': '세로 배율', + '水平': '가로', + '垂直': '세로', + '旋转': '회전', + '透明': '불투명도', + '裁左': '왼쪽 자르기', + '裁右': '오른쪽 자르기', + '裁上': '위쪽 자르기', + '裁下': '아래쪽 자르기', + '音量': '볼륨', + '淡入': '페이드 인', + '淡出': '페이드 아웃', + '输入{name}的精确值': '{name}의 정확한 값 입력', + '点击输入精确值;左右拖动调整;Shift ×10;⌘ ×0.1': '클릭하여 정확한 값 입력, 좌우로 드래그하여 조절, Shift ×10, ⌘ ×0.1', + '重置{name}': '{name} 초기화', + '重置整个分组': '그룹 전체 초기화', + '重置': '초기화', + '文字内容': '텍스트 내용', + '字号': '글꼴 크기', + '颜色': '색상', + '对齐': '정렬', + '左': '왼쪽', + '中': '가운데', + '右': '오른쪽', + '粗细': '굵기', + '常规': '보통', + '粗体': '굵게', + '特粗': '아주 굵게', + '曲线': '곡선', + '无': '없음', + '倍数': '확대 배율', + '焦点X': '초점 X', + '焦点Y': '초점 Y', + '在播放头记录焦点+倍数为关键帧': '재생 헤드 위치에 초점 + 확대 배율을 키프레임으로 기록', + '关键帧': '키프레임', + '关键帧(覆盖曲线,逐帧插值)': '키프레임(곡선을 대체하며 프레임 단위로 보간)', + '删除关键帧': '키프레임 삭제', + '与前一段相邻音频交叉淡化(出点渐弱 / 入点渐强)': '앞의 인접 오디오와 크로스페이드(컷에서 페이드 아웃 / 이후 페이드 인)', + '从前一个相邻片段进入本片段': '앞의 인접 클립에서 이 클립으로 전환', + '类型': '유형', + '时长': '길이', + '方向': '방향', + '上': '위', + '下': '아래', + '亮度': '밝기', + '对比': '대비', + '饱和': '채도', + '模糊': '흐림', + '自动校色': '자동 색 보정', + '保守型技术修正': '보수적인 기술 보정', + '分析选中片段': '선택한 클립 분석', + '请选择已导入媒体池的视频、图片或 GIF 片段': '미디어 풀에 가져온 동영상, 이미지 또는 GIF 클립을 선택하세요', + '本机抽样分析,仅做小幅亮度、对比和饱和度修正,不添加创意 LUT。': '로컬에서 미디어를 샘플링하여 밝기, 대비, 채도만 소폭 보정합니다. 크리에이티브 LUT는 추가하지 않습니다.', + '预览中 · {n} 个片段': '미리 보는 중 · 클립 {n}개', + ' · {n} 个失败': ' · {n}개 실패', + '应用校色': '보정 적용', + '画面文字已烘焙,仅可整体缩放移动': '화면 텍스트가 영상에 합성되어 있어 클립 전체만 이동/크기 조절할 수 있습니다', + '模板': '템플릿', + '让 AI 改写这段文字': 'AI에게 이 화면 텍스트 다시 쓰기 요청', + '优化这段画面文字(保持版式):「{text}」': '이 화면 텍스트를 개선하세요(레이아웃 유지): ‘{text}’', + '(空)': '(비어 있음)', + '字重': '굵기', + '取消预览': '미리보기 취소', + '未获得可用的校色结果': '사용 가능한 색 보정 결과가 반환되지 않았습니다', + '已预览 {n} 个片段,{failed} 个分析失败': '클립 {n}개 미리 보는 중, {failed}개 분석 실패', + '自动校色预览已生成,可确认应用或取消': '자동 색 보정 미리보기가 준비되었습니다. 적용하거나 취소하세요.', + '自动校色分析失败:{error}': '자동 색 보정 분석 실패: {error}', + '已将自动校色应用到 {n} 个片段': '클립 {n}개에 자동 색 보정을 적용했습니다', + '+ 添加特效…': '+ 효과 추가…', + '尚未添加特效。': '아직 추가된 효과가 없습니다.', + '上移': '위로 이동', + '下移': '아래로 이동', + '移除特效': '효과 제거', + '展开属性': '속성 펼치기', + '收起属性': '속성 접기', + '属性': '속성', + '片段属性': '클립 속성', + '片段': '클립', + '图片': '이미지', + '动效图形': '모션 그래픽', + '仅作用于当前时间线片段,不修改媒体池中的源文件。': '이 타임라인 클립에만 적용되며 미디어 풀의 원본 파일은 변경되지 않습니다.', + '仅作用于当前时间线片段。': '이 타임라인 클립에만 적용됩니다.', + '没有更早的关键帧': '이전 키프레임 없음', + '没有更晚的关键帧': '다음 키프레임 없음', + '属性分类': '속성 카테고리', + '基础': '기본', + '动画': '애니메이션', + '人声隔离': '음성 분리', + '隔离强度': '분리 강도', + '应用人声隔离': '음성 분리 적용', + '重新隔离': '다시 분리', + '清除': '지우기', + '需先上传到媒体池(/media/uploads)': '먼저 미디어 풀에 업로드하세요(/media/uploads)', + '用本机 ffmpeg 频谱降噪,保留原轨': '로컬 ffmpeg 스펙트럼 노이즈 제거, 원본 트랙 유지', + '已应用 · 播放用隔离音轨 · master 不变': '적용됨 · 재생 시 분리된 오디오 사용 · 마스터는 변경되지 않음', + '开箱 ffmpeg 降噪(非 DeepFilterNet3)': '기본 제공 ffmpeg 노이즈 제거(DeepFilterNet3 아님)', + '选中时间线上的片段以编辑属性。': '속성을 편집하려면 타임라인에서 클립을 선택하세요.', + '音频片段。可在时间线上拖动位置、裁剪首尾。': '오디오 클립입니다. 타임라인에서 드래그하여 이동하거나 양 끝을 트리밍할 수 있습니다.', + '视频片段。可在时间线上拖动位置、裁剪首尾(左裁剪推进源入点)。': '비디오 클립입니다. 타임라인에서 드래그하여 이동하거나 양 끝을 트리밍할 수 있습니다(왼쪽 가장자리를 트리밍하면 소스 시작점이 더 나중 시점으로 이동합니다).', + '图片片段。': '이미지 클립입니다.', + 'GIF 片段。': 'GIF 클립입니다.', + 'SVG 片段。': 'SVG 클립입니다.', + '纯色片段。': '단색 클립입니다.', + '文字片段。': '텍스트 클립입니다.', + '文字': '텍스트', + '变换': '변형', + '滤镜': '필터', + '特效': '효과', + '画布': '캔버스', + '背景填充': '배경 채우기', + '用片段副本填满画布空白': '클립 복사본으로 캔버스의 빈 영역 채우기', + '背景填充强度': '배경 채우기 강도', + '背景填充效果': '배경 채우기 효과', + '轻度': '약하게', + '标准': '표준', + '强烈': '강하게', + '极强': '최대', + '所选片段使用不同的背景强度': '선택한 클립의 배경 강도가 서로 다릅니다', + '全部应用': '모두 적용', + '收起背景填充效果': '배경 채우기 효과 접기', + '展开背景填充效果': '배경 채우기 효과 펼치기', + '已将背景填充应用到 {n} 个片段': '클립 {n}개에 배경 채우기를 적용했습니다', + '转场': '트랜지션', + '音频转场': '오디오 트랜지션', + '淡入淡出': '페이드', + '纯色': '단색', + '填充颜色': '채우기 색상', + '该模板无可编辑属性。': '이 템플릿에는 편집 가능한 속성이 없습니다.', + '闪白转场': '플래시', + '径向模糊转场': '방사형 블러', + '故障切换转场': '글리치 컷', + '闪色转场': '색상으로 디졸브', + '音频交叉淡化': '오디오 크로스페이드', + '自定义着色器转场': '사용자 지정 셰이더', + '冲击': '펀치', + '瞬时': '즉시', + '心跳脉冲': '펄스', + '保调变速(预览/导出)· 时长随速率伸缩并波纹合缝': '피치를 유지하며 속도 조절(미리보기/내보내기) · 길이가 속도에 맞춰 조정되고 이후 클립도 함께 이동', + '分析中…': '분석 중…', + '分析并归一到 -14 LUFS': '분석 후 -14 LUFS로 정규화', + '响度归一 (-14 LUFS)': '음량 정규화(-14 LUFS)', + '离线素材:{list}': '오프라인 미디어: {list}', + 'CSS 回退预览 · 不代表导出效果': 'CSS 대체 미리보기 · 내보내기 결과와 다를 수 있음', + 'Enter 向后滑移 · Shift+Enter 向前滑移;仅改变源入点。': 'Enter로 뒤로 슬립 · Shift+Enter로 앞으로 슬립합니다. 소스 시작점만 변경됩니다.', + 'WebGL2 不可用': 'WebGL2를 사용할 수 없음', + '{n} 个导出': '내보내기 {n}개', + '{n} 个片段': '클립 {n}개', + '从角点 {n} 等比缩放片段': '모서리 {n}에서 클립 비율 유지 크기 조절', + '向前': '앞으로', + '向后': '뒤로', + '字幕属性': '자막 속성', + '将源区间向前滑移,时间线位置和时长不变': '소스 구간을 앞으로 슬립합니다. 타임라인 위치와 길이는 유지됩니다', + '将源区间向后滑移,时间线位置和时长不变': '소스 구간을 뒤로 슬립합니다. 타임라인 위치와 길이는 유지됩니다', + '嵌套序列': '중첩 시퀀스', + '已到达源素材边界': '소스 미디어의 경계에 도달했습니다', + '已选择 {n} 个片段': '클립 {n}개 선택됨', + '所选片段的特效堆栈不同;请先统一堆栈后再批量编辑。': '선택한 클립의 효과 스택이 서로 다릅니다. 일괄 편집하려면 먼저 스택을 통일하세요.', + '把播放头移进这个片段才能打关键帧': '키프레임을 설정하려면 재생 헤드를 이 클립 안으로 이동하세요', + '把播放头移进这个片段才能改这里的关键帧': '키프레임을 편집하려면 재생 헤드를 이 클립 안으로 이동하세요', + '文字描边': '텍스트 윤곽선', + '文字阴影': '텍스트 그림자', + '文描透明度': '윤곽선 불투명도', + '旋转片段': '클립 회전', + '时间线帧': '타임라인 프레임', + '查看后台导出任务': '백그라운드 내보내기 작업 보기', + '正在准备流畅预览…': '부드러운 미리보기 준비 중…', + '正在准备真实 GL 预览…': '실제 GL 미리보기 준비 중…', + '正在加载效果预览;暂时显示回退画面': '효과 미리보기를 불러오는 중입니다. 잠시 대체 화면을 표시합니다', + '步长': '단계 크기', + '流畅预览暂不可用,已自动使用原画质播放(画面正常,不影响导出)': '부드러운 미리보기를 사용할 수 없어 원본 화질로 재생합니다(화면은 정상이며 내보내기에는 영향이 없습니다)', + '源入点': '소스 시작점', + '源出点': '소스 종료점', + '源画面回退 · 当前未显示特效': '소스 대체 화면 · 효과가 표시되지 않음', + '滑移': '슬립', + '滑移预览': '슬립 미리보기', + '真实 GL 预览 · 与导出共用参数': '실제 GL 미리보기 · 내보내기와 같은 매개변수 사용', + '着色器编译或运行失败': '셰이더 컴파일 또는 실행 실패', + '着色器资源缺失': '셰이더 리소스 누락', + '着色器预览不可用;当前显示未处理源画面': '셰이더 미리보기를 사용할 수 없어 처리되지 않은 소스를 표시합니다', + '着色器预览已回退为 CSS 近似;当前画面不代表导出效果': '셰이더 미리보기가 CSS 근사치로 대체되었습니다. 현재 화면은 내보내기 결과와 다를 수 있습니다', + '素材类型不支持纹理预览': '이 미디어 유형은 텍스처 미리보기를 지원하지 않습니다', + '裁切上边(拖入则遮住上方)': '위쪽 가장자리 자르기(안쪽으로 드래그하면 위쪽을 가림)', + '裁切下边(拖入则遮住下方)': '아래쪽 가장자리 자르기(안쪽으로 드래그하면 아래쪽을 가림)', + '裁切右边(拖入则遮住右侧)': '오른쪽 가장자리 자르기(안쪽으로 드래그하면 오른쪽을 가림)', + '裁切左边(拖入则遮住左侧)': '왼쪽 가장자리 자르기(안쪽으로 드래그하면 왼쪽을 가림)', + '资源尚未就绪': '리소스가 아직 준비되지 않았습니다', + '转场不支持 GL': '트랜지션이 GL을 지원하지 않습니다', + '边描透明度': '테두리 불투명도', + '边框圆角': '테두리 모서리 반경', + '边框描边': '테두리 선', + '边框阴影': '테두리 그림자', + '边框颜色': '테두리 색상', + '预览画布片段变换': '미리보기 캔버스 클립 변형', +} as Record; diff --git a/src/i18n/dict/ko/coverage.verify.ts b/src/i18n/dict/ko/coverage.verify.ts new file mode 100644 index 000000000..0866eb4fe --- /dev/null +++ b/src/i18n/dict/ko/coverage.verify.ts @@ -0,0 +1,29 @@ +// Korean must cover every English UI entry and every data name, and keep the +// {placeholder} set of each entry intact — t() substitutes by name, so a dropped +// or renamed placeholder would leak a raw "{n}" into the UI. +// npx tsx src/i18n/dict/ko/coverage.verify.ts +import assert from 'node:assert/strict'; +import { EN } from '../en'; +import EN_DATA from '../en/templates-data'; +import { ZH_DATA } from '../zh'; +import { KO } from './index'; +import KO_DATA from './templates-data'; + +function placeholders(text: string): string { + return [...text.matchAll(/\{(\w+)\}/g)].map((match) => match[1]).sort().join(','); +} + +const missing = Object.keys(EN).filter((key) => !KO[key]?.trim()); +assert.deepEqual(missing, [], `Korean dictionary is missing ${missing.length} English keys:\n${missing.join('\n')}`); + +const mismatched = Object.entries(KO) + .filter(([key, korean]) => placeholders(korean) !== placeholders(EN[key] ?? key)) + .map(([key, korean]) => `${key} → ${korean}`); +assert.deepEqual(mismatched, [], `Korean placeholders differ from the source entry:\n${mismatched.join('\n')}`); + +// Data names arrive both as Chinese keys (EN_DATA) and English keys (ZH_DATA). +const dataKeys = [...Object.keys(EN_DATA), ...Object.keys(ZH_DATA)]; +const missingData = dataKeys.filter((key) => !KO_DATA[key]?.trim()); +assert.deepEqual(missingData, [], `Korean data dictionary is missing ${missingData.length} names:\n${missingData.join('\n')}`); + +console.log(`ko coverage.verify: ${Object.keys(EN).length} UI keys and ${dataKeys.length} data names covered`); diff --git a/src/i18n/dict/ko/editor.ts b/src/i18n/dict/ko/editor.ts new file mode 100644 index 000000000..47dde30cb --- /dev/null +++ b/src/i18n/dict/ko/editor.ts @@ -0,0 +1,29 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '冲击': '펀치', + '推进拉回': '푸시 앤 풀백', + '慢推': '느린 푸시', + '瞬时': '즉시', + '拉远': '줌 아웃', + '缓入推近': '이즈 인 푸시', + '弹性推近': '바운스 푸시', + '快切推近': '스냅 푸시', + '心跳脉冲': '펄스', + '甩入推近': '휩 인 푸시', + '推进转场': '예비 동작 줌', + '白色划线转场': '클린 라인 와이프', + '叠化转场': '크로스 디졸브', + '闪黑转场': '검은색으로 디졸브', + '闪白转场': '플래시', + '冲击抖动转场': '임팩트 흔들림', + '叠加转场': '루마 블렌드', + '光溶转场': '유기적 디졸브', + '翻页转场': '페이지 말림', + '焦点转场': '랙 포커스', + '柔化擦除转场': '소프트 와이프', + '甩镜转场': '휩 팬', + '圆形擦除转场': '원형 와이프', + '人声分离失败,未修改任何片段。': '음성 분리에 실패했습니다. 수정된 클립은 없습니다.', + '响度分析失败,未修改任何片段。': '음량 분석에 실패했습니다. 수정된 클립은 없습니다.', + '所选片段的源素材已变化,旧的人声分离结果已丢弃。请重试。': '소스 미디어가 변경되어 이전 음성 분리 결과를 폐기했습니다. 다시 시도하세요.', +} as Record; diff --git a/src/i18n/dict/ko/exportPanel.ts b/src/i18n/dict/ko/exportPanel.ts new file mode 100644 index 000000000..d8d7bec6f --- /dev/null +++ b/src/i18n/dict/ko/exportPanel.ts @@ -0,0 +1,199 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '导出设置': '내보내기 설정', + '发布工作台': '딜리버리 스튜디오', + '关闭': '닫기', + '视频': '비디오', + '音频': '오디오', + 'MG动画': '모션 그래픽', + '字幕': '자막', + '成片': '완성 영상', + '音轨': '오디오 믹스', + '动态图层': '모션 레이어', + '字幕稿': '자막 파일', + '剪辑工程': '편집 프로젝트', + '剪映草稿': 'JianYing 초안', + '导出剪映草稿': 'JianYing 초안 내보내기', + '输出类型': '출력 유형', + '本机渲染': '로컬 렌더링', + '本机自适应': '로컬 자동 선택', + '正在检测本机': '이 기기 확인 중', + 'WebCodecs · 硬件加速': 'WebCodecs · 하드웨어 가속', + 'WebCodecs · 本机编码': 'WebCodecs · 로컬 인코딩', + '本机兼容渲染': '로컬 호환 렌더러', + '保存到': '저장 위치', + '浏览器下载目录': '브라우저 다운로드 폴더', + '保存位置由浏览器下载设置决定': '저장 위치는 브라우저 다운로드 설정을 따릅니다', + '导出目录无效': '내보내기 대상이 올바르지 않습니다.', + '导出目录授权无效': '내보내기 대상 권한이 올바르지 않습니다.', + '当前浏览器不支持选择导出目录,请使用 Chrome、Edge 或桌面版': '이 브라우저는 내보내기 폴더 선택을 지원하지 않습니다. Chrome, Edge 또는 데스크톱 앱을 사용하세요.', + '导出文件名无效': '내보내기 파일 이름이 올바르지 않습니다.', + '没有所选导出目录的写入权限,请重新选择目录': '선택한 내보내기 폴더에 더 이상 쓸 수 없습니다. 폴더를 다시 선택하세요.', + '所选导出目录不可用,请重新选择目录': '선택한 내보내기 폴더를 사용할 수 없습니다. 폴더를 다시 선택하세요.', + '导出文件过大,无法写入所选目录': '내보낸 파일이 너무 커서 선택한 폴더에 쓸 수 없습니다.', + '浏览器返回了无效的导出目录': '브라우저가 올바르지 않은 내보내기 폴더를 반환했습니다.', + '导出来源地址无效': '내보내기 소스 URL이 올바르지 않습니다.', + '导出来源地址不受支持': '지원되지 않는 내보내기 소스 URL입니다.', + '写入导出目录失败(HTTP {status})': '내보내기 폴더에 쓰지 못했습니다(HTTP {status}).', + '导出文件内容无效': '내보낸 파일의 내용이 올바르지 않습니다.', + '读取导出文件失败(HTTP {status})': '내보낸 파일을 읽지 못했습니다(HTTP {status}).', + '选择导出目录失败': '내보내기 폴더를 선택하지 못했습니다.', + '文件将直接写入所选文件夹': '파일이 선택한 폴더에 바로 저장됩니다', + '正在选择…': '선택 중…', + '选择…': '선택…', + '更改…': '변경…', + '编码': '코덱', + '格式 / 编码': '형식 / 코덱', + '画质策略': '화질 정책', + '均衡': '균형', + '画质优先': '화질 우선', + '母带': '중간 마스터', + 'ProRes 422 HQ 母带 (.mov)': 'ProRes 422 HQ 중간 마스터(.mov)', + 'ProRes 母带体积较大,仅本机渲染;适合调色或交给达芬奇继续剪。网发请用 H.264。': 'ProRes 중간 마스터 파일은 용량이 크며 로컬 렌더링만 지원합니다. 색 보정이나 DaVinci Resolve로 넘길 때 사용하고, 웹 배포용으로는 H.264를 사용하세요.', + 'ProRes 母带仅支持本机渲染': 'ProRes 중간 마스터는 로컬 렌더링만 지원합니다', + '高清优先预览;导出默认高码率,不主动压缩导入素材。': '고화질 미리보기 우선. 내보내기는 기본적으로 높은 비트레이트를 사용하며 가져온 미디어를 용량 기준으로 압축하지 않습니다.', + '平衡流畅与体积;预览可用轻量副本,导出默认自动码率。': '부드러움과 용량의 균형. 미리보기에 경량 사본을 사용할 수 있으며 내보내기는 자동 비트레이트를 사용합니다.', + '分辨率': '해상도', + '帧率': '프레임 레이트', + '码率': '비트레이트', + '自动': '자동', + '小文件': '작은 파일', + '推荐': '권장', + '高质量': '고화질', + '自定义': '사용자 지정', + '码率模式': '비트레이트 모드', + '自定义码率': '사용자 지정 비트레이트', + '预计视频码率:{value} Mbps': '예상 비디오 비트레이트: {value} Mbps', + '导出后自动质量检查': '내보낸 후 자동으로 품질 검사', + '检查画面、声音、剪辑点和字幕安全区;临时失败最多自动复检 3 轮。': '영상, 오디오, 편집점, 자막 안전 영역을 검사합니다. 일시적인 실패는 최대 3회까지 다시 시도합니다.', + '格式': '형식', + '目标软件': '대상 앱', + '纯文本 (.txt)': '일반 텍스트(.txt)', + '达芬奇': 'DaVinci Resolve', + 'MP3 音轨': 'MP3 오디오 믹스', + '提取时间线中的完整混音,视频画面不会写入文件。': '비디오 프레임 없이 타임라인의 전체 믹스를 추출합니다.', + '{n} 个动态图层': '모션 레이어 {n}개', + '没有可导出的动态图层': '내보낼 모션 레이어가 없습니다', + '逐个生成带透明通道的 ProRes 4444 MOV,方便在其他工程中复用。': '레이어마다 알파 채널이 포함된 ProRes 4444 MOV를 생성하여 다른 프로젝트에서 재사용할 수 있습니다.', + '先在时间线上添加 MG 动画,再从这里生成透明素材。': '투명 소스를 생성하려면 먼저 타임라인에 모션 그래픽을 추가하세요.', + '字幕轨尚未开启': '자막 트랙이 꺼져 있습니다', + '开启字幕并确认内容后,即可下载字幕稿。': '자막을 켜고 내용을 확인하면 자막 파일을 다운로드할 수 있습니다.', + '可继续编辑的工程': '편집 가능한 프로젝트', + '生成带轨道与素材引用的 FCPXML,交给 Premiere Pro 或达芬奇继续制作。': '트랙과 미디어 참조가 포함된 FCPXML을 생성하여 Premiere Pro 또는 DaVinci Resolve에서 계속 작업할 수 있습니다.', + '当前 FCPXML 会保留背景参数,但不生成图层': 'FCPXML에는 배경 매개변수가 유지되지만 레이어는 생성되지 않습니다', + 'OpenChatCut 会把 {n} 个片段的背景填充开关与百分比写入 FCPXML 元数据,但目标剪辑软件不会据此还原模糊图层;如需完全一致,请同时导出成片。': 'OpenChatCut은 클립 {n}개의 배경 채우기 설정과 비율을 FCPXML 메타데이터에 기록하지만, 대상 편집 프로그램은 이를 바탕으로 블러 레이어를 재구성하지 않습니다. 화면을 정확히 일치시키려면 완성 영상도 함께 내보내세요.', + '同时打包动态图层': '모션 레이어 함께 묶기', + '额外生成带透明通道的 ProRes 4444 MOV。': '알파 채널이 포함된 ProRes 4444 MOV 파일도 생성합니다.', + '导出为 MP3 音频,视频轨道将被忽略。': 'MP3 오디오로 내보냅니다. 비디오 트랙은 무시됩니다.', + '{n} 个MG动画 · ProRes 4444': 'MG 애니메이션 {n}개 · ProRes 4444', + '每个元素都会导出为独立的 .mov 文件,并保留透明通道。': '각 요소는 알파 채널이 유지된 개별 .mov 파일로 내보내집니다.', + '时间线上没有 MG动画 片段。': '타임라인에 MG 애니메이션 클립이 없습니다.', + '请先开启字幕——字幕将从当前字幕轨道导出。': '먼저 자막을 켜세요. 자막은 현재 자막 트랙에서 내보내집니다.', + '将时间线导出到剪辑软件中继续编辑。': '타임라인을 편집 프로그램(NLE)으로 내보내 계속 편집합니다.', + '包含 MG动画': 'MG 애니메이션 포함', + '把每个 MG动画渲染成带 alpha 的 ProRes 4444 .mov,并和 XML 一起下载。': '각 MG 애니메이션을 알파 채널이 포함된 ProRes 4444 .mov로 렌더링하여 XML과 함께 다운로드합니다.', + '导入后,请在剪辑软件中指向原始素材所在文件夹,以重新链接离线片段。': '가져온 후 편집 프로그램에서 원본 미디어 폴더를 지정하여 오프라인 클립을 다시 연결하세요.', + '渲染 MG {i}/{n} · {name}': 'MG 렌더링 중 {i}/{n} · {name}', + '正在渲染第 {i}/{n} 个动态图层': '모션 레이어 렌더링 중 {i}/{n}', + '导出中…': '내보내는 중…', + '准备导出…': '내보내기 준비 중…', + '正在下载…': '다운로드 중…', + '导出': '내보내기', + '导出成片': '영상 내보내기', + '提取音轨': '오디오 추출', + '导出动态图层': '모션 레이어 내보내기', + '下载字幕': '자막 다운로드', + '生成剪辑工程': '편집 프로젝트 생성', + '即将生成': '출력', + '输出规格': '출력 설정', + '已生成': '생성됨', + '等待渲染': '렌더링 대기 중', + '已有其他导出任务正在运行,当前任务将在其完成后自动开始': '다른 내보내기 작업이 실행 중입니다. 해당 작업이 끝나면 이 작업이 자동으로 시작됩니다.', + '准备素材': '미디어 준비 중', + '正在渲染': '렌더링 중', + '浏览器渲染中…': '브라우저에서 렌더링 중…', + 'WebCodecs 浏览器加速': 'WebCodecs 브라우저 가속', + '切换兼容渲染…': '호환 렌더러로 전환 중…', + '浏览器快导不可用:{reason},已切换兼容渲染': '브라우저 빠른 내보내기를 사용할 수 없습니다: {reason}. 호환 렌더링으로 전환했습니다.', + '历史实测显示浏览器路径更快': '이전 로컬 내보내기에서 브라우저 경로가 더 빠른 것으로 측정되었습니다', + '历史实测显示本机渲染器更快': '이전 로컬 내보내기에서 네이티브 렌더러가 더 빠른 것으로 측정되었습니다', + '浏览器确认支持硬件高效编码': '브라우저가 전력 효율적인 하드웨어 인코딩을 지원합니다', + '检测到本机硬件编码器': '작동하는 로컬 하드웨어 인코더가 감지되었습니다', + '浏览器兼容且无需额外渲染进程': '호환 브라우저 경로는 별도의 렌더링 프로세스가 필요하지 않습니다', + '本机渲染失败:{reason},已切换 WebCodecs': '로컬 렌더링 실패: {reason}. WebCodecs로 전환했습니다.', + '正在保存…': '저장 중…', + '正在写入所选位置': '선택한 위치에 쓰는 중', + '包含 WebGL 片段特效': 'WebGL 클립 효과 포함', + '包含 WebGL 转场': 'WebGL 트랜지션 포함', + '浏览器快导暂不转换时间线帧率': '브라우저 빠른 내보내기는 아직 타임라인 프레임 레이트를 변환할 수 없습니다', + '浏览器编码器不支持此导出规格': '브라우저의 비디오 인코더로는 이 내보내기 설정을 처리할 수 없습니다', + '浏览器快导未能完成': '브라우저 내보내기가 완료되지 않았습니다', + '当前浏览器不支持此编码配置': '이 브라우저는 선택한 인코딩 설정을 지원하지 않습니다', + '浏览器快导失败': '브라우저 빠른 내보내기 실패', + '已取消导出': '내보내기가 취소되었습니다', + '正在封装': '파일 마무리 중', + '正在质量检查': '품질 검사 중', + '正在下载': '다운로드 중', + '导出完成': '내보내기 완료', + '完成': '완료', + '重试': '재시도', + '已渲染 {done}/{total} 帧': '{done}/{total} 프레임 렌더링됨', + '已用 {time}': '경과 시간 {time}', + '预计剩余 {time}': '약 {time} 남음', + '文件大小 {size}': '파일 크기 {size}', + '兼容渲染': '호환 렌더링', + '浏览器加速': '브라우저 가속', + '检测浏览器': '브라우저 확인 중', + '浏览器优先': '브라우저 우선', + '{n} 个透明 MOV 文件': '투명 MOV 파일 {n}개', + '{n} 个动态图层渲染失败,XML 已保留占位': '모션 레이어 {n}개를 렌더링하지 못했습니다. XML에는 자리 표시자가 유지됩니다', + '导出失败 ({status})': '내보내기 실패({status})', + '无法读取导出进度 ({status})': '내보내기 진행 상황을 읽을 수 없습니다({status})', + '导出完成,但没有可下载的文件': '내보내기는 완료되었지만 다운로드할 파일이 없습니다', + '下载导出文件失败 ({status})': '내보낸 파일을 다운로드할 수 없습니다({status})', + '正在检查导出质量…': '내보내기 품질 검사 중…', + '检查画面、声音、剪辑点和字幕安全区,失败时最多自动复检 3 轮': '영상, 오디오, 편집점, 자막 안전 영역을 검사하는 중입니다. 일시적인 실패는 최대 3회까지 다시 시도합니다', + '正在自动检查成片…': '내보낸 영상을 자동으로 검사하는 중…', + '自动质量检查未完成': '자동 품질 검사가 완료되지 않았습니다', + '成片仍会正常下载;你可以稍后重新导出复检。': '영상은 정상적으로 다운로드됩니다. 나중에 다시 내보내 재검사할 수 있습니다.', + '自动质量检查通过': '자동 품질 검사 통과', + '自动质量检查发现问题': '자동 품질 검사에서 문제가 발견되었습니다', + '{errors} 个错误 · {warnings} 个警告': '오류 {errors}개 · 경고 {warnings}개', + '第 {n} 轮检查完成': '{n}번째 검사 완료', + '查看剪辑点前后对照图': '편집점 전후 비교 보기', + '剪辑点前后画面对照': '편집점 전후 프레임 비교', + '成片缺少视频轨': '내보낸 파일에 비디오 스트림이 없습니다', + '成片时长与时间线不一致': '내보낸 영상의 길이가 타임라인과 일치하지 않습니다', + '成片分辨率与导出设置不一致': '내보낸 영상의 해상도가 설정과 일치하지 않습니다', + '成片帧率与导出设置不一致': '내보낸 영상의 프레임 레이트가 설정과 일치하지 않습니다', + '成片缺少应有的音频轨': '내보낸 영상에 있어야 할 오디오 스트림이 없습니다', + '检测到异常黑帧': '예상치 못한 검은 프레임이 감지되었습니다', + '检测到较长静帧': '긴 정지 화면 구간이 감지되었습니다', + '检测到较长静音': '긴 무음 구간이 감지되었습니다', + '音频峰值接近削波': '오디오 피크가 클리핑에 가깝습니다', + '字幕越出横向安全区': '자막이 가로 안전 영역을 벗어났습니다', + '字幕越出纵向安全区': '자막이 세로 안전 영역을 벗어났습니다', + '导出失败': '내보내기 실패', + '请先开启字幕': '먼저 자막을 켜세요', + '当前字幕轨没有可导出的内容': '현재 자막 트랙에 내보낼 내용이 없습니다', + '后台导出': '백그라운드 내보내기', + '后台导出任务': '백그라운드 내보내기 작업', + '导出素材未就绪:{n} 个素材仍是未完成的上传占位(可能因磁盘满或断网上传失败),请删除或重新导入这些素材:{list}': '내보낼 미디어가 준비되지 않았습니다: {n}개 미디어가 아직 완료되지 않은 업로드 자리 표시자입니다(디스크 공간 부족 또는 네트워크 끊김으로 업로드가 실패했을 수 있습니다). 해당 미디어를 삭제하거나 다시 가져오세요: {list}', + '正在恢复导出…': '내보내기 재개 중…', + '此导出正在由另一个窗口恢复,请稍后重试': '다른 창에서 이 내보내기를 복구하고 있습니다. 잠시 후 다시 시도하세요.', + '剪映草稿导出失败': 'JianYing 초안을 만들지 못했습니다', + '生成剪映草稿': 'JianYing 초안 만들기', + '把时间线上的视频、音轨与字幕写入本地草稿库,用剪映或 CapCut 打开即可继续剪辑。': '타임라인의 비디오, 오디오, 자막을 로컬 초안에 기록합니다. JianYing 또는 CapCut에서 열어 계속 편집하세요.', + '草稿名称': '초안 이름', + '目标草稿库': '대상 초안 저장소', + 'CapCut 草稿库': 'CapCut 저장소', + '剪映草稿库': 'JianYing 저장소', + '剪映 6.0 起草稿文件已加密,本工具生成明文草稿,建议使用剪映 5.9.0 或更早版本打开;CapCut 国际版不受此限制。': 'JianYing 6.0부터 초안 파일이 암호화되며 이 도구는 평문 초안을 생성하므로 JianYing 5.9.0 이하 버전을 사용하세요. 글로벌 버전 CapCut은 영향을 받지 않습니다.', + '草稿已生成': '초안이 생성되었습니다', + '{videos} 个视频 · {audios} 个音轨 · {captions} 条字幕': '비디오 {videos}개 · 오디오 트랙 {audios}개 · 자막 {captions}개', + '导出到剪映': 'JianYing으로 내보내기', + '正在生成草稿…': '초안 생성 중…', + '自定义路径': '사용자 지정 경로', + '草稿库路径': '초안 저장소 경로', + '切换 WebCodecs…': 'WebCodecs로 전환…', +} as Record; diff --git a/src/i18n/dict/ko/fx.ts b/src/i18n/dict/ko/fx.ts new file mode 100644 index 000000000..c7ac10ff5 --- /dev/null +++ b/src/i18n/dict/ko/fx.ts @@ -0,0 +1,144 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '黑底叠加': '루마 키', + '局部马赛克': '부분 모자이크', + '放大镜': '돋보기', + '方形蒙版': '사각형 마스크', + '圆形蒙版': '원형 마스크', + 'CRT 复古显像管': '레트로 CRT', + 'ASCII 字符雨': 'ASCII 레인', + '手持运镜': '핸드헬드 카메라', + '移轴镜头': '틸트 시프트', + '色度键/绿幕': '크로마 키 / 그린 스크린', + '暗角': '비네트', + '胶片颗粒': '필름 그레인', + 'RGB 分离': 'RGB 분리', + '故障闪烁': '글리치', + '光晕 Bloom': '블룸', + '像素化': '픽셀화', + '色调分离': '포스터화', + '双色调': '듀오톤', + '镜像对称': '미러', + '鱼眼': '어안', + '万花筒': '만화경', + '边缘发光': '가장자리 글로우', + '柔焦模糊': '소프트 블러', + '漏光': '라이트 릭', + '棕褐色': '세피아', + '反色': '반전', + '半色调网点': '하프톤', + '运动模糊': '모션 블러', + '把黑色背景变透明、保留亮部,像 Screen 混合——叠加火焰/烟雾/漏光/粒子等黑底素材。': '밝은 부분은 유지하면서 검은 배경을 투명하게 만듭니다(스크린 블렌드와 유사). 검은 배경에서 촬영한 불/연기/라이트 릭/파티클 소스를 겹칠 때 사용합니다.', + '对矩形区域打码,可调位置/尺寸/块大小/羽化。': '사각형 영역을 픽셀화합니다. 위치/크기/블록 크기/페더를 조정할 수 있습니다.', + '在指定圆心加一个放大镜头,可调半径/倍率/边框。': '지정한 중심에 돋보기 렌즈를 추가합니다. 반지름/배율/테두리를 조정할 수 있습니다.', + '把画面裁成圆角矩形,可调位置/尺寸/圆角/羽化/反转。': '화면을 둥근 사각형으로 자릅니다. 위치/크기/모서리 반경/페더/반전을 조정할 수 있습니다.', + '把画面裁成柔边圆形,可调圆心/半径/羽化/反转。': '화면을 가장자리가 부드러운 원형으로 자릅니다. 중심/반지름/페더/반전을 조정할 수 있습니다.', + '模拟 CRT 显像管:扫描线/屏幕弯曲/RGB 偏移/噪点/暗角。动画。': '스캔라인, 화면 굴곡, RGB 시프트, 노이즈, 비네트로 CRT 브라운관을 시뮬레이션합니다. 애니메이션 효과입니다.', + '在视频亮部生成蓝色发光 ASCII 字符雨。': '영상의 밝은 부분 위로 파랗게 빛나는 ASCII 레인을 생성합니다.', + 'fbm 噪声抖动 + 旋转/缩放/呼吸,模拟手持相机运动。动画。': 'fbm 노이즈 흔들림과 회전/확대·축소/호흡 효과로 핸드헬드 카메라 움직임을 시뮬레이션합니다. 애니메이션 효과입니다.', + '模拟移轴镜头:一条焦点带清晰、上下渐糊 + 饱和度/暗角。两遍可分离高斯模糊。': '선명한 초점 띠의 위아래를 점점 흐리게 하고 채도와 비네트를 적용해 틸트 시프트 렌즈를 시뮬레이션합니다. 2패스 분리형 가우시안 블러를 사용합니다.', + '按键色(默认绿幕)抠除背景,可调容差/羽化/溢色抑制。': '키 색상(기본값: 그린 스크린)으로 배경을 제거합니다. 유사도/페더/스필 억제를 조정할 수 있습니다.', + '四周压暗,突出中心主体。可调强度/柔和/圆度。': '가장자리를 어둡게 해 중앙 피사체를 강조합니다. 강도/부드러움/원형도를 조정할 수 있습니다.', + '动态胶片噪点质感。动画。': '움직이는 필름 그레인 질감을 표현하는 애니메이션 효과입니다.', + '通道错位色差,赛博/故障感。': '채널 오프셋에 따른 색수차로 사이버/글리치 느낌을 냅니다.', + '横向切片错位 + 偶发反色/色差。动画。': '가로 슬라이스를 어긋나게 하고 간헐적으로 색 반전과 색 번짐을 적용하는 애니메이션 효과입니다.', + '亮部溢光,电影高光感。': '하이라이트 블룸으로 영화 같은 광채를 줍니다.', + '整帧像素块风格化。': '전체 화면에 픽셀 블록 스타일을 적용합니다.', + '减少色阶,插画/海报感。': '색 단계를 줄여 일러스트/포스터 느낌을 냅니다.', + '按亮度映射阴影色与高光色。': '밝기에 따라 섀도와 하이라이트를 두 가지 색으로 매핑합니다.', + '左右/上下镜像拼贴。mode: 0左→右 1右→左 2上→下 3下→上。': '가로/세로 방향으로 미러 타일링을 적용합니다. 모드: 0 왼쪽→오른쪽, 1 오른쪽→왼쪽, 2 위→아래, 3 아래→위', + '桶形畸变广角效果。': '배럴 왜곡으로 광각 효과를 냅니다.', + '径向分片镜像,万花筒图案。': '방사형으로 분할한 영역을 반사해 만화경 패턴을 만듭니다.', + 'Sobel 边缘检测叠加彩色描边。': 'Sobel 방식으로 감지한 가장자리에 컬러 글로우 윤곽선을 적용합니다.', + '轻量全图柔焦。': '전체 화면에 가벼운 소프트 포커스를 적용합니다.', + '胶片漏光色带,轻微呼吸动画。': '필름 빛샘을 표현하는 컬러 띠에 은은하게 강약이 변하는 애니메이션을 적용합니다.', + '经典 Sepia 复古染色。': '클래식한 세피아 색조로 빈티지 느낌을 냅니다.', + 'RGB 反相,负片/故障风格。': 'RGB 색상을 반전해 네거티브/글리치 스타일을 표현합니다.', + '印刷网点/漫画圆点风格。': '인쇄 하프톤이나 만화 망점 스타일을 적용합니다.', + '定向拖影,表现速度感。': '방향성 잔상으로 속도감을 표현합니다.', + '青橙电影感': '틸 & 오렌지', + '黑白胶片': '흑백 필름', + '暖调复古': '따뜻한 빈티지', + '冷调青蓝': '쿨 블루', + '日落暖金': '골든 선셋', + '赛博霓虹': '사이버 네온', + '漂白旁路': '블리치 바이패스', + '富士 Classic Chrome': 'Fuji Classic Chrome', + '富士人像 Pro Neg': 'Fuji 인물 Pro Neg', + '富士 Velvia 风光': 'Fuji Velvia 풍경', + '理光 GR 街拍': 'Ricoh GR 스트리트', + '柯达金 Gold': 'Kodak Gold', + '拍立得 / 一次性': '인스턴트 / 일회용', + 'CineStill 夜景': 'CineStill 야경', + 'Sony S-Log3 / S-Gamut3.Cine → Rec.709。.cube 三维查找表(Sony_Slog3_s709.cube, 33³)+ 通用 lut.frag(sampler3D,BT.709 编解码包夹)': 'Sony S-Log3 / S-Gamut3.Cine → Rec.709. 실제 .cube 3D LUT(Sony_Slog3_s709.cube, 33³) + 공용 lut.frag(sampler3D, BT.709 인코딩/디코딩으로 래핑)', + 'Canon Cinema Gamut / Canon Log 3 → Canon 709。.cube 三维查找表(CinemaGamut_CanonLog3-to-Canon709_33_Ver.1.0.cube, 33³)+ 通用 lut.frag': 'Canon Cinema Gamut / Canon Log 3 → Canon 709. 실제 .cube 3D LUT(CinemaGamut_CanonLog3-to-Canon709_33_Ver.1.0.cube, 33³) + 공용 lut.frag', + '阴影偏青、高光偏橙的好莱坞调色。': '할리우드 그레이딩: 청록색 섀도, 오렌지색 하이라이트', + '高对比黑白 + 轻微动态颗粒。': '고대비 흑백 + 은은한 움직이는 그레인', + '偏暖色温与轻度褪色,复古质感。': '따뜻한 색온도와 약한 페이드 — 빈티지 느낌', + '偏冷色温,阴影加压蓝。': '차가운 색온도와 섀도에 더한 푸른색', + '高光偏金、阴影压暖的黄昏感。': '황금빛 하이라이트와 따뜻한 섀도 — 해 질 녘 느낌', + '阴影青蓝、高光品红的霓虹科幻调。': '네온 SF 그레이딩: 청록·파란색 섀도, 마젠타 하이라이트', + '低饱和 + 抬黑的漂白旁路电影感。': '낮은 채도와 밝게 조정한 검은색 영역으로 블리치 바이패스 영화 룩을 표현합니다.', + '低饱和、柔和对比、中灰偏冷——旅行/街拍纪录片感(灵感自富士胶片模拟,非官方 LUT)。': '낮은 채도, 부드러운 대비, 차가운 중간 회색 — 여행/스트리트 다큐멘터리 느낌(Fujifilm 필름 시뮬레이션에서 영감, 공식 LUT 아님)', + '奶油肤色、粉柔高光、抬黑阴影——人像/生活感(灵感自 Portra / Pro Neg)。': '크리미한 피부 톤, 부드러운 핑크 하이라이트, 밝게 조정한 섀도로 인물/라이프스타일 느낌을 냅니다(Portra / Pro Neg에서 영감).', + '高饱和绿/蓝、通透对比——景区/自然风光(灵感自 Velvia 反转片)。': '채도 높은 초록/파랑과 선명한 대비 — 명소/자연 풍경(Velvia 슬라이드 필름에서 영감)', + '硬一点对比、冷中性灰、城市纪实——GR 随手拍感(灵感自理光街拍审美)。': '약간 강한 대비, 차가운 뉴트럴 그레이, 도시 다큐멘터리 — GR 스냅 느낌(Ricoh 스트리트 미학에서 영감)', + '暖黄绿怀旧、软对比——千禧年随手拍 / 家庭相册感(灵感自 Kodak Gold)。': '향수 어린 따뜻한 노랑·초록, 부드러운 대비 — Y2K 스냅 / 가족 앨범 느낌(Kodak Gold에서 영감)', + '软糊、绿偏、粗颗粒、暗角——拍立得与一次性相机那味。': '부드러운 흐림, 초록빛 색조, 거친 그레인, 비네트 — 인스턴트 / 일회용 카메라 감성', + '钨丝灯冷青、高光微溢——夜街/霓虹(灵感自 CineStill 800T)。': '텅스텐 조명의 차가운 시안과 약간의 하이라이트 헐레이션 — 밤거리/네온(CineStill 800T에서 영감)', + '强度': '강도', + '阈值': '임계값', + '柔和': '부드러움', + '中心 X': '중심 X', + '中心 Y': '중심 Y', + '宽度': '너비', + '高度': '높이', + '块大小': '블록 크기', + '羽化': '페더', + '半径': '반지름', + '倍率': '배율', + '边框': '테두리', + '圆角': '모서리 반경', + '反转': '반전', + '扫描线': '스캔라인', + '弯曲': '굴곡', + '噪点': '노이즈', + 'RGB 偏移': 'RGB 시프트', + '字符大小': '글자 크기', + '发光强度': '글로우', + '泛光范围': '블룸 반경', + '字符颜色': '글자 색상', + '呼吸': '호흡', + '焦点位置': '초점 위치', + '焦点带宽': '초점 폭', + '倾角': '기울기 각도', + '模糊强度': '블러 강도', + '模糊侧(0双/1上/2下)': '블러 방향(0 양쪽 / 1 위 / 2 아래)', + '饱和度': '채도', + '键色': '키 색상', + '容差': '유사도', + '溢色抑制': '스필 억제', + '圆度': '원형도', + '颗粒大小': '그레인 크기', + '偏移': '오프셋', + '切片密度': '슬라이스 밀도', + '色阶': '레벨', + '阴影色': '섀도 색상', + '高光色': '하이라이트 색상', + '轴线': '축', + '分片': '분할 수', + '模糊量': '블러 양', + '角度': '각도', + '色调': '틴트', + '网点大小': '망점 크기', + '颗粒': '그레인', + '色温': '색온도', + '褪色': '페이드', + '冷度': '차가움', + '阴影蓝': '섀도 블루', + '暖度': '따뜻함', + '冷调': '쿨 톤', + '金黄': '골든', + '偏色': '색조 편향', + '青冷': '시안', +} as Record; diff --git a/src/i18n/dict/ko/index.ts b/src/i18n/dict/ko/index.ts new file mode 100644 index 000000000..b8febd8b7 --- /dev/null +++ b/src/i18n/dict/ko/index.ts @@ -0,0 +1,22 @@ +// KO dictionary assembly, split by the same fields as dict/en. Untranslated +// entries fall back to English, then to the Chinese original. +import audio from './audio'; +import captions from './captions'; +import chat from './chat'; +import components from './components'; +import editor from './editor'; +import exportPanel from './exportPanel'; +import fx from './fx'; +import library from './library'; +import media from './media'; +import review from './review'; +import settings from './settings'; +import timeline from './timeline'; +import topbar from './topbar'; +import transcript from './transcript'; + +export const KO: Record = Object.assign( + {}, + audio, captions, chat, components, editor, exportPanel, fx, + library, media, review, settings, timeline, topbar, transcript, +); diff --git a/src/i18n/dict/ko/library.ts b/src/i18n/dict/ko/library.ts new file mode 100644 index 000000000..758770d01 --- /dev/null +++ b/src/i18n/dict/ko/library.ts @@ -0,0 +1,177 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '我的素材': '내 미디어', + '序列': '시퀀스', + '资源库': '라이브러리', + '文字稿': '전사 텍스트', + '点击把序列作为引用实例加入当前时间线;修改子序列会同步到所有实例。': '시퀀스를 클릭하면 현재 타임라인에 연결된 인스턴스로 추가됩니다. 하위 시퀀스의 변경 사항은 모든 인스턴스에 동기화됩니다.', + 'MG 动画': '모션 그래픽', + '音效': '효과음', + '音频效果': '오디오 효과', + '转场': '트랜지션', + '特效': '효과', + '缩放': '확대/축소', + '插件': '플러그인', + '扩展': '확장', + '音频': '오디오', + '音频转场 · Audio Cross Fade': '오디오 크로스페이드', + '画面转场 · Video': '비디오 전환 효과', + '交叉淡化': '크로스페이드', + '点击应用到选中音频(需同轨前一段相邻音频)。出点渐弱、入点渐强。': '클릭하면 선택한 오디오 클립에 적용됩니다(같은 트랙에 인접한 이전 오디오 클립 필요). 나가는 클립은 페이드 아웃, 들어오는 클립은 페이드 인됩니다.', + '点击应用到选中视频/音频(开箱人声隔离 · 也可拖到时间线片段)': '클릭하면 선택한 비디오/오디오에 적용됩니다(기본 제공 음성 분리 · 타임라인 클립으로 드래그해도 됨)', + '悬停预览 · 点击应用到选中画面片段(入场,需前一个相邻同轨片段)': '마우스를 올려 미리보기 · 클릭하면 선택한 화면 클립에 적용(시작 전환, 같은 트랙에 인접한 이전 클립 필요)', + '悬停预览 · 点击应用到选中视频/图片': '마우스를 올려 미리보기 · 클릭하면 선택한 비디오/이미지에 적용', + '悬停预览 · 点击应用到选中片段(默认 1.5×,属性可细调)': '마우스를 올려 미리보기 · 클릭하면 선택한 클립에 적용(기본값 1.5×, 속성에서 세부 조정)', + '悬停预览 · 点击应用到选中视频/图片(强度可在属性细调)': '마우스를 올려 미리보기 · 클릭하면 선택한 비디오/이미지에 적용(속성에서 강도 조정)', + '「{main} · {sub}」内容待接入。': '‘{main} · {sub}’은(는) 아직 연결되지 않았습니다.', + '人声隔离只能用在视频 / 音频片段上': '음성 분리는 비디오 / 오디오 클립에서만 사용할 수 있습니다', + '人声隔离失败': '음성 분리 실패', + '人声隔离处理中…': '음성 분리 중…', + '人声隔离已应用': '음성 분리가 적용되었습니다', + '已清除人声隔离': '음성 분리가 해제되었습니다', + '未知音频效果:{id}': '알 수 없는 오디오 효과: {id}', + '人声隔离(轻)': '음성 분리(약)', + '人声隔离(强)': '음성 분리(강)', + '开箱 ffmpeg 频谱降噪 · 强度 70': '기본 제공 ffmpeg 스펙트럼 노이즈 제거 · 강도 70', + '轻度降噪 · 干净麦 · 强度 35': '약한 노이즈 제거 · 깨끗한 마이크 · 강도 35', + '轻': '약', + '强力降噪 · 嘈杂环境 · 强度 90': '강한 노이즈 제거 · 시끄러운 환경 · 강도 90', + '强': '강', + ' · 也可拖到时间线片段上': ' · 타임라인 클립으로 드래그해도 됩니다', + '(先在时间线选中,或直接拖到片段上)': ' (먼저 타임라인에서 클립을 선택하거나 클립으로 바로 드래그하세요)', + '点击应用 / 拖到时间线:{name}': '클릭하여 적용 / 타임라인으로 드래그: {name}', + '拖到时间线片段:{name}': '타임라인 클립으로 드래그: {name}', + '预览:{name}(选中片段后可应用)': '미리보기: {name}(클립을 선택하면 적용 가능)', + '应用到选中片段:{name}': '선택한 클립에 적용: {name}', + '拖到时间线:{name}': '타임라인으로 드래그: {name}', + '收藏': '즐겨찾기', + '最近': '최근', + '热门': '인기', + '行动号召': '행동 유도', + '数据可视化': '데이터 시각화', + '信息图表': '인포그래픽', + '下三分之一字幕': '로어 서드', + '引用卡片': '인용 카드', + '社交界面': '소셜 UI', + '出镜叠加': '토킹헤드 오버레이', + '文字特效': '텍스트 효과', + '标题卡片': '타이틀 카드', + '社交媒体': '소셜 미디어', + '竖屏自媒体': '세로 / 쇼츠', + '口播场景': '토킹헤드 장면', + '未分类': '미분류', + '还没有收藏的模板。将鼠标移到卡片上点 ★ 收藏。': '즐겨찾기한 템플릿이 없습니다. 카드에 마우스를 올리고 ★를 클릭해 즐겨찾기에 추가하세요.', + '还没有最近使用的模板。点卡片或拖到时间线后会出现在这里。': '최근 사용한 템플릿이 없습니다. 카드를 클릭하거나 타임라인으로 드래그하면 여기에 표시됩니다.', + '点击或拖到时间线:{name}': '클릭하거나 타임라인으로 드래그: {name}', + '取消收藏': '즐겨찾기 해제', + '更多操作': '추가 작업', + '添加到时间线': '타임라인에 추가', + '用 AI 生成': 'AI로 생성', + '确认删除': '삭제 확인', + '取消': '취소', + '删除': '삭제', + '从资源库列表移除(本地隐藏);时间线已用片段不受影响': '라이브러리 목록에서 제거(로컬에서 숨김). 타임라인에 이미 있는 클립에는 영향을 주지 않습니다', + '搜索音效': '효과음 검색', + '清除': '지우기', + '音效分组': '효과음 그룹', + '此分类下暂无音效': '이 그룹에 효과음이 없습니다', + '(与「{query}」不匹配)': ' (‘{query}’와(과) 일치하는 항목 없음)', + '音效列表': '효과음 목록', + '{desc} · 可拖到时间线音轨': '{desc} · 타임라인 오디오 트랙으로 드래그 가능', + '暂停 {name}': '{name} 일시 정지', + '试听 {name}': '{name} 미리 듣기', + '添加到时间线:{name}': '타임라인에 추가: {name}', + '添加 {name}': '{name} 추가', + '单击试听 · 双击/点 + 或拖到时间线音轨 · 共 {n} 个音效': '클릭하여 미리 듣기 · 더블클릭 / + / 오디오 트랙으로 드래그 · 효과음 총 {n}개', + '扩展中心': '확장 센터', + '发现': '둘러보기', + '已安装': '설치됨', + '创作': '만들기', + '全部': '전체', + '发现、管理并分享创意扩展包': '크리에이티브 확장 팩을 찾고, 관리하고, 공유하세요', + '收起安装': '설치 영역 접기', + '返回资源库': '라이브러리로 돌아가기', + '仅安装你信任的扩展包;安装前会校验格式并真实编译其中的 MG 与 Shader。': '신뢰할 수 있는 확장 팩만 설치하세요. OpenChatCut은 설치 전에 형식을 검증하고 MG와 셰이더를 컴파일합니다.', + '扩展包 JSON URL…': '확장 팩 JSON URL…', + '从 URL 安装': 'URL에서 설치', + '选择文件': '파일 선택', + '搜索扩展…': '확장 검색…', + '社区作者': '커뮤니티 제작자', + '已校验': '검증됨', + '在官网查看': '웹사이트에서 보기', + '创意资源扩展包': '크리에이티브 리소스 확장 팩', + '{n} 个项目': '{n}개 항목', + '更新': '업데이트', + '没有匹配的扩展': '일치하는 확장이 없습니다', + '官网资源暂时不可用,正在显示上次同步内容。': '공식 리소스를 일시적으로 사용할 수 없습니다. 마지막으로 동기화된 내용을 표시합니다.', + 'URL 安装': 'URL 설치', + '本地文件': '로컬 파일', + '旧版迁移': '레거시 마이그레이션', + '停用扩展': '확장 비활성화', + '启用扩展': '확장 활성화', + '卸载扩展': '확장 제거', + '未知作者': '알 수 없는 제작자', + '已启用': '활성화됨', + '已停用': '비활성화됨', + '已停用「{name}」': '‘{name}’ 비활성화됨', + '已启用「{name}」': '‘{name}’ 활성화됨', + '已卸载「{name}」': '‘{name}’ 제거됨', + '还没有安装扩展': '아직 설치된 확장이 없습니다', + '去“发现”安装扩展,内容会自动进入对应资源分类。': '둘러보기에서 확장을 설치하세요. 콘텐츠가 해당 리소스 카테고리에 자동으로 표시됩니다.', + '创建扩展包': '확장 팩 만들기', + '把当前工程中的自定义 MG、Shader 特效和转场打包分享;接收方安装后仍会经过安全校验。': '이 프로젝트의 사용자 지정 MG, 셰이더 효과, 트랜지션을 패키지로 묶어 공유합니다. 받는 사람이 설치할 때도 전체 안전성 검사를 거칩니다.', + '确认卸载': '제거 확인', + '卸载': '제거', + '已安装「{name}」': '‘{name}’ 설치됨', + '安装失败': '설치 실패', + '插件包是一份 JSON(MG 模板 / 转场 / 特效 / LUT / 缩放曲线),安装后出现在各分类里。': '플러그인 팩은 하나의 JSON 파일(MG 템플릿 / 트랜지션 / 효과 / LUT / 줌 커브)이며, 설치하면 각 카테고리에 항목이 표시됩니다.', + '示例:': '예시: ', + '插件包 JSON 的 URL…': '플러그인 팩 JSON URL…', + '安装中…': '설치 중…', + '安装': '설치', + '选文件': '파일 선택', + '社区插件': '커뮤니티 플러그인', + '还没有安装插件': '아직 설치된 플러그인이 없습니다', + '先勾选要打包的内容': '먼저 패키지에 포함할 콘텐츠를 선택하세요', + '包 id 需为小写字母/数字/连字符(2..40 位),如 my-pack': '팩 ID는 영문 소문자/숫자/하이픈(2–40자)이어야 합니다. 예: my-pack', + '已导出 {file}({n} 条内容)——分享该文件即可让他人安装': '{file}을(를) 내보냈습니다({n}개 항목) — 이 파일을 공유하면 다른 사용자가 설치할 수 있습니다', + '导出为插件': '플러그인으로 내보내기', + '把 AI 生成的特效/转场、时间线 MG 打包分享': 'AI로 생성한 효과/트랜지션과 타임라인 MG를 패키지로 묶어 공유', + '导出扩展包': '확장 팩 내보내기', + '把 AI 生成的特效、转场和时间线 MG 打包分享': 'AI로 생성한 효과, 트랜지션, 타임라인 MG를 패키지로 묶어 공유', + '本工程暂无可导出的自定义内容。让 Agent 用 submit_shader 生成特效/转场,或往时间线加 MG 片段后再来。': '이 프로젝트에는 아직 내보낼 수 있는 사용자 지정 콘텐츠가 없습니다. 에이전트에게 submit_shader로 효과/트랜지션을 생성하도록 요청하거나, 먼저 타임라인에 MG 클립을 추가하세요.', + '包 id(my-pack)': '팩 ID(my-pack)', + '包名(可中文)': '팩 이름', + '作者(可选)': '작성자(선택 사항)', + '自定义特效 · {n}': '사용자 지정 효과 · {n}', + '自定义转场 · {n}': '사용자 지정 트랜지션 · {n}', + '时间线 MG · {n}': '타임라인 MG · {n}', + '导出 JSON': 'JSON 내보내기', + '创作扩展': '확장 만들기', + '把 Agent 生成和时间线创作保存到资源库,或导出投稿包': '에이전트 생성 콘텐츠와 타임라인 작업물을 라이브러리에 저장하거나 제출용 팩으로 내보냅니다', + '本工程暂无可保存的创作。让 Agent 生成内容,或在时间线制作 MG/缩放后再来。': '이 프로젝트에는 아직 저장할 작업물이 없습니다. 에이전트에게 콘텐츠 생성을 요청하거나, 먼저 타임라인에서 MG/줌을 만드세요.', + '自定义 LUT · {n}': '사용자 지정 LUT · {n}', + '时间线缩放 · {n}': '타임라인 줌 · {n}', + '保存中…': '저장 중…', + '保存到资源库': '라이브러리에 저장', + '导出投稿包': '제출용 팩 내보내기', + '已导出 {file}({n} 条内容)——可直接上传资源网站': '{file}을(를) 내보냈습니다({n}개 항목) — 리소스 웹사이트에 바로 업로드할 수 있습니다', + '已保存到资源库({n} 条内容),可在对应分类直接使用': '리소스 라이브러리에 저장했습니다({n}개 항목). 이제 해당 카테고리에서 사용할 수 있습니다.', + '保存失败:{message}': '저장 실패: {message}', + '技能': '스킬', + '选择创作工作流会约束 Agent 的规划与工具调用;激活后下一条消息按该工作流执行。': '크리에이티브 워크플로를 선택하면 에이전트의 계획과 도구 사용이 해당 워크플로를 따릅니다. 다음 메시지부터 적용됩니다.', + '当前:{name}': '활성: {name}', + '点击取消创作模式,回到自由创作': '클릭하면 크리에이티브 모드를 종료하고 자유 형식으로 돌아갑니다', + '提示:也可在聊天输入框用 /skill:名称 快速激活,或用「技能创作器」创建自己的技能。': '팁: 채팅 입력창에 /skill:이름을 입력해 빠르게 활성화하거나, 스킬 크리에이터로 나만의 스킬을 만드세요.', + '修改技能': '스킬 편집', + '删除技能': '스킬 삭제', + '名称': '이름', + '名称不能为空': '이름을 입력하세요', + '拖到时间线,或使用添加按钮:{name}': '타임라인으로 드래그하거나 추가 버튼을 사용하세요: {name}', + '搜索技能(名称 / 说明)': '스킬 검색(이름 / 설명)', + '正文(Markdown,含 frontmatter)': '본문(Markdown, frontmatter 포함)', + '没有匹配的技能': '일치하는 스킬이 없습니다', + '确认?': '확인할까요?', + '说明': '설명', + '还没有最近使用的模板。点卡片右上角+或拖到时间线后会出现在这里。': '아직 최근 사용한 템플릿이 없습니다. 카드의 +를 클릭하거나 타임라인으로 드래그하면 여기에 표시됩니다.', +} as Record; diff --git a/src/i18n/dict/ko/media.ts b/src/i18n/dict/ko/media.ts new file mode 100644 index 000000000..0e7cf8d39 --- /dev/null +++ b/src/i18n/dict/ko/media.ts @@ -0,0 +1,227 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '搜索素材': '미디어 검색', + '搜索': '검색', + '上传素材': '미디어 업로드', + '添加纯色': '단색 추가', + '添加纯色片段': '단색 클립 추가', + '色': '색', + '新建文件夹': '새 폴더', + '切换网格列表': '그리드/목록 보기 전환', + '切换网格/列表': '그리드/목록 전환', + '切换到列表视图': '목록 보기로 전환', + '切换到网格视图': '그리드 보기로 전환', + '素材池空白区域菜单': '미디어 풀 빈 영역 메뉴', + '素材排序': '미디어 정렬', + '排序': '정렬', + '最新导入': '최신순', + '名称 A–Z': '이름 A–Z', + '时长': '길이', + '筛选素材': '미디어 필터', + '筛选': '필터', + '全部': '전체', + '视频': '비디오', + '图片': '이미지', + '音频': '오디오', + '文档': '문서', + '其他文件': '기타 파일', + '收藏': '즐겨찾기', + '有 {n} 个素材丢失或无法加载。选择文件夹搜索,或从行内重新链接。': '미디어 {n}개가 누락되었거나 불러오지 못했습니다. 검색할 폴더를 선택하거나 각 행에서 다시 연결하세요.', + '重新链接离线素材': '오프라인 미디어 다시 연결', + '移除全部失效素材': '오프라인 미디어 모두 제거', + '本地音乐分析模型未安装,素材卡片暂不显示分析入口。在 设置 → 本地 AI 中安装「节拍」与「音乐语义」模型包后即可分析。': '로컬 음악 분석 모델이 설치되지 않아 카드에 분석 항목이 표시되지 않습니다. 설정 → 로컬 AI에서 ‘리듬’ 및 ‘음악 의미 분석’ 팩을 설치하면 분석할 수 있습니다.', + '点击重新链接': '클릭하여 다시 연결', + '单击选中,双击加入时间线,或拖到指定轨道:{name}': '클릭하여 선택, 더블클릭하여 타임라인에 추가하거나 특정 트랙으로 드래그하세요: {name}', + '单击选中,或拖到 AI 对话框:{name}': '클릭하여 선택하거나 AI 채팅으로 드래그하세요: {name}', + '重新链接文件': '파일 다시 연결', + '工程中的文件已移动或重命名。选一个文件夹按文件名批量重链,或从下方逐个重新链接。': '이 프로젝트의 파일이 이동되었거나 이름이 변경되었습니다. 폴더를 선택해 파일 이름으로 일괄 다시 연결하거나, 아래에서 미디어를 하나씩 다시 연결하세요.', + '正在按文件名匹配…': '파일 이름으로 일치 항목 찾는 중…', + '选择文件夹批量重链(按文件名匹配)': '폴더를 선택해 일괄 다시 연결(파일 이름으로 일치)', + '已从文件夹按文件名重链 {n} 个素材': '폴더에서 파일 이름으로 미디어 {n}개를 다시 연결했습니다', + '文件夹中没有与丢失素材同名的文件': '폴더에 누락된 미디어와 이름이 같은 파일이 없습니다', + '没有待重链的素材': '다시 연결할 미디어가 없습니다', + '返回上级文件夹': '상위 폴더로 돌아가기', + '上一层': '상위 폴더', + '返回上级:{name}(可拖入素材移回)': '{name}(으)로 돌아가기(미디어를 여기에 놓으면 상위 폴더로 이동)', + '重命名': '이름 바꾸기', + '重命名文件夹': '폴더 이름 변경', + '删除空文件夹': '빈 폴더 삭제', + '删除空文件夹「{name}」?': '빈 폴더 ‘{name}’을(를) 삭제할까요?', + '删除': '삭제', + '正在导入素材…': '미디어 가져오는 중…', + '清除选择': '선택 해제', + '全选': '모두 선택', + '取消全选': '모두 선택 해제', + '已选 {n}': '{n}개 선택됨', + '加到时间线': '타임라인에 추가', + '加到时间线:{name}': '타임라인에 추가: {name}', + '点击素材右上角“⋯”:图片、视频和音频可下载原文件,MG 可导出透明 MOV。': '오른쪽 위 메뉴(⋯)를 여세요. 이미지, 동영상, 오디오는 원본 파일을 다운로드하고, MG는 투명 MOV로 내보낼 수 있습니다.', + '下载原文件': '원본 다운로드', + '导出透明 MOV': '투명 MOV 내보내기', + '导出中…': '내보내는 중…', + '素材导出失败:{message}': '미디어 내보내기 실패: {message}', + 'MG 素材缺少动画代码': 'MG 미디어에 애니메이션 코드가 없습니다', + '素材地址无效': '미디어 URL이 잘못되었습니다', + '移动所选素材': '선택한 미디어 이동', + '移动到…': '이동…', + '移动到': '이동', + '移动 {name}': '{name} 이동', + '选择 {name}': '{name} 선택', + '管理 {name}': '{name} 관리', + '这个文件夹是空的': '이 폴더는 비어 있습니다', + '导入媒体或把素材拖到这里。': '미디어를 가져오거나 파일을 여기로 드래그하세요.', + '当前筛选下没有素材': '현재 필터와 일치하는 미디어가 없습니다', + '正在时间线中使用': '타임라인에서 사용 중', + '删除正在使用的素材': '사용 중인 미디어 삭제', + '此素材正在剪辑中,确定删除吗?': '이 미디어는 편집에 사용 중입니다. 삭제할까요?', + '删除「{name}」会同时从所有时间线移除对应片段。': '‘{name}’을(를) 삭제하면 모든 타임라인에서 해당 클립도 제거됩니다.', + '取消收藏': '즐겨찾기 해제', + '确认删除': '삭제 확인', + '取消': '취소', + '确定': '확인', + '关闭': '닫기', + '新文件夹名称': '새 폴더 이름', + '素材显示名称': '미디어 표시 이름', + '批量重命名素材': '미디어 일괄 이름 변경', + '批量重命名': '일괄 이름 변경', + '复制所选': '선택 항목 복사', + '粘贴副本': '사본 붙여넣기', + '副本': '사본', + '粘贴素材': '미디어 붙여넣기', + '所选素材中有正在剪辑的内容,确定删除吗?': '선택한 미디어 중 일부가 편집에 사용 중입니다. 삭제할까요?', + '确定删除所选素材吗?': '선택한 미디어를 삭제할까요?', + '将删除 {count} 个素材,并从所有时间线移除其中 {used} 个素材对应的片段。': '미디어 {count}개를 삭제하고, 그중 {used}개에 연결된 클립을 모든 타임라인에서 제거합니다.', + '将从素材池删除 {count} 个素材。': '미디어 풀에서 미디어 {count}개를 삭제합니다.', + '名称不能包含 /': '이름에 /를 포함할 수 없습니다', + '上传失败 ({status})': '업로드 실패({status})', + '视频兼容性处理失败:{error}': '동영상 호환성 처리 실패: {error}', + '不支持的文件类型(视频 / 图片 / 音频 / GIF / SVG)': '지원하지 않는 파일 형식(동영상 / 이미지 / 오디오 / GIF / SVG)', + '{verb}失败({status})': '{verb} 실패({status})', + '导出': '내보내기', + '转换': '변환', + '透明编码': '알파 인코딩', + '清理素材': '미디어 정리', + '列出所有工程都不引用的上传文件': '어떤 프로젝트에서도 참조하지 않는 업로드 파일', + '扫描中…(逐工程收集引用)': '스캔 중…(프로젝트별 참조 수집)', + '没有无主素材,盘上很干净 ✨': '사용되지 않는 미디어가 없습니다 — 디스크가 깨끗합니다 ✨', + '已顺手清掉 {n} 份孤儿工程文档(测试残留)': '사용되지 않는 프로젝트 문서 {n}개도 정리했습니다(테스트 잔여물)', + '扫描失败:{msg}': '스캔 실패: {msg}', + '已删 {ok} 个,{fail} 个失败': '{ok}개 삭제, {fail}개 실패', + '已删 {n} 个文件': '파일 {n}개 삭제됨', + '已选 {n} 个 · {size}': '{n}개 선택됨 · {size}', + '删除中…': '삭제 중…', + '删除所选': '선택 항목 삭제', + '上传中': '업로드 중', + '上传已取消': '업로드 취소됨', + '文件过大,无法上传': '파일이 너무 커서 업로드할 수 없습니다', + '手机传素材': '휴대폰에서 업로드', + '扫码后从手机选择视频、图片或音频': 'QR 코드를 스캔해 휴대폰에서 동영상, 이미지, 오디오를 선택하세요', + '正在建立局域网上传通道…': '로컬 네트워크 업로드 채널을 여는 중…', + '手机上传二维码': '휴대폰 업로드 QR 코드', + '正在生成二维码…': 'QR 코드 생성 중…', + '二维码生成失败,请复制链接': 'QR 코드를 생성하지 못했습니다. 대신 링크를 복사하세요.', + '让手机与电脑连接同一 Wi-Fi': '휴대폰과 컴퓨터를 같은 Wi-Fi에 연결하세요', + '使用手机相机扫描二维码': '휴대폰 카메라로 QR 코드를 스캔하세요', + '选择素材,上传完成后会自动进入媒体池': '미디어를 선택하세요. 업로드가 완료되면 미디어 풀에 자동으로 추가됩니다', + '局域网地址': '로컬 네트워크 주소', + '复制链接': '링크 복사', + '复制失败,请手动复制链接': '복사하지 못했습니다. 링크를 직접 복사하세요.', + '通道将在 {seconds} 秒后关闭': '{seconds}초 후 채널이 닫힙니다', + '上传通道已过期,请关闭后重试': '업로드 채널이 만료되었습니다. 닫고 다시 시도하세요.', + '已接收并导入 {n} 个素材': '미디어 파일 {n}개를 받아 가져왔습니다', + '手机上传不可用:{error}': '휴대폰 업로드를 사용할 수 없음: {error}', + 'HEIC 转换失败': 'HEIC 변환 실패', + '仅在本次会话中临时开放素材上传,不会暴露编辑器或 API 密钥。': '이 세션에서는 미디어 업로드만 임시로 허용됩니다. 편집기와 API 키는 노출되지 않습니다.', + '正在完成导入…': '가져오기 마무리 중…', + '完成': '완료', + '语义搜索': '의미 검색', + '本地语义搜索': '로컬 의미 검색', + '语义搜索暂不可用,请重试。': '의미 검색을 사용할 수 없습니다. 다시 시도하세요.', + '素材不会上传': '미디어가 이 기기 밖으로 전송되지 않습니다', + '按画面内容搜索素材': '화면 내용으로 검색', + '首次启用会下载可选模型。索引和搜索都在本机完成,不影响未启用时的编辑器。': '처음 사용할 때 선택 모델을 다운로드합니다. 인덱싱과 검색은 이 기기에서만 이루어지며, 비활성화 상태에서는 편집기에 영향을 주지 않습니다.', + '启用本地模型': '로컬 모델 활성화', + '停用本地模型': '로컬 모델 비활성화', + '正在准备本地模型…': '로컬 모델 준비 중…', + 'GPU 加速': 'GPU 가속', + 'CPU 模式': 'CPU 모드', + '例如:海边日落、城市夜景': '예: 바닷가 일몰, 도시 야경', + '正在建立索引…': '인덱스 생성 중…', + '本地索引': '로컬 인덱스', + '已处理 {done} / {total}': '{done} / {total} 처리됨', + '已索引 {done} / {total} 个可视素材': '시각 미디어 {done} / {total}개 인덱싱됨', + '索引新素材': '새 미디어 인덱싱', + '重建': '다시 빌드', + '有 {n} 个素材无法解码,已跳过': '미디어 {n}개를 디코딩할 수 없어 건너뛰었습니다', + '语义结果 {n} 个': '의미 검색 결과 {n}개', + '疑似重复素材': '중복 의심 미디어', + '采样设置': '샘플링 설정', + '索引帧采样密度,网页与桌面端通用。改动需重建索引生效。': '인덱스 프레임 샘플링 밀도입니다. 웹과 데스크톱에 모두 적용됩니다. 변경 사항을 적용하려면 인덱스를 다시 빌드하세요.', + '索引帧采样与搜索参数,网页与桌面端通用。改动索引相关项需重建索引生效。': '인덱스 프레임 샘플링 및 검색 매개변수입니다. 웹과 데스크톱에 모두 적용됩니다. 인덱싱 관련 변경 사항을 적용하려면 인덱스를 다시 빌드하세요.', + '兜底间隔(秒)': '대체 간격(초)', + '兜底最大帧数': '최대 대체 프레임 수', + '场景模式上限': '장면 인식 상한', + '搜索结果条数': '검색 결과 수', + '搜索结果相对下限': '검색 결과 상대 하한', + '疑似重复阈值': '중복 유사도 임계값', + '长视频阈值(秒)': '긴 동영상 기준(초)', + '保存': '저장', + '恢复默认': '기본값 복원', + '采样设置已保存,重建索引后生效。': '샘플링 설정을 저장했습니다. 인덱스를 다시 빌드하면 적용됩니다.', + '采样设置已恢复默认,重建索引后生效。': '샘플링 설정을 기본값으로 되돌렸습니다. 인덱스를 다시 빌드하면 적용됩니다.', + '导入文件夹…': '폴더 가져오기…', + '文件夹导入不完整:仅检查前 {n} 个文件。': '폴더를 일부만 가져왔습니다: 처음 {n}개 파일만 확인했습니다.', + '文件夹导入不完整:已跳过超出 {n} 层的内容。': '폴더를 일부만 가져왔습니다: {n}단계보다 깊은 콘텐츠는 건너뛰었습니다.', + '已跳过 {n} 个不支持的文件。': '지원하지 않는 파일 {n}개를 건너뛰었습니다.', + '文件夹中没有支持的媒体文件。': '폴더에 지원되는 미디어 파일이 없습니다.', + '文件夹中没有文件。': '폴더가 비어 있습니다.', + '监听文件夹(自动导入新素材)…': '감시 폴더(새 미디어 자동 가져오기)…', + '正在选择监听文件夹…': '감시할 폴더 선택 중…', + '停止正在准备的监听文件夹「{dir}」': '감시 폴더 ‘{dir}’ 준비 중지', + '停止监听文件夹「{dir}」': '‘{dir}’ 감시 중지', + '监听文件夹导入失败:{error}': '감시 폴더 가져오기 실패: {error}', + '监听目录中的视频尚未完成兼容性处理': '감시 폴더의 동영상이 호환성 처리가 완료되기 전에 게시되었습니다.', + '不支持导入「{name}」': '지원하지 않는 파일: ‘{name}’', + 'AI 对话框': 'AI 채팅', + '上传会话已失效,请重新导入': '업로드 세션이 만료되었습니다. 다시 가져오세요', + '上传第 {part} 个分片失败({status})': '{part}번째 파트 업로드 실패({status})', + '只能删除空文件夹,请先移出或删除其中的内容': '빈 폴더만 삭제할 수 있습니다. 먼저 폴더 안의 콘텐츠를 옮기거나 삭제하세요', + '导入素材失败,请重试': '미디어를 가져오지 못했습니다. 다시 시도하세요', + '已取消上传同名素材': '같은 이름의 미디어 업로드를 취소했습니다', + '已重链 {n} 个素材;未找到匹配的文件:{list}': '미디어 {n}개를 다시 연결했습니다. 일치하는 파일을 찾지 못함: {list}', + '打开': '열기', + '收藏夹': '즐겨찾기', + '文件夹菜单': '폴더 메뉴', + '服务器没有返回素材保存路径,请重试': '서버가 미디어 저장 경로를 반환하지 않았습니다. 다시 시도하세요', + '未找到与丢失素材匹配的文件:{list}': '누락된 미디어와 일치하는 파일이 없습니다: {list}', + '添加 {name} 到 AI 对话框': 'AI 채팅에 {name} 추가', + '添加 {name} 到时间线': '타임라인에 {name} 추가', + '添加到:': '추가 위치:', + '添加纯色背景/画布': '단색 배경/캔버스 추가', + '管理文件夹 {name}': '{name} 폴더 관리', + '素材请求失败({status})': '미디어 요청 실패({status})', + '网络连接失败,请检查网络后重试': '네트워크 연결에 실패했습니다. 네트워크를 확인한 후 다시 시도하세요', + '视频兼容性处理失败,请重试': '동영상 호환성 처리에 실패했습니다. 다시 시도하세요', + '相关文本 {n} 处': '관련 텍스트({n})', + '转写': '전사 텍스트', + '索引和搜索都在本机完成,素材不会上传,不影响未启用时的编辑器。': '인덱싱과 검색은 모두 이 기기에서 실행됩니다 — 미디어는 업로드되지 않으며, 활성화하기 전에는 편집기에 영향을 주지 않습니다.', + '首次使用需要下载可选模型包(约 178MB)。模型在本机运行,素材不会上传。': '처음 사용하려면 선택 모델 팩(약 178 MB)을 다운로드해야 합니다. 모델은 로컬에서 실행되며 미디어는 이 기기 밖으로 전송되지 않습니다.', + '下载并启用': '다운로드 후 활성화', + '正在下载画面语义轻量包… {n}%': '시각 의미 분석 팩 다운로드 중… {n}%', + '模型包下载失败,请到 设置 → 本地模型 重试。': '모델 팩 다운로드에 실패했습니다 — 설정 → 로컬 모델에서 다시 시도하세요.', + '转写:{name}': '전사: {name}', + '重新转写:{name}': '다시 전사: {name}', + '重新转写': '다시 전사', + '正在转写…': '전사 중…', + '已转写': '전사 완료', + '转写失败': '전사 실패', + '文字稿:{name}': '전사 텍스트: {name}', + '查看文字稿:{name}': '전사 텍스트 보기: {name}', + '查看文字稿': '전사 텍스트 보기', + '复制全文': '전체 텍스트 복사', + '已复制': '복사됨', + '上一条': '이전', + '下一条': '다음', + '暂无文字稿': '아직 전사 텍스트가 없습니다', + '素材「{name}」已存在。覆盖会同步替换已在时间线中使用的该素材。': '미디어 ‘{name}’이(가) 이미 있습니다. 덮어쓰면 타임라인에서 사용 중인 해당 미디어도 함께 교체됩니다.', +} as Record; diff --git a/src/i18n/dict/ko/review.ts b/src/i18n/dict/ko/review.ts new file mode 100644 index 000000000..ea311f1d0 --- /dev/null +++ b/src/i18n/dict/ko/review.ts @@ -0,0 +1,19 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '审阅评论': '검토 댓글', + '评论': '댓글', + '评论加载失败': '댓글을 불러오지 못했습니다', + '评论保存失败': '댓글을 저장하지 못했습니다', + '回复保存失败': '답글을 저장하지 못했습니다', + '在当前帧添加审阅评论': '현재 프레임에 검토 댓글 추가', + '绑定当前帧;可用时同时记录片段与源位置': '이 프레임에 고정되며, 가능한 경우 클립과 소스 위치도 함께 기록합니다', + '添加评论': '댓글 추가', + '还没有审阅评论': '아직 검토 댓글이 없습니다', + '片段': '클립', + '时间线': '타임라인', + '输入回复': '답글 입력', + '回复': '답글', + '重新打开': '다시 열기', + '解决': '해결', + '删除评论': '댓글 삭제', +} as Record; diff --git a/src/i18n/dict/ko/settings.ts b/src/i18n/dict/ko/settings.ts new file mode 100644 index 000000000..47cfd8110 --- /dev/null +++ b/src/i18n/dict/ko/settings.ts @@ -0,0 +1,531 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '当前版本号:{version}': '현재 버전: {version}', + '检查更新': '업데이트 확인', + '检查中…': '확인 중…', + '设置 · API 密钥': '설정 · API 키', + '关闭': '닫기', + '收起': '접기', + '展开': '펼치기', + '显示明文': '값 표시', + '第三方字体许可': '타사 글꼴 라이선스', + '保存中…': '저장 중…', + '保存': '저장', + '无法读取配置(dev 服务未就绪?)': '설정을 불러올 수 없습니다(개발 서버가 준비되지 않았나요?)', + '没有改动': '변경 사항 없음', + '保存失败 ({n})': '저장 실패 ({n})', + '有未保存改动,再按一次关闭将丢弃': '저장하지 않은 변경 사항이 있습니다 — 한 번 더 닫으면 삭제됩니다', + '密钥仅存本机': '키는 이 컴퓨터의', + '(已 gitignore),经服务端注入,': ' 파일(gitignore 적용)에만 저장되며 서버가 주입합니다 — ', + '不进浏览器。': '브라우저로는 전송되지 않습니다.', + 'Agent 模型': '에이전트 모델', + 'Agent 大脑': '에이전트 두뇌', + 'AI 生成': 'AI 생성', + '生图': '이미지', + '配音 / TTS': '음성 / TTS', + '生视频': '동영상', + '生音乐': '음악', + '素材 · 转写': '미디어 · 전사', + '在线图库': '스톡 미디어', + '转写 / 口播剪辑': '전사 / 대본 편집', + '存储': '저장소', + '增强工具': '고급 도구', + '沙箱执行': '샌드박스 실행', + '网页抓取': '웹 스크래핑', + '发布到社交平台': '소셜 게시', + 'publish_to_social · 把导出的成片发布到 TikTok、Instagram、YouTube 等平台。': 'publish_to_social · 내보낸 완성 영상을 TikTok, Instagram, YouTube 등에 게시합니다.', + '一个 Key 发布到 TikTok、Instagram、YouTube、LinkedIn、Facebook、X、Threads、Pinterest、Bluesky。先在 Upload-Post 创建一个 Profile 并连接各平台账号,再把 Profile 名称填在下面。Agent 发布前总会先预览平台、标题与视频,等你确认后才上传;YouTube 默认私密。': '키 하나로 TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest, Bluesky에 게시할 수 있습니다. Upload-Post에서 프로필을 만들고 각 플랫폼 계정을 연결한 다음 아래에 프로필 이름을 입력하세요. 에이전트는 업로드 전에 항상 플랫폼, 제목, 동영상을 미리 보여 주고 확인을 기다립니다. YouTube는 기본적으로 비공개로 게시됩니다.', + '在 Upload-Post 控制台创建、已连接社交账号的 Profile 名称。': 'Upload-Post 프로필 이름(Upload-Post 대시보드에서 생성하고 소셜 계정을 연결한 프로필)', + 'Anthropic / 兼容 API': 'Anthropic / 호환 API', + 'Anthropic / OpenAI': 'Anthropic / OpenAI', + '模型供应商': '모델 공급자', + '豆包 TTS · 火山': 'Doubao TTS · Volcano', + 'Seedance · 火山': 'Seedance · Volcano', + '可灵 Kling': 'Kling', + 'MiniMax 海螺': 'MiniMax Hailuo', + '本地磁盘': '로컬 디스크', + '选择 Fal.ai 作为默认厂商,然后选择模型。聊天中指定的模型优先于此默认值。': 'Fal.ai를 기본 공급자로 선택한 다음 모델을 선택하세요. 채팅에서 모델을 명시적으로 요청하면 이 기본값보다 우선합니다.', + '对话与工具调用的核心,未配置无法对话。': '채팅과 도구 호출의 핵심입니다 — 설정하기 전에는 채팅을 사용할 수 없습니다.', + 'submit_image · 文生图 / 图生图,任一厂商即可。': 'submit_image · 텍스트→이미지 / 이미지→이미지. 공급자 하나만 있으면 됩니다.', + 'submit_voice · 文字转配音,任一厂商即可。': 'submit_voice · 텍스트를 음성 내레이션으로 변환. 공급자 하나만 있으면 됩니다.', + 'submit_video · 文 / 图生视频,任一厂商即可。': 'submit_video · 텍스트 / 이미지→동영상. 공급자 하나만 있으면 됩니다.', + 'submit_music · 文字 / 成片生成配乐,任一厂商即可。': 'submit_music · 텍스트 또는 완성 영상으로 배경 음악 생성. 공급자 하나만 있으면 됩니다.', + 'search_stock_media · 搜索可商用图片 / 视频素材。': 'search_stock_media · 상업적으로 사용 가능한 사진 / 동영상을 검색합니다.', + 'transcribe_track · 词级字幕、清口水、删词。': 'transcribe_track · 단어 단위 자막, 군더더기 말 정리, 단어 삭제', + '素材的本地保存目录,与可选的 R2 云备份。': '미디어의 로컬 저장 디렉터리 및 선택적 R2 클라우드 백업', + 'run_code · 云端沙箱运行 ffmpeg / node / python。': 'run_code · 클라우드 샌드박스에서 ffmpeg / node / python을 실행합니다.', + 'web_browser · 抓取网页内容供 Agent 参考。': 'web_browser · 에이전트가 참고할 웹 페이지를 가져옵니다.', + '默认厂商': '기본 공급자', + '接口格式': 'API 형식', + 'Responses API(推荐)': 'Responses API(권장)', + 'Chat Completions API': 'Chat Completions API', + '模型厂商': '모델 공급자', + '模型': '모델', + '上下文窗口(tokens)': '컨텍스트 창(토큰)', + '最大输入(tokens)': '최대 입력(토큰)', + '模型能力': '모델 기능', + '最大输出(tokens)': '최대 출력(토큰)', + '工具调用': '도구 호출', + '图片输入': '이미지 입력', + '推理能力': '추론', + '继承模型目录': '모델 카탈로그 사용', + '支持': '지원', + '不支持': '지원 안 함', + '清除覆盖': '재정의 지우기', + '自定义 · 精确': '사용자 지정 · 정확', + '模型目录 · 精确': '모델 카탈로그 · 정확', + '厂商回退 · 估算': '공급자 대체값 · 추정', + '厂商回退': '공급자 대체값', + '留空会使用内置模型目录;未知模型使用保守回退值。': '비워 두면 내장 모델 카탈로그를 사용합니다. 알 수 없는 모델에는 보수적인 대체값이 적용됩니다.', + 'API Base URL': 'API Base URL', + 'API Key(gpt-image)': 'API 키(gpt-image)', + 'API Key(Nano Banana)': 'API 키(Nano Banana)', + '生图模型': '이미지 모델', + '配音模型': '음성 모델', + '音效模型': '효과음 모델', + '视频模型': '동영상 모델', + '音乐模型': '음악 모델', + '云同步': '클라우드 동기화', + 'Bucket 名': '버킷 이름', + '模板 ID(可选)': '템플릿 ID(선택)', + '转写模型': '전사 모델', + '转写语言': '전사 언어', + '说话人分离': '화자 분리', + '每次询问(默认)': '매번 묻기(기본값)', + '豆包': 'Doubao', + '可灵': 'Kling', + '{name}(未配置)': '{name}(설정 안 됨)', + '选中未配置的厂商时,Agent 会回退为先询问。': '선택한 공급자가 설정되지 않은 경우 에이전트는 먼저 묻는 방식으로 대체합니다.', + 'AssemblyAI(云端)': 'AssemblyAI(클라우드)', + 'AssemblyAI(默认)': 'AssemblyAI(기본값)', + '本地模型(免费 · 离线)': '로컬 모델(무료 · 오프라인)', + 'OpenAI(云端)': 'OpenAI(클라우드)', + 'Mistral Voxtral(云端)': 'Mistral Voxtral(클라우드)', + 'Deepgram(云端)': 'Deepgram(클라우드)', + 'Groq(云端)': 'Groq(클라우드)', + 'ElevenLabs Scribe(云端)': 'ElevenLabs Scribe(클라우드)', + 'Cartesia(云端)': 'Cartesia(클라우드)', + '中文(zh)': '중국어(zh)', + '英语(en)': '영어(en)', + '意大利语(it)': '이탈리아어(it)', + '日语(ja)': '일본어(ja)', + '韩语(ko)': '한국어(ko)', + '西班牙语(es)': '스페인어(es)', + '法语(fr)': '프랑스어(fr)', + '德语(de)': '독일어(de)', + '俄语(ru)': '러시아어(ru)', + '葡萄牙语(pt)': '포르투갈어(pt)', + '启用': '켜기', + '停用': '끄기', + '本地模型(whisper)': '로컬 모델(Whisper)', + '转写在本机完成:免费、离线、素材不出本机。模型需先下载,下载与删除在 本地模型 → 本地转写 页(点下方按钮前往)。自动选择设备优势后端:WebGPU 不可用时回退 CPU。本地转写不含说话人分离(全部归为同一位说话人)。': '전사가 이 컴퓨터에서 실행됩니다: 무료, 오프라인, 비공개. 먼저 모델을 다운로드해야 하며, 로컬 모델 → 로컬 전사 페이지에서 다운로드하거나 삭제할 수 있습니다(아래 버튼 사용). OpenChatCut은 사용 가능한 최적의 백엔드를 선택하며 WebGPU를 사용할 수 없으면 CPU로 대체합니다. 로컬 전사는 화자 분리를 지원하지 않습니다.', + '下载 / 管理本地模型': '로컬 모델 다운로드 / 관리', + 'MiniMax 同一个 Key,配置一次全能力(生图 / 配音 / 视频 / 音乐)通用。': 'MiniMax 키 하나로 모든 기능(이미지 / 음성 / 동영상 / 음악)을 사용할 수 있습니다 — 한 번만 설정하세요.', + 'Key 同时用于音效生成(submit_sound)。': '이 키는 효과음 생성(submit_sound)에도 사용됩니다.', + '按成片生成:把渲染好的视频交给 Sonilo,配乐跟着画面节奏走(可选一句风格提示,不填也行)。配乐自带授权、可商用(以条款为准);每条音轨附 license_id 留档。同一个 Key 也用于按成片生成音效(submit_sound,免版税)。': '완성 영상 기반 생성: 렌더링된 동영상을 Sonilo에 전달하면 음악이 영상의 흐름에 맞춰 생성됩니다(스타일 힌트 한 줄은 선택 사항이며 없어도 됩니다). 음악은 라이선스가 포함되어 상업적으로 사용할 수 있으며(약관 적용), 각 트랙에는 license_id 기록이 첨부됩니다. 같은 키로 영상에 맞춘 효과음(submit_sound, 로열티 프리)도 생성할 수 있습니다.', + '可直接使用 Anthropic 官方 API Key;如使用兼容服务,再修改 Base URL 和模型。': 'Anthropic 공식 API 키를 바로 사용하거나, 호환 서비스를 쓰는 경우 Base URL과 모델을 변경하세요.', + '默认使用 Claude Fable 5;自定义兼容地址时,也可填写该服务支持的模型 ID。': '기본값은 Claude Fable 5입니다. 호환 엔드포인트를 사용하는 경우 해당 서비스가 지원하는 모델 ID를 입력하세요.', + '每个厂商独立保存地址、密钥与模型。先测试连接,成功后可从接口返回的模型中选择。': '공급자마다 엔드포인트, 키, 모델이 따로 저장됩니다. 연결을 테스트한 다음 해당 API가 반환한 모델 중에서 선택하세요.', + '填写完整 API 前缀;可使用官方地址、自建网关或兼容中转。': '전체 API 접두사를 입력하세요. 공식 엔드포인트, 자체 게이트웨이 또는 호환 릴레이를 사용할 수 있습니다.', + '测试连接后可直接选择接口返回的模型,也可以手动填写模型 ID。': '테스트 후 반환된 모델을 선택하거나 모델 ID를 직접 입력하세요.', + '也可以手动填写厂商的其它模型 ID,建议列表仅为常用模型。': '이 공급자의 다른 모델 ID를 직접 입력할 수도 있습니다. 추천 목록에는 자주 쓰는 모델만 있습니다.', + '选择服务实际支持的协议;OpenAI 使用 Responses API,兼容服务使用 Chat Completions API。': '서비스가 실제로 지원하는 프로토콜을 선택하세요. OpenAI는 Responses API를, 호환 서비스는 Chat Completions를 사용합니다.', + '选择厂商后会自动使用官方 API 地址、接口格式和推荐模型,也可以在下方覆盖。': '공급자를 선택하면 공식 엔드포인트, 프로토콜, 권장 모델이 자동으로 적용되며, 아래에서 재정의할 수도 있습니다.', + '填写完整 API 前缀(可含 /v1、/v1beta/openai 等路径);切换厂商会重置地址与模型,并立即生效。': '/v1 또는 /v1beta/openai 같은 경로를 포함한 전체 API 접두사를 입력하세요. 공급자를 전환하면 Base URL과 모델이 초기화되며 즉시 적용됩니다.', + '默认值仅对内置模型准确;自定义、OpenRouter 或本地模型请填写模型实际上限(4,096–4,000,000)。': '기본값은 내장 모델에만 정확합니다. 사용자 지정, OpenRouter 또는 로컬 모델의 경우 모델의 실제 한도(4,096–4,000,000)를 입력하세요.', + '未配置时素材只存本机(「本地磁盘」页的目录)。配置后:每次上传同步写入 R2(桶保持私有,读取经本地服务回源,src 路径不变);本机缺文件时自动从云端取回。改动即时生效。R2 控制台建桶 → R2 API Token(Object Read & Write)即可拿到下面四个值。': '설정하지 않으면 미디어는 이 컴퓨터(로컬 디스크 디렉터리)에만 저장됩니다. 설정하면: 모든 업로드가 R2에도 기록되고(버킷은 비공개로 유지되며, 읽기는 로컬 서버를 거치고 src 경로는 바뀌지 않음), 로컬에 없는 파일은 클라우드에서 자동으로 가져옵니다. 변경 사항은 즉시 적용됩니다. R2 콘솔에서 버킷을 만든 다음 R2 API 토큰(Object Read & Write)을 생성하면 아래 네 가지 값을 얻을 수 있습니다.', + '停用后新上传只存本地(密钥保留、已上云文件不受影响);重新启用即恢复写穿。': '끄면 새 업로드는 로컬에만 저장됩니다(키는 유지되며 이미 클라우드에 있는 파일은 영향받지 않음). 다시 켜면 동시 기록(write-through)이 재개됩니다.', + '云端隔离 Linux 沙箱,不触碰本机文件。Agent 用它跑 run_code:ffprobe 探测素材时长 / 尺寸编码、ffmpeg 转码 / 抽帧 / 加工音视频、执行 node / python 技能脚本,结果回传后由本地工具应用到时间线。未配置只影响这些工具,剪辑与预览不受影响。': '클라우드의 격리된 Linux 샌드박스로, 로컬 파일에는 절대 접근하지 않습니다. 에이전트는 run_code에 이를 사용합니다: ffprobe로 미디어 길이 / 크기 / 코덱 확인, ffmpeg로 트랜스코딩 / 프레임 추출 / 오디오·비디오 처리, node / python 스킬 스크립트 실행. 결과가 돌아오면 로컬 도구가 타임라인에 적용합니다. 설정하지 않아도 이 도구들만 영향을 받으며 편집과 미리보기는 영향받지 않습니다.', + '默认模板不带 ffmpeg;转码 / 抽帧类任务需自建含 ffmpeg 的模板并填其 ID。': '기본 템플릿에는 ffmpeg가 없습니다. 트랜스코딩 / 프레임 추출 작업을 하려면 ffmpeg가 포함된 템플릿을 만들고 해당 ID를 입력하세요.', + '素材进入媒体池后是否立即转写。本地 Whisper 免费且在本机运行;云端付费供应商建议保持关闭或手动转写。': '미디어가 미디어 풀에 들어오자마자 전사할지 여부입니다. 로컬 Whisper는 무료이며 이 컴퓨터에서 실행됩니다. 유료 클라우드 공급자는 끄거나 수동으로 사용하는 것이 좋습니다.', + '导入后自动转写': '가져온 후 자동 전사', + '关闭(手动转写)': '끄기(수동 전사)', + '仅本地引擎(免费)': '로컬 엔진만(무료)', + '全部引擎(含云端付费)': '모든 엔진(유료 클라우드 포함)', + 'BytePlus ModelArk 同一个 Key,图生 / 视频生成通用;与「Agent 大脑」的 BytePlus 配置各自独立。': 'BytePlus ModelArk 키 하나로 이미지와 동영상 생성을 모두 사용할 수 있습니다. 에이전트 두뇌의 BytePlus 설정과는 별개입니다.', + '国内网络访问海外模型(Gemini / OpenAI / Anthropic / Mistral 等)失败时,可在此填写本地代理地址(如 http://127.0.0.1:7890)。留空则使用系统环境变量(HTTPS_PROXY / HTTP_PROXY)。生效范围:Agent 模型、AI 生成、模型下载、R2 云同步。': '네트워크에서 해외 모델 API(Gemini / OpenAI / Anthropic / Mistral 등)에 접속할 수 없는 경우 여기에 로컬 프록시 URL(예: http://127.0.0.1:7890)을 입력하세요. 비워 두면 시스템 환경 변수(HTTPS_PROXY / HTTP_PROXY)를 사용합니다. 적용 범위: 에이전트 모델, AI 생성, 모델 다운로드, R2 클라우드 동기화.', + '统一配置服务端访问海外 API 使用的代理地址。': '서버가 해외 API에 접속할 때 사용할 프록시 URL을 설정합니다.', + '网络代理': '네트워크 프록시', + '界面': '인터페이스', + '界面缩放与显示相关设置。': '인터페이스 배율 및 표시 설정', + '界面缩放': '인터페이스 배율', + '调整整个编辑器的缩放比例(80%–150%)。桌面版保存后立即生效,也可用 Ctrl/Cmd + +/- 快速调整、Ctrl/Cmd + 0 复位。浏览器版请使用浏览器自带缩放。': '편집기 전체 배율을 조정합니다(80%–150%). 데스크톱 앱에서는 저장 즉시 적용되며, Ctrl/Cmd + +/-로 빠르게 조정하고 Ctrl/Cmd + 0으로 초기화할 수 있습니다. 브라우저에서는 브라우저의 확대/축소 기능을 사용하세요.', + '本地模型': '로컬 모델', + '本地转写、节拍与音乐分析、画面语义搜索。模型按需安装,数据不出本机。': '로컬 전사, 비트/음악 분석, 시각적 의미 검색. 모델은 필요할 때 설치되며 데이터는 이 컴퓨터를 벗어나지 않습니다.', + '默认 https://api.fish.audio': '기본값 https://api.fish.audio', + '默认 https://api.inworld.ai': '기본값 https://api.inworld.ai', + '默认 https://api.sws.speechify.com': '기본값 https://api.sws.speechify.com', + '默认 https://api.wavespeed.ai': '기본값 https://api.wavespeed.ai', + '默认 https://ark.ap-southeast.bytepluses.com/api/v3': '기본값 https://ark.ap-southeast.bytepluses.com/api/v3', + 'Codex 模型': 'Codex 모델', + 'Copilot 模型': 'Copilot 모델', + 'Copilot 默认模型': 'Copilot 기본 모델', + '使用 GitHub Copilot 订阅:官方 Copilot CLI 管理登录与凭据(终端运行 copilot login),OpenChatCut 通过 Copilot SDK 直接驱动编辑工具,不会读取或显示凭据。会话状态隔离在 ~/.openchatcut/copilot,不影响你自己的 ~/.copilot。': 'GitHub Copilot 구독을 사용합니다: 공식 Copilot CLI가 로그인과 자격 증명을 관리합니다(터미널에서 `copilot login` 실행). OpenChatCut은 Copilot SDK를 통해 편집 도구를 직접 구동하며 자격 증명을 읽거나 표시하지 않습니다. 세션 상태는 ~/.openchatcut/copilot에 격리되어 사용자의 ~/.copilot에 영향을 주지 않습니다.', + '登录后可读取当前订阅可用的模型,也可以手动填写模型 ID。仅支持工具调用的模型可用于编辑。': '로그인한 후 이 구독에서 사용 가능한 모델을 불러오거나 모델 ID를 직접 입력하세요. 도구 호출을 지원하는 모델만 편집에 사용할 수 있습니다.', + 'Codex 默认模型': 'Codex 기본 모델', + '推理强度': '추론 강도', + '模型默认': '모델 기본값', + '模型默认({name})': '모델 기본값({name})', + '读取模型后显示当前模型支持的档位;留空使用该模型的默认值。': '모델을 불러오면 현재 모델이 지원하는 강도 단계가 표시됩니다. 설정하지 않으면 모델 기본값을 사용합니다.', + '使用 ChatGPT 订阅登录,由官方 Codex CLI 管理凭据、续期与退出。OpenChatCut 不会读取或显示 OAuth 凭据。': 'ChatGPT 구독으로 로그인합니다. 공식 Codex CLI가 자격 증명, 갱신, 로그아웃을 관리하며 OpenChatCut은 OAuth 자격 증명을 읽거나 표시하지 않습니다.', + '登录后可读取当前账号可用的模型,也可以手动填写模型 ID。': '로그인한 후 이 계정에서 사용 가능한 모델을 불러오거나 모델 ID를 직접 입력하세요.', + '状态未知': '상태 알 수 없음', + 'CLI 未安装': 'CLI 미설치', + '登录中': '로그인 중', + '已登录': '로그인됨', + 'API Key 模式': 'API 키 모드', + '连接异常': '연결 오류', + '未登录': '로그아웃됨', + '无法连接 Codex 服务,请确认开发服务正在运行。': 'Codex 서비스에 연결할 수 없습니다. 개발 서버가 실행 중인지 확인하세요.', + '无法启动登录,请稍后重试。': '로그인을 시작할 수 없습니다. 다시 시도하세요.', + '无法取消登录,请稍后重试。': '로그인을 취소할 수 없습니다. 다시 시도하세요.', + '无法退出登录,请稍后重试。': '로그아웃할 수 없습니다. 다시 시도하세요.', + '读取模型失败:{message}': '모델을 불러올 수 없습니다: {message}', + '无法读取 Codex 模型,请稍后重试。': 'Codex 모델을 불러올 수 없습니다. 다시 시도하세요.', + '正在检查 Codex CLI…': 'Codex CLI 확인 중…', + '正在读取本机 Codex 运行时状态。': '로컬 Codex 런타임 상태를 읽는 중입니다.', + '未检测到 Codex CLI': 'Codex CLI를 찾을 수 없습니다', + '请先安装 OpenAI Codex CLI,然后刷新状态。': 'OpenAI Codex CLI를 설치한 다음 상태를 새로 고치세요.', + '尚未登录 ChatGPT': 'ChatGPT에 로그인하지 않음', + '通过 Codex 官方登录流程连接 ChatGPT 订阅。': '공식 Codex 로그인 절차를 통해 ChatGPT 구독을 연결합니다.', + '等待 ChatGPT 授权': 'ChatGPT 승인 대기 중', + '请在登录页面完成授权,完成后会自动刷新。': '로그인 페이지에서 승인을 완료하세요. 상태가 자동으로 새로 고쳐집니다.', + '已登录 ChatGPT': 'ChatGPT에 로그인됨', + '凭据与续期均由 Codex CLI 管理。': '자격 증명과 갱신은 Codex CLI가 관리합니다.', + '版本过低': '버전이 너무 낮음', + '正在检查 Copilot CLI…': 'Copilot CLI 확인 중…', + '正在读取本机 Copilot 运行时状态。': '로컬 Copilot 런타임 상태를 읽는 중입니다.', + '未检测到 Copilot CLI': 'Copilot CLI를 찾을 수 없습니다', + '安装后重试:npm i -g @github/copilot(或 brew install copilot)。': '설치한 후 다시 시도하세요: npm i -g @github/copilot (또는 brew install copilot).', + 'Copilot CLI 版本过低': 'Copilot CLI가 오래되었습니다', + '在终端运行 copilot update 后重试。': '터미널에서 `copilot update`를 실행한 다음 다시 시도하세요.', + '尚未登录 Copilot': 'Copilot에 로그인하지 않음', + '在终端运行 copilot login 完成登录后点击刷新。': '터미널에서 `copilot login`을 실행한 다음 새로 고치세요.', + '已登录 GitHub Copilot': 'GitHub Copilot에 로그인됨', + '凭据与续期均由 Copilot CLI 管理。': '자격 증명과 갱신은 Copilot CLI가 관리합니다.', + '无法连接 Copilot': 'Copilot에 연결할 수 없음', + '请确认开发服务正在运行后重试。': '개발 서버가 실행 중인지 확인한 다음 다시 시도하세요.', + '账号': '계정', + '登录方式': '로그인 방식', + '主机': '호스트', + '无法连接 Copilot 服务,请确认开发服务正在运行。': 'Copilot 서비스에 연결할 수 없습니다. 개발 서버가 실행 중인지 확인하세요.', + '无法读取 Copilot 模型列表,请稍后重试。': 'Copilot 모델을 불러올 수 없습니다. 다시 시도하세요.', + 'Codex CLI 正在使用 API Key': 'Codex CLI가 API 키를 사용 중입니다', + '此页面仅启用 ChatGPT 订阅;API Key 请使用 OpenAI 厂商页。': '이 페이지는 ChatGPT 구독 전용입니다. API 키는 OpenAI 공급자 페이지에서 사용하세요.', + 'Codex 暂时不可用': 'Codex를 일시적으로 사용할 수 없습니다', + '请刷新后重试。': '새로 고친 후 다시 시도하세요.', + 'Codex CLI {version}': 'Codex CLI {version}', + '套餐:{plan}': '요금제: {plan}', + '请在先前打开的 Codex 登录窗口中完成授权。': '앞서 열었던 Codex 로그인 창에서 승인을 완료하세요.', + '登录地址': '로그인 URL', + '验证地址': '인증 URL', + '设备代码': '기기 코드', + '刷新中…': '새로 고치는 중…', + '刷新状态': '상태 새로 고침', + '读取中…': '불러오는 중…', + '读取模型': '모델 불러오기', + '正在退出…': '로그아웃 중…', + '退出登录': '로그아웃', + '取消登录': '로그인 취소', + '正在启动…': '시작하는 중…', + '浏览器登录': '브라우저로 로그인', + '使用设备代码': '기기 코드 사용', + '复制': '복제', + '已复制': '복사됨', + 'Codex 返回了无效的登录地址。': 'Codex가 잘못된 로그인 URL을 반환했습니다.', + 'Codex 返回了无效的验证地址。': 'Codex가 잘못된 인증 URL을 반환했습니다.', + '复制失败': '복사 실패', + '内置 Agent 可使用 Anthropic API Key,也可以在下方「Anthropic · Claude Code」页用 Claude 订阅登录(无需 API Key)。独立运行的 Claude Code 会话也可以通过「外部 Agent 接入 (MCP)」驱动 OpenChatCut。': '내장 에이전트는 Anthropic API 키를 사용하거나, 아래 ‘Anthropic · Claude Code’ 페이지에서 Claude 구독으로 로그인할 수 있습니다(API 키 불필요). 독립 실행 Claude Code 세션도 ‘외부 에이전트(MCP)’를 통해 OpenChatCut을 구동할 수 있습니다.', + '使用 Claude 订阅登录,由官方 Claude Code CLI 管理凭据、续期与退出,OpenChatCut 不会读取或显示 OAuth 凭据。在终端运行 claude auth login(或 claude setup-token 获取长期令牌)完成登录后,点击“重新检测”。': 'Claude 구독으로 로그인합니다. 공식 Claude Code CLI가 자격 증명, 갱신, 로그아웃을 관리하며 OpenChatCut은 OAuth 자격 증명을 읽거나 표시하지 않습니다. 터미널에서 claude auth login(장기 토큰이 필요하면 claude setup-token)을 실행한 다음 ‘다시 확인’을 클릭하세요.', + 'Claude Code 模型': 'Claude Code 모델', + 'Claude Code 默认模型': 'Claude Code 기본 모델', + '登录后可从可用模型中选择,也可以手动填写别名(如 sonnet / opus / haiku)。': '로그인한 후 사용 가능한 모델 중에서 선택하거나 별칭(예: sonnet / opus / haiku)을 직접 입력하세요.', + '正在检查 Claude Code CLI…': 'Claude Code CLI 확인 중…', + '正在读取本机 Claude Code 运行时状态。': '로컬 Claude Code 런타임 상태를 읽는 중입니다.', + '未检测到 Claude Code CLI': 'Claude Code CLI를 찾을 수 없습니다', + '请先安装官方 Claude Code CLI,然后刷新状态。': '공식 Claude Code CLI를 설치한 다음 상태를 새로 고치세요.', + '尚未登录 Claude': 'Claude에 로그인하지 않음', + '在终端完成登录后点击“重新检测”。': '터미널에서 로그인한 후 ‘다시 확인’을 클릭하세요.', + '已登录 Claude': 'Claude에 로그인됨', + '凭据与续期均由 Claude Code CLI 管理。': '자격 증명과 갱신은 Claude Code CLI가 관리합니다.', + 'Claude Code 暂时不可用': 'Claude Code를 일시적으로 사용할 수 없습니다', + 'Claude Code CLI {version}': 'Claude Code CLI {version}', + '无法连接 Claude Code 服务,请确认开发服务正在运行。': 'Claude Code 서비스에 연결할 수 없습니다. 개발 서버가 실행 중인지 확인하세요.', + '无法读取 Claude Code 模型,请稍后重试。': 'Claude Code 모델을 불러올 수 없습니다. 다시 시도하세요.', + '重新检测': '다시 확인', + '登录': '로그인', + '长期令牌': '장기 토큰', + '已配置': '설정됨', + '未配置': '설정 안 됨', + '测试中…': '테스트 중…', + '测试连接': '연결 테스트', + '测试代理连接': '프록시 연결 테스트', + '测试并读取模型': '테스트 및 모델 불러오기', + '会话有效期至': '세션 유효 기간', + '导入登录状态': '로그인 정보 가져오기', + '重新导入': '다시 가져오기', + '注销': '로그아웃', + '请先在终端运行官方 Grok CLI 登录,再回到这里导入登录状态:': '먼저 터미널에서 공식 Grok CLI로 로그인한 다음 여기에서 로그인 정보를 가져오세요:', + '订阅(SuperGrok 或 X Premium+)登录成功后,grok login 会把会话写入本机。': '구독(SuperGrok 또는 X Premium+)으로 로그인하면 grok login이 세션을 로컬에 저장합니다.', + '使用 SuperGrok 或 X Premium+ 订阅登录:官方 Grok CLI 管理登录与凭据(终端运行 grok login),OpenChatCut 导入会话并自动续期,不会读取或显示 OAuth 凭据。': 'SuperGrok 또는 X Premium+ 구독으로 로그인합니다: 공식 Grok CLI가 로그인과 자격 증명을 관리하며(터미널에서 grok login 실행), OpenChatCut은 세션을 가져와 자동으로 갱신하고 OAuth 자격 증명을 읽거나 표시하지 않습니다.', + 'xAI · Grok (订阅登录)': 'xAI · Grok(구독 로그인)', + '使用 xAI 订阅会话(SuperGrok / X Premium+,优先)或 LLM_XAI_API_KEY 生成图片。文生图:最多 4 张,1K / 2K。': 'xAI 구독 세션(SuperGrok / X Premium+, 우선) 또는 LLM_XAI_API_KEY로 이미지를 생성합니다. 텍스트→이미지: 최대 4장, 1K / 2K.', + '使用 xAI 订阅会话(SuperGrok / X Premium+,优先)或 LLM_XAI_API_KEY 生成视频。文生视频:1–15 秒,自带音轨,480p / 720p / 1080p。': 'xAI 구독 세션(SuperGrok / X Premium+, 우선) 또는 LLM_XAI_API_KEY로 동영상을 생성합니다. 텍스트→동영상: 1–15초, 오디오 트랙 포함, 480p / 720p / 1080p.', + 'OFox · 多模型': 'OFox · 멀티 모델', + 'OFox · 多模型网关': 'OFox · 멀티 모델 게이트웨이', + '使用 LLM_OFOX_API_KEY(在 Agent 供应商里配置 OFox)生成视频。一个 Key 覆盖 Seedance、Wan 等视频模型;支持文生视频、首帧/首尾帧图生视频与图片参考(最多 9 张);时长/分辨率按模型由 API 校验,2–30 秒。': 'LLM_OFOX_API_KEY(에이전트 공급자에서 OFox 설정)로 동영상을 생성합니다. 키 하나로 Seedance, Wan 등 여러 동영상 모델을 사용할 수 있으며, 텍스트→동영상, 첫 프레임 / 첫·마지막 프레임 기반 이미지→동영상, 최대 9장의 참조 이미지를 지원합니다. 길이/해상도는 모델별로 API가 검증하며 2–30초입니다.', + 'xAI · Grok Imagine (视频)': 'xAI · Grok Imagine(동영상)', + '验证地址与密钥,并读取该接口可用的模型': '엔드포인트와 키를 확인한 다음 해당 API에서 사용 가능한 모델을 불러옵니다', + '选择模型': '모델 선택', + '测试请求失败 ({n})': '테스트 요청 실패 ({n})', + '该厂商暂不支持连接测试': '이 공급자는 아직 연결 테스트를 지원하지 않습니다', + '(按当前输入测试,记得保存)': ' (현재 입력값으로 테스트함 — 저장하는 것을 잊지 마세요)', + '发一条最小请求验证 Key 与地址可用': '최소한의 요청을 한 번 보내 키와 엔드포인트를 확인합니다', + '使用当前代理地址访问外网探测端点': '현재 프록시 주소로 외부 연결 확인 엔드포인트에 접속합니다', + '本次设置': '이번 설정', + '取消清除': '지우기 취소', + '清除': '지우기', + '已启用': '활성화됨', + '已停用': '비활성화됨', + '已保存 · 工具即时生效,Agent 下一条消息即可感知': '저장됨 · 도구는 즉시 적용되며 에이전트는 다음 메시지부터 반영합니다', + '默认({name})': '기본값({name})', + '恢复默认 · 保存后生效': '기본값 복원 · 저장 후 적용', + '默认 {name}': '기본값 {name}', + '默认': '기본값', + '将清除 · 保存后生效': '지울 예정 · 저장 후 적용', + '已自定义 · 留空保持不变': '사용자 지정됨 · 비워 두면 유지', + '已配置 · 留空保持不变': '설정됨 · 비워 두면 유지', + '未配置 · 粘贴以启用': '설정 안 됨 · 붙여 넣어 사용', + 'API Key(可选)': 'API 키(선택)', + '代理地址': '프록시 URL', + '例如 http://127.0.0.1:7890': '예: http://127.0.0.1:7890', + '系统默认素材目录': '시스템 기본 미디어 디렉터리', + '选择目录': '폴더 선택', + '选择中…': '선택 중…', + '选择素材保存目录': '미디어 저장 폴더 선택', + '无法打开目录选择器': '폴더 선택기를 열 수 없습니다', + '目录选择器仅桌面端可用': '폴더 선택기는 데스크톱 앱에서만 사용할 수 있습니다', + '目录选择器仅桌面端可用,浏览器中请手动输入绝对路径。': '폴더 선택기는 데스크톱 앱에서만 사용할 수 있습니다. 브라우저에서는 절대 경로를 직접 입력하세요.', + '默认 https://api.anthropic.com': '기본값 https://api.anthropic.com', + '按接口使用官方默认地址': '선택한 API 형식의 공식 기본 주소 사용', + '按接口自动选择': 'API 형식에 따라 자동', + '按厂商使用官方默认地址': '선택한 공급자의 공식 엔드포인트 사용', + '按厂商自动选择': '공급자에 따라 자동', + '默认 https://api.openai.com': '기본값 https://api.openai.com', + '默认 https://generativelanguage.googleapis.com': '기본값 https://generativelanguage.googleapis.com', + '默认 https://api.elevenlabs.io': '기본값 https://api.elevenlabs.io', + '默认 https://openspeech.bytedance.com': '기본값 https://openspeech.bytedance.com', + '音色 ID(speaker)': '음성 ID(speaker)', + '由对话选择': '채팅에서 선택', + '粘贴火山控制台复制的音色 ID(如 S_5wulnA7i2);填写后豆包配音默认用它,对话里指定其它音色仍可覆盖。': 'Volcengine 콘솔에서 복사한 음성 ID를 붙여넣으세요(예: S_5wulnA7i2). 설정하면 Doubao TTS가 기본으로 이 음성을 사용하며, 채팅에서 다른 음성을 지정하면 그 음성이 우선합니다.', + '默认 https://ark.cn-beijing.volces.com/api/v3': '기본값 https://ark.cn-beijing.volces.com/api/v3', + '默认 https://api-singapore.klingai.com': '기본값 https://api-singapore.klingai.com', + '默认 https://api.mureka.ai': '기본값 https://api.mureka.ai', + '默认 https://api.sonilo.com': '기본값 https://api.sonilo.com', + '默认 https://api.minimaxi.com': '기본값 https://api.minimaxi.com', + '默认 https://api.atlascloud.ai/api/v1': '기본값 https://api.atlascloud.ai/api/v1', + '默认 https://api.mistral.ai/v1': '기본값 https://api.mistral.ai/v1', + '默认 https://api.groq.com/openai/v1': '기본값 https://api.groq.com/openai/v1', + '设计风格': '디자인 스타일', + '选择 MG 动画的视觉风格': 'MG 애니메이션의 시각 스타일 선택', + '全部场景': '모든 시나리오', + '无': '없음', + '预设': '프리셋', + '我的风格': '내 스타일', + '配色': '색상', + '主色': '기본 색상', + '辅色': '보조 색상', + '强调色': '강조 색상', + '背景': '배경', + '文字': '텍스트', + '字体': '글꼴', + '标题字体': '제목 글꼴', + '正文字体': '본문 글꼴', + '品牌指引(可选)': '브랜드 가이드(선택 사항)', + '工程创作指引(可选)': '프로젝트 편집 가이드(선택 사항)', + '写下调色、字幕、节奏、转场偏好和禁用项,Agent 编辑时会遵守。': '색 보정, 자막, 페이싱, 전환 선호도와 에이전트가 피해야 할 사항을 작성하세요.', + '用一句话描述这个品牌的视觉倾向,AI 生成时会遵守。': '브랜드의 시각적 방향을 한 문장으로 설명하세요. AI 생성 시 이를 따릅니다.', + '预览': '미리보기', + '标题示例 Heading': '제목 샘플', + '正文示例:这段文字演示正文字体与文字颜色的搭配效果。': '본문 샘플: 이 텍스트는 본문 글꼴과 텍스트 색상의 조합을 보여줍니다.', + '主色按钮': '기본 버튼', + '强调': '강조', + '风格名称': '스타일 이름', + '风格资料': '스타일 정보', + '适用场景,用逗号分隔': '시나리오(쉼표로 구분)', + '缩略图 URL(仅用于风格选择器)': '썸네일 URL(스타일 선택기 전용)', + '保存资料': '정보 저장', + '清除缩略图': '썸네일 지우기', + '确定': '확인', + '取消': '취소', + '清除风格': '스타일 지우기', + '保存为我的风格': '내 스타일로 저장', + '应用到工程': '프로젝트에 적용', + '删除此风格': '이 스타일 삭제', + '中文': '중국어', + '西文': '라틴 문자', + '如 Inter / 得意黑': '예: Inter / Smiley Sans', + '从清单选择字体': '목록에서 글꼴 선택', + '皮肤': '스킨', + '石墨': '그래파이트', + '墨黑': '미드나이트', + '摩卡': '모카', + '北极': '노르드', + '东京夜': '도쿄 나이트', + '拿铁(浅色)': '라테(라이트)', + '键盘快捷键': '키보드 단축키', + '点击快捷键可改绑': '단축키를 클릭하여 다시 지정', + '全部重置': '모두 초기화', + '恢复默认': '기본값 복원', + '点击改绑': '클릭하여 다시 지정', + '按下按键… (Esc)': '키를 누르세요… (Esc)', + '已被占用:': '이미 사용 중: ', + '仍要绑定': '그래도 지정', + '清理素材': '미디어 정리', + '列出所有工程都不引用的上传文件': '어떤 프로젝트에서도 참조하지 않는 업로드 파일', + '扫描中…(逐工程收集引用)': '스캔 중…(프로젝트별 참조 수집)', + '没有无主素材,盘上很干净 ✨': '사용되지 않는 미디어가 없습니다 — 디스크가 깨끗합니다 ✨', + '已顺手清掉 {n} 份孤儿工程文档(测试残留)': '사용되지 않는 프로젝트 문서 {n}개도 정리했습니다(테스트 잔여물)', + '扫描失败:{msg}': '스캔 실패: {msg}', + '已删 {ok} 个,{fail} 个失败': '{ok}개 삭제, {fail}개 실패', + '已删 {n} 个文件': '파일 {n}개 삭제됨', + '已选 {n} 个 · {size}': '{n}개 선택됨 · {size}', + '删除中…': '삭제 중…', + '删除所选': '선택 항목 삭제', + '外部 Agent 接入 (MCP)': '외부 에이전트(MCP)', + 'Streamable HTTP · 与内置 Agent 共享编辑工具': 'Streamable HTTP · 내장 에이전트와 편집 도구 공유', + '所有客户端共用一个端点': '모든 클라이언트가 하나의 엔드포인트를 공유합니다', + 'Anthropic 官方 CLI,Claude 订阅用户直连。': 'Claude 구독자를 위한 Anthropic 공식 CLI', + 'OpenAI CLI,通过环境变量携带令牌。': 'OpenAI 공식 CLI, 환경 변수로 토큰을 전달합니다.', + '写入 ~/.cursor/mcp.json 的全局配置。': '~/.cursor/mcp.json에 전역 설정을 기록합니다.', + '写入 ~/.gemini/antigravity/mcp_config.json。': '~/.gemini/antigravity/mcp_config.json에 전역 설정을 기록합니다.', + '写入 ~/.qoder/settings.json,国内版同时写 ~/.qoder-cn。': '~/.qoder/settings.json에 기록하며, 중국판은 ~/.qoder-cn에도 기록합니다.', + '千问办公': 'Qwen Work', + '自定义 MCP 只存在应用内,复制 JSON 后在连接器里粘贴。': '사용자 지정 MCP 서버는 앱 내부에만 존재합니다. 이 JSON을 복사하여 앱의 커넥터에 붙여넣으세요.', + '复制配置': '설정 복사', + '配置已复制,粘贴到客户端的自定义 MCP 输入框。': '설정이 복사되었습니다. 클라이언트의 사용자 지정 MCP 입력란에 붙여넣으세요.', + '复制失败,请手动选择配置文本。': '복사에 실패했습니다. 설정 텍스트를 직접 선택하세요.', + '连接': '연결', + '连接中…': '연결 중…', + '已连接': '연결됨', + '连接失败': '연결 실패', + '已写入 {paths}': '{paths}에 기록했습니다', + '已写入 {paths}。请完全退出并重新打开 Codex,令牌才会生效。': '{paths}에 기록했습니다. 토큰이 적용되도록 Codex를 완전히 종료한 후 다시 여세요.', + '连接后重启对应客户端生效;Codex 需新开终端使环境变量生效。': '연결 후 해당 클라이언트를 다시 시작하세요. Codex는 환경 변수 적용을 위해 새 터미널이 필요합니다.', + '目标配置文件不是有效 JSON,为避免覆盖未写入。': '대상 설정 파일이 유효한 JSON이 아니므로 덮어쓰지 않도록 아무것도 기록하지 않았습니다.', + '写入配置文件失败。': '설정 파일을 기록하지 못했습니다.', + '执行 codex mcp add 失败。': 'codex mcp add 실행에 실패했습니다.', + '已在 Codex 注册,但令牌未能保存为 Windows 用户环境变量,连接未完成。': 'Codex에 등록했지만 토큰을 Windows 사용자 환경 변수로 저장하지 못해 연결이 완료되지 않았습니다.', + 'OpenChatCut 暴露一个 Streamable HTTP MCP 端点。Claude Code / Codex / Cursor 等外部 Agent 接入后,与内置 Agent 共用同一套编辑工具,可直接读写当前工程。': 'OpenChatCut은 Streamable HTTP MCP 엔드포인트를 제공합니다. Claude Code, Codex, Cursor 등 외부 에이전트는 내장 에이전트와 동일한 편집 도구를 공유하며 현재 프로젝트를 직접 읽고 편집할 수 있습니다.', + '端点地址': '엔드포인트', + '内置 Agent 与外部 MCP': '내장 에이전트와 외부 MCP 비교', + '内置 Agent 会先生成可预览的修改提案,由你应用或拒绝;外部 MCP 使用独立编辑会话,manual 模式等待审核,auto 模式在 review 时直接应用。两者都只通过 EditorCore 命令修改工程。': '내장 에이전트는 미리 볼 수 있는 수정 제안을 만들어 적용하거나 거부할 수 있게 합니다. 외부 MCP는 독립된 편집 세션을 사용합니다. manual 모드는 검토를 기다리고, auto 모드는 review 시 바로 적용합니다. 두 방식 모두 EditorCore 명령을 통해서만 프로젝트를 수정합니다.', + '连接本地模型': '로컬 모델 연결', + '打开 设置 → Agent 模型 → Agent 大脑 → OpenAI,填写本地或兼容服务的 API URL 和模型;按服务选择 Responses API 或 Chat Completions API,再点“测试并读取模型”。仅在服务要求时填写 API Key。': '설정 → 에이전트 모델 → 에이전트 두뇌 → OpenAI를 열고 로컬 또는 호환 서비스의 API URL과 모델을 입력하세요. 서비스에 맞게 Responses API 또는 Chat Completions API를 선택한 다음 ‘테스트 및 모델 불러오기’를 클릭하세요. 서비스에서 요구하는 경우에만 API 키를 입력하세요.', + '复制到剪贴板': '복사', + '编辑配方': '편집 레시피', + '导入配方': '레시피 가져오기', + '导出配方': '레시피 내보내기', + '配方导入失败': '레시피를 가져올 수 없습니다', + '配方导出失败': '레시피를 내보낼 수 없습니다', + '配方文件过大': '레시피 파일이 너무 큽니다', + '配方文件不是有效的 JSON': '레시피 파일이 유효한 JSON이 아닙니다', + '配方文件结构无效': '레시피 파일 구조가 올바르지 않습니다', + '配方文件版本不受支持': '지원되지 않는 레시피 파일 버전입니다', + '配方缺少风格内容': '레시피에 스타일이 없습니다', + '配方风格结构无效': '레시피 스타일 구조가 올바르지 않습니다', + '配方内容过多': '레시피 항목이 너무 많습니다', + '配方颜色结构无效': '레시피 색상 구조가 올바르지 않습니다', + '配方字体结构无效': '레시피 글꼴 구조가 올바르지 않습니다', + '配方名称无效': '레시피 이름이 올바르지 않습니다', + '颜色角色无效': '색상 역할이 올바르지 않습니다', + '颜色值无效': '색상 값이 올바르지 않습니다', + '字体角色无效': '글꼴 역할이 올바르지 않습니다', + '字体名称无效': '글꼴 패밀리가 올바르지 않습니다', + '工程创作指引无效': '프로젝트 편집 가이드가 올바르지 않습니다', + '适用场景结构无效': '레시피 시나리오가 올바르지 않습니다', + '适用场景无效': '레시피 시나리오가 올바르지 않습니다', + '缩略图地址无效': '썸네일 URL이 올바르지 않습니다', + '正在读取 MCP 连接令牌…': 'MCP 연결 토큰 불러오는 중…', + '无法读取 MCP 连接令牌,请从受信任的编辑器窗口重试。': 'MCP 연결 토큰을 불러올 수 없습니다. 신뢰할 수 있는 편집기 창에서 다시 시도하세요.', + 'MCP 端点始终要求 Bearer 令牌。令牌在首次启动时生成并保存在本机,重启后保持不变,配置一次即可持续使用;OPENCHATCUT_MCP_TOKEN 环境变量可覆盖。令牌只在当前受信任编辑器会话中显示,不写入工程、聊天或浏览器存储。': 'MCP 엔드포인트는 항상 Bearer 토큰이 필요합니다. 토큰은 처음 실행할 때 생성되어 이 기기에 저장되며 다시 시작해도 바뀌지 않으므로 한 번만 등록하면 계속 사용할 수 있습니다. OPENCHATCUT_MCP_TOKEN 환경 변수로 재정의할 수 있습니다. 토큰은 현재 신뢰할 수 있는 편집기 세션에서만 표시되며 프로젝트, 채팅, 브라우저 저장소에는 기록되지 않습니다.', + '设置 → 连接器 → 添加自定义连接器,粘贴上面的端点地址即可。': '설정 → 커넥터 → 사용자 지정 커넥터 추가에서 위의 엔드포인트를 붙여넣으세요.', + '端点默认仅监听本机;对外暴露时请配置 OPENCHATCUT_MCP_TOKEN 鉴权。桌面端 5199 端口被占用时会回退随机端口,以启动日志与本页地址为准。': '엔드포인트는 기본적으로 localhost에서만 수신합니다. 외부에 노출하기 전에 OPENCHATCUT_MCP_TOKEN 인증을 설정하세요. 5199 포트가 사용 중이면 데스크톱 앱은 임의 포트로 대체되므로 시작 로그와 여기에 표시된 주소를 기준으로 하세요.', + '本地转写': '로컬 전사', + '节拍与音乐分析': '비트 및 음악 분석', + '画面语义搜索': '시각적 의미 검색', + '本地模型按需安装,索引、转写和分析都在本机完成。': '로컬 모델은 필요할 때 설치됩니다. 인덱싱, 전사, 분석은 모두 이 기기에서 실행됩니다.', + '节拍与音乐分析模型': '비트 및 음악 분석 모델', + '画面语义搜索模型包': '시각적 의미 검색 모델 팩', + '按画面内容搜索素材的本地向量模型(约 178MB)。模型在本机运行,素材不会上传。': '화면 내용으로 미디어를 검색하는 로컬 벡터 모델입니다(약 178 MB). 이 기기에서 실행되며 미디어를 업로드하지 않습니다.', + '操作失败:{err}': '작업 실패: {err}', + '未检测到模型包服务。': '모델 팩 서비스를 사용할 수 없습니다.', + '下载中…': '다운로드 중…', + '已安装。打开媒体池 → 语义搜索面板即可索引素材并按画面搜索。': '설치되었습니다. 미디어 풀 → 의미 검색을 열어 미디어를 인덱싱하고 화면 내용으로 검색하세요.', + '下载中 {pct}%': '다운로드 중 {pct}%', + '下载失败': '다운로드 실패', + '已下载': '다운로드됨', + '未下载': '다운로드 안 됨', + '删除': '삭제', + '下载': '다운로드', + '补全': '보완', + '桌面引擎已就绪;补全浏览器引擎文件,供桌面推理失败时回退': '데스크톱 엔진이 준비되었습니다. 데스크톱 추론 실패 시 대체용으로 브라우저 엔진 파일도 다운로드하세요.', + '模型按需下载到本机,不随应用打包。首次使用或下载模型时自动加速下载。': '모델은 필요할 때 이 기기에 다운로드되며 앱에 포함되어 있지 않습니다. 다운로드에는 가속 파이프라인이 자동으로 사용됩니다.', + '桌面原生推理加速': '데스크톱 네이티브 추론 가속', + '启用后,转写使用 macOS Metal 或原生 CPU;画面语义、节拍与音乐语义模型自动选择 Windows DirectML、Linux CUDA、macOS CoreML 或浏览器 WebGPU;失败时回退 CPU 或浏览器引擎。': '사용하면 전사에 macOS Metal 또는 네이티브 CPU를 사용합니다. 시각적 의미 분석, 리듬, 음악 의미 분석 모델은 Windows DirectML, Linux CUDA, macOS CoreML 또는 브라우저 WebGPU를 자동으로 선택합니다. 실패하면 CPU 또는 브라우저 엔진으로 대체됩니다.', + 'WebGPU 转写加速': 'WebGPU 전사 가속', + '删除静音(本地 VAD)': '무음 제거(로컬 VAD)', + '启用后,Agent 的删除静音用本机 Silero VAD 判定语音区间,只删除确认无人说话的片段;关闭时不执行删除。模型随应用内置,无需下载。': '사용하면 에이전트의 무음 제거가 기기 내 Silero VAD로 음성 구간을 찾아 음성이 없는 것으로 확인된 구간만 삭제합니다. 사용하지 않으면 아무것도 삭제하지 않습니다. 모델이 앱에 포함되어 있어 다운로드가 필요 없습니다.', + '无法读取模型列表:{err}': '모델 목록을 불러올 수 없습니다: {err}', + '默认模型': '기본 모델', + '自动(按设备内存选择)': '자동(기기 메모리 기준)', + '选中的模型需已下载;未选择时按设备内存自动挑选(内存 ≥6GB 用 Small,否则 Base)。': '선택한 모델은 먼저 다운로드해야 합니다. 선택하지 않으면 기기 메모리에 따라 자동으로 선택됩니다(6GB 이상 → Small, 그 외 Base).', + 'Whisper Tiny(约 100MB · 最快)': 'Whisper Tiny(약 100MB · 가장 빠름)', + 'Whisper Base(约 80MB · 均衡)': 'Whisper Base(약 80MB · 균형)', + 'Whisper Small(约 250MB · 推荐)': 'Whisper Small(약 250MB · 권장)', + 'Whisper Medium(约 1.1GB · 精度最高)': 'Whisper Medium(약 1.1GB · 최고 정확도)', + 'Whisper Large v3 Turbo(约 1.1GB · 多语言最强)': 'Whisper Large v3 Turbo(약 1.1GB · 최고 다국어 성능)', + '本地智能模型': '로컬 인텔리전스 모델', + '模型不会自动安装。安装后,节拍与音乐语义分析只在本机运行。': '모델은 자동으로 설치되지 않습니다. 설치 후 비트 및 음악 의미 분석은 이 기기에서만 실행됩니다.', + '无法读取模型包列表:{err}': '모델 팩을 불러올 수 없습니다: {err}', + '节奏分析轻量包': '리듬 라이트', + '音乐语义轻量包': '음악 의미 분석 라이트', + '本地分析节拍、下拍、速度、拍号与节拍能量。': '비트, 다운비트, 템포, 박자, 비트 에너지를 로컬에서 분석합니다.', + '在本机生成音乐语义向量,用于检索与相似度匹配。': '검색 및 유사도 매칭을 위한 음악 의미 임베딩을 로컬에서 생성합니다.', + '节拍定位': '비트 추적', + '下拍定位': '다운비트 추적', + 'BPM 与拍号': 'BPM 및 박자', + '节拍能量': '비트 에너지', + '音乐语义向量': '음악 의미 임베딩', + '音乐相似度': '음악 유사도', + '建议内存 {memory}': '권장 메모리 {memory}', + '安装中 {pct}%({done}/{total} 个文件)': '설치 중 {pct}%({done}/{total}개 파일)', + '已安装': '설치됨', + '安装中': '설치 중', + '安装错误': '설치 오류', + '未安装': '설치 안 됨', + '重新安装': '다시 설치', + '安装': '설치', + '不描述图片,一律剥离。': '이미지를 설명하지 않고 항상 제거합니다.', + '主模型不支持图片时维持现状(图片剥离为文本)。': '주 모델이 이미지를 인식할 수 없을 때 현재 동작을 유지합니다(이미지를 텍스트로 대체).', + '厂商(已配置 API Key)': '공급자(API 키 설정됨)', + '图片与时间线帧由所选视觉模型理解后以文本注入。': '이미지와 타임라인 프레임은 선택한 비전 모델이 해석한 후 텍스트로 주입됩니다.', + '图片会发送给所选视觉模型厂商用于描述;视觉调用失败时自动回退为剥离文本,不阻塞对话。': '이미지는 설명을 위해 선택한 비전 공급자에게 전송됩니다. 비전 호출이 실패하면 텍스트 대체로 자동 전환되며 대화를 막지 않습니다.', + '基底模型不支持图片输入时(如 DeepSeek 系),图片由所选视觉模型理解后以文本注入。': '기본 모델이 이미지 입력을 지원하지 않는 경우(예: DeepSeek 계열) 선택한 비전 모델이 이미지를 해석하여 텍스트로 주입합니다.', + '已指定': '사용자 지정', + '已禁用': '사용 안 함', + '指定视觉模型': '특정 비전 모델 사용', + '无可用厂商(请先配置 API Key)': '사용 가능한 공급자 없음(먼저 API 키를 설정하세요)', + '禁用': '사용 안 함', + '视觉模型': '비전 모델', + '视觉理解': '비전 인식', + '跟随主模型': '주 모델 따르기', + '默认工程位置': '기본 프로젝트 위치', + '应用默认数据目录': '기본 앱 데이터 폴더', + '新工程和生成素材的默认保存位置,以及可选的 R2 云备份。': '새 프로젝트와 생성된 미디어의 기본 저장 위치 및 선택적 R2 클라우드 백업입니다.', + '新建工程、历史版本和应用生成的素材保存在这里。桌面端从外部拖入的文件和文件夹保留在原位置,工程只建立引用;浏览器运行时会上传托管副本。修改后重启应用生效。': '새 프로젝트, 버전 기록, 앱에서 생성한 미디어가 여기에 저장됩니다. 데스크톱 앱에서는 외부 파일과 폴더가 원래 위치에 그대로 있으며 참조로 연결됩니다. 브라우저 세션에서는 관리용 사본을 업로드합니다. 변경 사항은 앱을 다시 시작한 후 적용됩니다.', + '未配置时素材只存本机。配置后:每次上传同步写入 R2(桶保持私有,读取经本地服务回源,src 路径不变);本机缺文件时自动从云端取回。改动即时生效。R2 控制台建桶 → R2 API Token(Object Read & Write)即可拿到下面四个值。': '설정하지 않으면 미디어는 이 기기에만 저장됩니다. 설정하면 업로드 시 R2에도 기록되며, 로컬에 없는 파일은 로컬 서비스를 통해 복원되고 소스 URL은 바뀌지 않습니다. 변경 사항은 즉시 적용됩니다. R2에서 버킷과 Object Read & Write API 토큰을 만들면 아래 네 가지 값을 얻을 수 있습니다.', + '桌面端点击“选择目录”;也可手动输入绝对路径(可用 ~/ 开头)。清除后回到默认目录。': '데스크톱에서는 ‘폴더 선택’을 클릭하세요. 절대 경로를 직접 입력할 수도 있습니다(~/ 사용 가능). 지우면 기본 폴더로 돌아갑니다.', + '已保存 · 重启应用后新的工程存储目录才会生效': '저장됨 · 새 프로젝트 저장 폴더는 다시 시작한 후 적용됩니다', + '该模型不在内置目录,以上数值为估算(上下文 {context} / 输出 {output})。若与实际不符,点「展开」手动修改。': '이 모델은 내장 카탈로그에 없으므로 위 값은 추정치입니다(컨텍스트 {context} / 출력 {output}). 실제 모델과 다르면 펼쳐서 직접 조정하세요.', +} as Record; diff --git a/src/i18n/dict/ko/templates-data.ts b/src/i18n/dict/ko/templates-data.ts new file mode 100644 index 000000000..6f1d89b65 --- /dev/null +++ b/src/i18n/dict/ko/templates-data.ts @@ -0,0 +1,312 @@ +// KO data dictionary: Korean display names for data (template/sound/music names). +// Holds both Chinese-key names (self-made templates) and English-key names (built-in catalog). +export default { + // Self-made templates (Chinese keys, see dict/en/templates-data) + '竖屏·重点词弹出': '세로 · 키워드 팝', + '竖屏·大字幕条': '세로 · 큰 자막 바', + '竖屏·金句卡片': '세로 · 인용 카드', + '竖屏·姓名条': '세로 · 이름 바', + '竖屏·关注引导': '세로 · 팔로우 유도', + '竖屏·步骤条': '세로 · 단계 목록', + '竖屏·数字大字报': '세로 · 큰 숫자', + '竖屏·章节进度': '세로 · 챕터 진행률', + '竖屏·价格标签': '세로 · 가격표', + '竖屏·封面大字': '세로 · 커버 타이틀', + '竖屏·清单勾选': '세로 · 체크리스트', + '竖屏·前后对比条': '세로 · 전후 비교', + '竖屏·便签贴纸': '세로 · 메모 스티커', + '竖屏·互动提示': '세로 · 참여 유도', + '竖屏·期数角标': '세로 · 회차 배지', + '口播·米色格纹(横)': '토킹헤드 · 베이지 모눈종이 (16:9)', + '口播·奶咖横线(横)': '토킹헤드 · 라테 줄노트 (16:9)', + '口播·黑板报(横)': '토킹헤드 · 칠판 (16:9)', + '口播·侧栏拼贴(横)': '토킹헤드 · 콜라주 분할 (16:9)', + '口播·便签五五分(竖)': '토킹헤드 · 메모지 분할 (9:16)', + '口播·点阵五五分(竖)': '토킹헤드 · 도트 모눈 분할 (9:16)', + '口播·牛皮纸圆窗(竖)': '토킹헤드 · 크라프트지 코너 (9:16)', + '口播·羊皮纸(横)': '토킹헤드 · 양피지 (16:9)', + '口播·奶油拍立得(竖)': '토킹헤드 · 크림 폴라로이드 (9:16)', + // Built-in templates (English keys, see dict/zh/templates) + 'Bar Chart - Annual Sales': '막대 차트 - 연간 매출', + 'Bar Chart - Category Sales': '막대 차트 - 카테고리별 매출', + 'Bar Chart - Department Headcount': '막대 차트 · 부서별 인원', + 'Bar Chart - Monthly Sales': '막대 차트 · 월별 매출', + 'Bar Chart - Monthly Targets': '막대 차트 · 월별 목표', + 'Bar Chart - Monthly User Growth': '막대 차트 · 월별 사용자 증가', + 'Bar Chart - Quarterly Revenue Comparison': '막대 차트 · 분기별 매출 비교', + 'Bar Chart - Sales by Region': '막대 차트 · 지역별 매출', + 'Bar Chart - Weekly Growth Rate': '막대 차트 · 주간 성장률', + 'Benchmark Bar Chart - Pantone Warm': '벤치마크 막대 차트 · Pantone 웜톤', + 'Benchmark Score Comparison': '벤치마크 점수 비교', + 'Coordinates Weather Dashboard': '좌표 날씨 대시보드', + 'Donut Chart - Budget Allocation': '도넛 차트 · 예산 배분', + 'Donut Chart - Market Share': '도넛 차트 · 시장 점유율', + 'Donut Chart - Regional Sales': '도넛 차트 · 지역별 매출', + 'Hand-Drawn Line Chart': '손그림 꺾은선 차트', + 'Hand-Drawn Radar Chart': '손그림 레이더 차트', + 'Hand-Drawn Scatter Plot': '손그림 분산형 차트', + 'Hand-Drawn Stack Chart': '손그림 누적 차트', + 'Line Chart - App Performance': '꺾은선 차트 · 앱 성능', + 'Line Chart - Growth Trend': '꺾은선 차트 · 성장 추세', + 'Line Chart - Monthly Active Users': '꺾은선 차트 · 월간 활성 사용자', + 'Line Chart - Sales Trend': '꺾은선 차트 · 매출 추세', + 'Line Chart - Stock Price': '꺾은선 차트 · 주가', + 'Line Chart - Temperature Change': '꺾은선 차트 · 기온 변화', + 'Line Chart - User Growth': '꺾은선 차트 · 사용자 증가', + 'Line Chart - Website Traffic': '꺾은선 차트 · 웹사이트 트래픽', + 'Pie Chart - Customer Satisfaction': '원형 차트 · 고객 만족도', + 'Pie Chart - Market Segments': '원형 차트 · 시장 세분화', + 'Pie Chart - Resource Allocation': '원형 차트 · 리소스 배분', + 'Pie Chart - User Age Distribution': '원형 차트 · 사용자 연령 분포', + 'Pie Chart - User Sources': '원형 차트 · 사용자 유입 경로', + 'Retention Graph Card — White Luminance Variant': '리텐션 그래프 카드 · 화이트 광채 버전', + 'Revenue counter stat reveal overlay': '매출 카운터 수치 공개 오버레이', + 'Sales Counter Dashboard': '매출 카운터 대시보드', + 'Article Card': '아티클 카드', + 'Checklist Tick Animation': '체크리스트 체크 애니메이션', + 'Fruit Shopping Tips': '과일 고르는 팁', + 'Product Specs Panel': '제품 사양 패널', + 'Progress Bar': '진행률 표시줄', + 'Progress Bar Title Card': '진행률 표시줄 타이틀 카드', + 'Savings Plan Sidebar': '저축 계획 사이드바', + 'Score Title Card': '점수 타이틀 카드', + 'Shopping Tips Animation': '쇼핑 팁 애니메이션', + 'Stat Title Card': '통계 타이틀 카드', + 'Timeline Progress Bar': '타임라인 진행률 표시줄', + 'Tip List Title Card': '팁 목록 타이틀 카드', + 'Distressed Paper Lower Third': '빈티지 종이 하단 자막', + 'Divided Name Lower Third': '구분선 이름 하단 자막', + 'Editorial Lower Third Card': '에디토리얼 하단 자막 카드', + 'Hand-Drawn Paper Lower Third': '손그림 종이 하단 자막', + 'Lower Third - Minimal Flat': '하단 자막 · 미니멀 플랫', + 'Lower Third - Warm Editorial': '하단 자막 · 웜톤 에디토리얼', + 'Lower Third 01 - Pill Badge': '하단 자막 01 · 알약 배지', + 'Lower Third 03 - Vertical Bar': '하단 자막 03 · 세로 바', + 'Photo Lower Third': '사진 하단 자막', + 'Speaker Intro Card': '연사 소개 카드', + 'Celebrity Quote Flashcards': '명언 플래시카드', + 'Quote Card': '인용 카드', + 'Quote Title Card': '인용 타이틀 카드', + 'Story Quote Card': '스토리 인용 카드', + 'X Quote Card': 'X 인용 카드', + 'Dark Tech — Feature Showcase': '다크 테크 · 기능 소개', + 'Finance Explainer — Chapter Marker Notebook': '금융 해설 · 노트 형식 챕터 페이지', + 'Finance Explainer — Poll Card Progress Bars': '금융 해설 · 투표 카드 진행률 표시줄', + 'Search Interface Simulator': '검색 화면 시뮬레이터', + 'Bullet Points Overlay': '글머리 기호 오버레이', + 'Bullet Points Overlay - Dark Neon': '글머리 기호 오버레이 · 다크 네온', + 'Bullet Points Overlay - Japanese Pastel': '글머리 기호 오버레이 · 일본풍 파스텔', + 'Bullet Points Overlay - Navy': '글머리 기호 오버레이 · 네이비', + 'Bullet Points Overlay - Soft Coral': '글머리 기호 오버레이 · 소프트 코랄', + 'Bullet Points Overlay - Y2K': '글머리 기호 오버레이 · Y2K', + 'Numbered Talking Head Overlay': '토킹헤드 번호 목록 오버레이', + 'Talking Head Keyword Card': '토킹헤드 키워드 카드', + 'Bold Glitch Title': '볼드 글리치 타이틀', + 'Finance Explainer — Chapter Title Card (Light)': '금융 해설 · 챕터 타이틀 카드(라이트)', + 'Gradient Layered Text Page': '그라데이션 레이어 텍스트 페이지', + 'Hand-Drawn List Overlay': '손그림 목록 오버레이', + 'Keyword Roller': '키워드 롤러', + 'Scrolling Text Ticker': '스크롤 텍스트 티커', + 'Takeaway lower-third overlay (baked)': '핵심 요약 하단 자막 오버레이(베이크)', + 'Vibe Effects Title Card': '분위기 효과 타이틀 카드', + 'Alert Card': '알림 카드', + 'Black Title - Box Title': '블랙 타이틀 · 박스 타이틀', + 'Black Title - Character Cascade': '블랙 타이틀 · 글자 캐스케이드', + 'Black Title - Subtitle Line': '블랙 타이틀 · 부제 구분선', + 'Breaking News Title Card': '속보 타이틀 카드', + 'Cinematic Welcome Screen': '시네마틱 환영 화면', + 'Community Stats Title Transition': '커뮤니티 통계 타이틀 전환', + 'Community Welcome Screen': '커뮤니티 환영 화면', + 'Countdown Timer Title Card': '카운트다운 타이머 타이틀 카드', + 'Dial Chapter Card': '다이얼 챕터 카드', + 'Dual Person Title Card': '2인 타이틀 카드', + 'Editorial Title Card': '에디토리얼 타이틀 카드', + 'Event Opener Screen': '이벤트 오프닝 화면', + 'Goal Hierarchy Chapter Page': '목표 계층 챕터 페이지', + 'Golden Chapter Card': '골드 챕터 카드', + 'Location Title Card': '장소 타이틀 카드', + 'Minimal Zoom Title Card': '미니멀 줌 타이틀 카드', + 'Modern Welcome Screen': '모던 환영 화면', + 'Name Tag Title Card': '이름표 타이틀 카드', + 'Neon Title Card': '네온 타이틀 카드', + 'News Broadcast Title Card': '뉴스 방송 타이틀 카드', + 'Paper Chapter Title': '종이 챕터 타이틀', + 'Question mark animation': '물음표 애니메이션', + 'Red Passion Chapter Card': '열정의 빨강 챕터 카드', + 'Simple Name Card': '심플 이름 카드', + 'Skewed Chapter Label': '기울어진 챕터 라벨', + 'Typewriter Chapter Title': '타자기 챕터 타이틀', + '1920s Cultural — Style Showcase HQ': '1920년대 문화 · 스타일 쇼케이스 HQ', + 'AI video script builder': 'AI 동영상 스크립트 빌더', + 'Art Deco Newsletter — Style Showcase HQ': '아르데코 뉴스레터 · 스타일 쇼케이스 HQ', + 'Bar chart growth animation': '막대 차트 성장 애니메이션', + 'Black Friday — Style Showcase HQ': '블랙 프라이데이 · 스타일 쇼케이스 HQ', + 'Bold Typography — Style Showcase HQ': '볼드 타이포그래피 · 스타일 쇼케이스 HQ', + 'Bold Typography Aesthetic — Style Showcase': '볼드 타이포그래피 감성 · 스타일 쇼케이스', + 'Bold Typography Impact — Style Showcase HQ': '볼드 타이포그래피 임팩트 · 스타일 쇼케이스 HQ', + 'Cartoon Style — Style Showcase': '카툰 스타일 · 스타일 쇼케이스', + 'Chapter overview page — 4-part grid': '챕터 개요 페이지 · 4분할 그리드', + 'Chapter page number icon animation': '챕터 페이지 번호 아이콘 애니메이션', + 'Chapter Title Card — Business Overview': '챕터 타이틀 카드 · 비즈니스 개요', + 'Chapter title card — icon + letter-by-letter reveal with motion blur exit': '챕터 타이틀 카드 · 아이콘 + 글자별 등장 + 모션 블러 퇴장', + 'Colorful Inspiration — Style Showcase HQ': '컬러풀 인스피레이션 · 스타일 쇼케이스 HQ', + 'Company Introduction — Split Layout': '회사 소개 · 분할 레이아웃', + 'Creative Watercolor — Chapter Title Card': '크리에이티브 수채화 · 챕터 타이틀 카드', + 'Creative Watercolor — Company Introduction': '크리에이티브 수채화 · 회사 소개', + 'Creative Watercolor — Data Chart': '크리에이티브 수채화 · 데이터 차트', + 'Creative Watercolor — Team Members': '크리에이티브 수채화 · 팀원', + 'Creative Watercolor — Timeline': '크리에이티브 수채화 · 타임라인', + 'Creative Watercolor — Universal Anchor': '크리에이티브 수채화 · 범용 앵커', + 'Dark cinematic chapter title card — "Number 3 / TONE"': '다크 시네마틱 챕터 타이틀 카드 · ‘Number 3 / TONE’', + 'Dark Tech — Callout Tag': '다크 테크 · 콜아웃 태그', + 'Dark Tech — Chapter Title Card': '다크 테크 · 챕터 타이틀 카드', + 'Dark Tech — Comparison Table': '다크 테크 · 비교표', + 'Dark Tech — Price Badge Popup': '다크 테크 · 가격 배지 팝업', + 'Dark Tech — Price Tier Panel': '다크 테크 · 요금제 패널', + 'Dark Tech — Spec Sheet': '다크 테크 · 사양표', + 'Data Chart — Investment Portfolio Allocation': '데이터 차트 · 투자 포트폴리오 배분', + 'Data visualization animation': '데이터 시각화 애니메이션', + 'Digital Revolution — Style Showcase': '디지털 혁명 · 스타일 쇼케이스', + 'eCommerce Business — Style Showcase': '이커머스 비즈니스 · 스타일 쇼케이스', + 'Finance Explainer — Bar Chart Diverging Animated': '금융 해설 · 양방향 막대 차트 애니메이션', + 'Generation Two — chapter title card': 'Generation Two · 챕터 타이틀 카드', + 'Glowing Ring MG — bullet list reveal': '글로잉 링 MG · 글머리 기호 목록 등장', + 'Group Project — Chapter Title Card': '그룹 프로젝트 · 챕터 타이틀 카드', + 'Group Project — Company Introduction': '그룹 프로젝트 · 회사 소개', + 'Group Project — Data Chart': '그룹 프로젝트 · 데이터 차트', + 'Group Project — Team Members': '그룹 프로젝트 · 팀원', + 'Group Project — Timeline': '그룹 프로젝트 · 타임라인', + 'Group Project — Universal Anchor': '그룹 프로젝트 · 범용 앵커', + 'Keyword typing animation': '키워드 타이핑 애니메이션', + 'Letter drop title — HOW DO YOU DIFFERENTIATE': '글자 낙하 타이틀 · HOW DO YOU DIFFERENTIATE', + 'Lower Third - Ball Swipe Typewriter Reveal': '하단 자막 · 볼 스와이프 타자기 등장', + 'Lower-third subtitle pop with gradient slide-up and keyword highlight': '하단 자막 팝 · 그라데이션 슬라이드 업 + 키워드 강조', + 'Manychat-style card slide-up with text mask reveal': 'Manychat 스타일 카드 슬라이드 업 · 텍스트 마스크 등장', + 'Median Age Bar Chart - Speckled Paper Texture with Growing Bars': '중위 연령 막대 차트 · 점박이 종이 질감 + 자라는 막대', + 'MindSpace — Chapter Five: Growth': 'MindSpace · 5장: 성장', + 'MindSpace — Chapter Four: Healing': 'MindSpace · 4장: 치유', + 'MindSpace — Chapter One: Awareness': 'MindSpace · 1장: 인식', + 'MindSpace — Chapter Three: Boundaries': 'MindSpace · 3장: 경계', + 'MindSpace — Chapter Two: Acceptance': 'MindSpace · 2장: 수용', + 'MindSpace — Free Challenge CTA': 'MindSpace · 무료 챌린지 CTA', + 'MindSpace — Kinetic Title Reveal': 'MindSpace · 키네틱 타이틀 등장', + 'MindSpace — Number Counter': 'MindSpace · 숫자 카운터', + 'MindSpace — Quote Card': 'MindSpace · 인용 카드', + 'MindSpace — Ribbon Statement': 'MindSpace · 리본 메시지', + 'MindSpace — Self-Check Questions': 'MindSpace · 자가 점검 질문', + 'MindSpace — Topic Menu': 'MindSpace · 주제 메뉴', + 'MindSpace — Weekly Progress Bar Chart': 'MindSpace · 주간 진행 막대 차트', + 'Minimal Gradient — Chapter Title Card': '미니멀 그라데이션 · 챕터 타이틀 카드', + 'Minimal Gradient — Company Introduction': '미니멀 그라데이션 · 회사 소개', + 'Minimal Gradient — Data Chart': '미니멀 그라데이션 · 데이터 차트', + 'Minimal Gradient — Team Members': '미니멀 그라데이션 · 팀원', + 'Minimal Gradient — Timeline': '미니멀 그라데이션 · 타임라인', + 'Minimal Gradient — Universal Anchor': '미니멀 그라데이션 · 범용 앵커', + 'Name card animation': '이름 카드 애니메이션', + 'News info card': '뉴스 정보 카드', + 'Numbered list card — 4 items with circle stroke animation': '번호 목록 카드 · 4개 항목 원형 테두리 애니메이션', + 'Numbered pebble-badge list with word reveal': '조약돌 배지 번호 목록 · 단어별 등장', + 'Paper texture text pop-up animation': '종이 질감 텍스트 팝업 애니메이션', + 'Picasso Stages — Style Showcase HQ': '피카소의 시기 · 스타일 쇼케이스 HQ', + 'Pie chart animation': '원형 차트 애니메이션', + 'Principle card — dot background, text left-slide': '원칙 카드 · 도트 배경 + 텍스트 왼쪽 슬라이드', + 'Principle card with diagonal band grow animation': '원칙 카드 · 대각선 띠 확장 애니메이션', + 'Quote card slide-in with word-by-word reveal': '인용 카드 슬라이드 인 · 단어별 등장', + 'Reconstruction Era — Bullet Points List': '재건 시대 · 글머리 기호 목록', + 'Reconstruction Era — Chapter Title Card': '재건 시대 · 챕터 타이틀 카드', + 'Reconstruction Era — Data Chart': '재건 시대 · 데이터 차트', + 'Reconstruction Era — Highlight Quote': '재건 시대 · 강조 인용', + 'Reconstruction Era — Lower Third Name Tag': '재건 시대 · 하단 자막 이름표', + 'Reconstruction Era — Universal Anchor': '재건 시대 · 범용 앵커', + 'Retention Graph': '리텐션 그래프', + 'Retro Decode — Style Showcase HQ': '레트로 디코드 · 스타일 쇼케이스 HQ', + 'Steps for Studying — Style Showcase': '공부 단계 · 스타일 쇼케이스', + 'Stock Market lower-third banner animation': '주식 시장 하단 배너 애니메이션', + 'Takeaway lower-third overlay': '핵심 요약 하단 자막 오버레이', + 'Team Members — Leadership Grid': '팀원 · 리더십 그리드', + 'Tech Trends 2026 — Chapter Title Card': '테크 트렌드 2026 · 챕터 타이틀 카드', + 'Tech Trends 2026 — Company Introduction': '테크 트렌드 2026 · 회사 소개', + 'Tech Trends 2026 — Data Chart': '테크 트렌드 2026 · 데이터 차트', + 'Tech Trends 2026 — Team Members': '테크 트렌드 2026 · 팀원', + 'Tech Trends 2026 — Timeline': '테크 트렌드 2026 · 타임라인', + 'Tech Trends 2026 — Universal Anchor': '테크 트렌드 2026 · 범용 앵커', + 'Timeline — Company Milestones': '타임라인 · 회사 연혁', + 'Type emphasis animation': '텍스트 강조 애니메이션', + 'Typewriter indicator animation': '타자기 하이라이트 표시 애니메이션', + 'Vertical timeline animation': '세로 타임라인 애니메이션', + 'White bold serif text slide-in reveal animation': '흰색 볼드 세리프 텍스트 슬라이드 인 애니메이션', + 'Work-Life — Style Showcase HQ': '일과 생활 · 스타일 쇼케이스 HQ', + // Sounds (English keys, see dict/zh/sounds) + 'Simple Whoosh': '심플 휙', + 'Deep Short Whoosh': '묵직한 짧은 휙', + 'Airy Short Whoosh': '가벼운 짧은 휙', + 'Long Suspense Riser': '긴 서스펜스 라이저', + 'Fast Suspense Riser': '빠른 서스펜스 라이저', + 'Sharp Bass Riser': '날카로운 베이스 라이저', + 'Short Drum Roll Sting': '짧은 드럼 롤 스팅', + 'Vine Boom Impact': '바인 붐 임팩트', + 'Dramatic Thunder Roll': '극적인 천둥소리', + 'Anime Wow Reaction': '애니메이션 감탄 리액션', + 'Awkward Crow Flyby': '어색한 까마귀 지나감', + 'Sitcom Laugh Track': '시트콤 웃음소리', + 'Tiny Bubble Pop': '작은 거품 톡', + 'Synthetic Bubble Pop': '합성 거품 톡', + 'Keyboard Typing Loop': '키보드 타이핑 루프', + 'Slow Dell Keyboard Typing': '느린 Dell 키보드 타이핑', + 'Mouse Click': '마우스 클릭', + 'New Notification Ping': '새 알림음', + 'UI Pop-up Alert': 'UI 팝업 알림', + 'Phone Notification Ping': '휴대폰 알림음', + 'Sent Message Ping': '메시지 전송음', + 'Video Call Ringtone': '영상 통화 벨소리', + 'Record Scratch Stop': '레코드 스크래치 정지', + 'Record Scratch Rewind': '레코드 스크래치 되감기', + 'Camera Shutter': '카메라 셔터', + 'Vintage Camera Shutter': '빈티지 카메라 셔터', + 'Short Shutter Click': '짧은 셔터 클릭', + 'Mechanical Clicking Loop': '기계식 클릭 루프', + 'Gear Turn Click': '기어 회전 딸깍', + 'Light Clock Tick': '가벼운 시계 똑딱', + 'Clean Ding': '맑은 딩', + 'Censor Beep': '검열 삐 소리', + 'Cash Register Success': '계산대 결제 성공음', + 'Glitchy TV Signal': 'TV 신호 글리치', + 'TV Switch Off Noise': 'TV 꺼지는 소리', + 'Soft Air Whoosh': '부드러운 바람 휙', + 'Deep Impact Hit': '묵직한 임팩트 히트', + 'Crisp UI Click': '또렷한 UI 클릭', + 'Success Chime': '성공 차임', + // Music (English keys, see dict/zh/music) + 'electronic': '일렉트로닉', + 'rock': '록', + 'hip-hop': '힙합', + 'pop': '팝', + 'orchestral': '오케스트라', + 'acoustic': '어쿠스틱', + 'jazz': '재즈', + 'ambient': '앰비언트', + 'energetic': '활기찬', + 'calm': '차분한', + 'tense': '긴장감', + 'romantic': '로맨틱', + 'dreamy': '몽환적', + 'playful': '경쾌한', + 'melancholic': '우울한', + 'epic': '웅장한', + 'vocal': '보컬', + 'instrumental': '연주곡', + 'guitar': '기타', + 'piano': '피아노', + 'strings': '현악기', + 'drums': '드럼', + 'synth': '신스', + 'brass': '금관악기', + 'vlog': '브이로그', + 'travel': '여행', + 'trailer': '예고편', + 'corporate': '기업', + 'wedding': '웨딩', + 'sports': '스포츠', + 'suspense': '서스펜스', + 'background': '배경 음악', +} as Record; diff --git a/src/i18n/dict/ko/timeline.ts b/src/i18n/dict/ko/timeline.ts new file mode 100644 index 000000000..5ef18100e --- /dev/null +++ b/src/i18n/dict/ko/timeline.ts @@ -0,0 +1,251 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '该轨道还没有可用文字稿': '이 트랙에는 아직 사용할 수 있는 전사 텍스트가 없습니다', + '导出 MG 动画中(ProRes 4444)…': 'MG 애니메이션 내보내는 중(ProRes 4444)…', + '导出失败': '내보내기 실패', + '转为视频中…': '비디오로 변환 중…', + '转换失败': '변환 실패', + '选择模式:点片段引用 · 拖过标尺/空白选时间段 · 单击标尺打时间点 — 引用会加进聊天输入框': '선택 모드: 클립을 클릭하면 항목 참조 · 눈금자/빈 공간을 드래그하면 시간 범위 · 눈금자를 클릭하면 시점 — 참조가 채팅 입력란에 추가됩니다', + 'Ctrl/⌘+滚轮 缩放时间轴 · Alt+滚轮 缩放轨道高度': 'Ctrl/⌘+휠로 타임라인 확대/축소 · Alt+휠로 트랙 높이 확대/축소', + '视': 'V', + '音': 'A', + '字': '자', + '新建序列': '새 시퀀스', + '新建轨道': '새 트랙', + '视频轨道': '비디오 트랙', + '音频 / 音乐轨道': '오디오 / 음악 트랙', + '字幕轨道': '자막 트랙', + '请先新建字幕轨道': '먼저 자막 트랙을 만드세요', + '已存在': '있음', + '字幕轨道为空': '자막 트랙이 비어 있습니다', + '拖动调整字幕开始时间': '드래그하여 자막 시작 시간 조정', + '拖动调整字幕结束时间': '드래그하여 자막 종료 시간 조정', + '选择模式 (V):拖动移动 / 裁剪首尾': '선택 모드(V): 드래그하여 이동 / 양 끝 트리밍', + '修剪模式 (N):裁剪片段边缘,后续片段自动跟随合缝(波纹)': '트림 모드(N): 클립 가장자리를 트리밍하면 뒤의 클립이 따라와 간격을 메웁니다(리플)', + '比率拉伸:拖动片段首尾,保持源区间并改变播放速度': '속도 늘이기: 클립 가장자리를 드래그하면 소스 범위를 유지하면서 재생 속도를 변경합니다', + '退出比率拉伸,返回选择模式': '속도 늘이기를 종료하고 선택 모드로 돌아가기', + '刀片模式 (B):点击片段在该处切分': '블레이드 모드(B): 클립을 클릭하면 해당 위치에서 분할합니다', + '钢笔模式 (P):在选中片段上点击绘制关键帧(视觉片段=透明度,音频片段=音量;纵向=值,拖点改帧/值,右键删点)': '펜 모드(P): 선택한 클립을 클릭하여 키프레임 그리기(비주얼 클립 = 불투명도, 오디오 클립 = 볼륨, 세로 = 값, 점을 드래그하여 프레임/값 변경, 마우스 오른쪽 클릭으로 삭제)', + '在播放头切分选中片段 (C)': '재생 헤드에서 선택한 클립 분할(C)', + '插入落轨': '삽입 배치', + '覆盖落轨': '덮어쓰기 배치', + '检测选中片段的场景切点': '선택한 클립의 장면 전환 감지', + '选择一个视频片段后进行场景检测': '장면 전환을 감지할 비디오 클립을 선택하세요', + '跟踪选中视频中的目标(实验功能)': '선택한 비디오에서 대상 추적(실험 기능)', + '选择一个本机视频片段后进行运动跟踪': '모션 추적을 사용할 로컬 비디오 클립을 선택하세요', + '磁性吸附:开 (S)': '스냅: 켬(S)', + '磁性吸附:关 (S)': '스냅: 끔(S)', + '插入落轨:库素材/模板拖入时把后续片段后推(波纹插入)': '삽입 배치: 라이브러리 미디어/템플릿을 놓으면 뒤의 클립을 밀어냅니다(리플 삽입)', + '覆盖落轨:库素材/模板按帧位叠放,不推后续片段(默认)': '덮어쓰기 배치: 라이브러리 미디어/템플릿이 뒤의 클립을 밀지 않고 해당 프레임 위치에 놓입니다(기본값)', + '● 录音中,点击停止': '● 녹음 중, 클릭하여 중지', + '录音失败:{error}': '녹음 실패: {error}', + '录制旁白(麦克风 → 音频轨)': '내레이션 녹음(마이크 → 오디오 트랙)', + '录音中': '녹음 중', + '暂停 (空格)': '일시 정지(Space)', + '播放 (空格)': '재생(Space)', + '缩小时间轴 (⌘−)': '타임라인 축소(⌘−)', + '缩放时间轴': '타임라인 확대/축소', + '放大时间轴 (⌘+)': '타임라인 확대(⌘+)', + '适配视图 (⇧Z)': '화면에 맞추기(⇧Z)', + '画幅比例': '화면 비율', + '时间线帧率': '타임라인 프레임 레이트', + '帧率需在时间线添加内容前设置': '타임라인에 콘텐츠를 추가하기 전에 프레임 레이트를 설정하세요', + '内容适配': '콘텐츠 맞춤', + '留边': '레터박스', + '裁切': '자르기', + '字幕显示': '자막', + '字幕显示(字幕轨暂无内容;画面上的文字素材不属于字幕轨,转写或让 Agent 生成后即可显示)': '자막(아직 자막 트랙 데이터가 없습니다 — 화면의 텍스트 클립은 자막이 아닙니다. 전사하거나 에이전트에게 생성을 요청하세요)', + '开启': '켬', + '未开启': '끔', + '关闭': '닫기', + '全屏预览': '전체 화면 미리보기', + '场景检测': '장면 감지', + '本机分析,不上传素材': '로컬에서 분석 — 미디어를 업로드하지 않습니다', + '检测灵敏度': '감지 민감도', + '数值越低,检测到的切点越多': '값이 낮을수록 더 많은 장면 전환을 감지합니다', + '最短场景间隔': '최소 장면 간격', + '最多切点': '최대 컷 수', + '等待检测': '대기 중', + '分析素材信息': '미디어 분석 중', + '检测场景变化': '장면 전환 감지 중', + '整理检测结果': '결과 정리 중', + '检测完成': '감지 완료', + '检测失败': '감지 실패', + '已取消': '취소됨', + '尚未开始': '시작 안 함', + '已分析到 {time}': '{time}까지 분석됨', + '取消检测': '감지 취소', + '重新检测': '다시 확인', + '开始检测': '감지 시작', + '场景检测只支持已经保存到本机素材库的视频': '장면 감지는 로컬 미디어 라이브러리에 저장된 비디오만 지원합니다', + '当前轨道已锁定,无法应用场景检测结果': '현재 트랙이 잠겨 있어 장면 감지 결과를 적용할 수 없습니다', + '切点证据': '컷 근거', + '检测到 {all} 个切点,当前片段可应用 {mapped} 个': '{all}개의 컷이 감지되었으며, 현재 클립에 {mapped}개를 적용할 수 있습니다', + '检测完成后会显示切点前后的画面对比': '감지가 완료되면 컷 전후 프레임 비교가 표시됩니다', + '正在读取画面变化…': '화면 변화 분석 중…', + '调整参数后开始检测': '설정을 조정한 후 감지를 시작하세요', + '没有发现满足条件的场景切点': '설정 조건에 맞는 장면 전환이 없습니다', + '硬切': '컷', + '渐变': '트랜지션', + '切点前画面': '컷 이전 프레임', + '切点后画面': '컷 이후 프레임', + '之前': '이전', + '之后': '이후', + '不在当前裁切范围': '현재 트림 범위 밖', + '已添加场景标记': '장면 마커를 추가했습니다', + '已按场景切分片段': '장면 전환 지점에서 클립을 분할했습니다', + '轨道已锁定': '트랙이 잠겨 있습니다', + '添加场景标记': '장면 마커 추가', + '按场景切分': '장면 전환 지점에서 분할', + '运动跟踪': '모션 추적', + '实验功能': '실험 기능', + '在起始画面拖拽框选纹理清晰的目标;按住 Ctrl/⌘ 滚轮可缩放预览。分析后轨迹会显示在画面上。': '첫 프레임에서 질감이 뚜렷한 대상을 드래그해 선택하세요. Ctrl/⌘를 누른 채 스크롤하면 미리보기를 확대/축소할 수 있습니다. 분석 후 화면에 경로가 표시됩니다.', + '应用方式': '적용 방식', + '稳定所选视频画面': '선택한 비디오 안정화', + '让「{name}」跟随目标': '‘{name}’이(가) 대상을 따라가도록 설정', + '最低置信度': '최소 신뢰도', + '正在跟踪画面…': '프레임 추적 중…', + '跟踪分析完成': '추적 완료', + '等待框选目标': '대상 선택 대기 중', + '{n} 个有效跟踪点': '유효한 추적 지점 {n}개', + '平均置信度 {value}': '평균 신뢰도 {value}', + '目标连续丢失,已提前停止;低置信度帧不会写入关键帧。': '대상을 반복해서 놓쳐 추적을 조기에 중단했습니다. 신뢰도가 낮은 프레임은 키프레임으로 기록되지 않습니다.', + '目标轨道已锁定': '대상 트랙이 잠겨 있습니다', + '应用后会替换目标现有的 X/Y 关键帧;可在“变换”中继续手动修正。': '적용하면 대상의 기존 X/Y 키프레임이 대체됩니다. ‘변형’에서 직접 다듬을 수 있습니다.', + '已应用;一次撤销可还原全部跟踪关键帧': '적용했습니다. 실행 취소 한 번으로 이전 추적 키프레임을 모두 복원할 수 있습니다.', + '取消跟踪': '추적 취소', + '重新分析': '다시 분석', + '开始分析': '분석 시작', + '应用关键帧': '키프레임 적용', + '无法读取所选视频': '선택한 비디오를 읽을 수 없습니다', + '读取视频帧超时': '비디오 프레임 읽기 시간이 초과되었습니다', + '框选区域缺少纹理,请选择边缘和细节更明显的目标': '선택한 영역에 질감이 부족합니다. 가장자리와 디테일이 더 뚜렷한 대상을 선택하세요.', + '框选区域太小,请重新框选': '선택한 영역이 너무 작습니다. 더 크게 다시 선택하세요.', + '有效跟踪点与目标片段没有足够的重叠范围': '유효한 추적 지점과 대상 클립이 겹치는 시간이 충분하지 않습니다', + '{name}({id})': '{name} ({id})', + '主轨(闪避)': '기준 (더킹)', + '跟随(闪避)': '추종 (더킹)', + '主轨': '기준', + '跟随': '추종', + '显示轨道': '트랙 표시', + '隐藏轨道': '트랙 숨기기', + '取消静音': '음소거 해제', + '静音轨道': '트랙 음소거', + '轨道已静音': '트랙이 음소거되었습니다', + '解锁轨道': '트랙 잠금 해제', + '重命名轨道': '트랙 이름 변경', + '轨道名称(留空恢复默认)': '트랙 이름 (비워 두면 기본값으로 재설정)', + '音乐': '음악', + '锁定轨道(禁止移动 / 裁剪 / 删除 / 落轨)': '트랙 잠금 (이동 / 트림 / 삭제 / 드롭 불가)', + '关闭字幕': '자막 숨기기', + '开启字幕': '자막 표시', + '字幕样式与翻译': '자막 스타일 및 번역', + '自动闪避(混音角色:主轨说话 / 跟随背景乐)': '자동 더킹 (믹스 역할: 기준 음성 / 추종 음악)', + '删除轨道': '트랙 삭제', + '至少保留一条视频轨道': '비디오 트랙은 최소 하나 이상 있어야 합니다', + '请先解锁轨道': '먼저 트랙 잠금을 해제하세요', + '删除轨道会同时删除其中的片段、字幕和转场,确认继续吗?': '이 트랙을 삭제하면 포함된 클립, 자막, 트랜지션도 함께 삭제됩니다. 계속하시겠습니까?', + '自动闪避 · 混音角色': '자동 더킹 · 믹스 역할', + '不参与自动闪避': '자동 더킹에 참여하지 않음', + '主轨 · 说话': '기준 · 음성', + '说话时触发其它轨闪避': '음성이 나오면 다른 트랙 볼륨을 낮춤', + '跟随 · 背景音乐': '추종 · 배경 음악', + '主轨说话时自动压低': '기준 트랙에서 음성이 나오는 동안 자동으로 낮아짐', + '闪避强度(dB)': '더킹 강도 (dB)', + '特效×{n}': '효과 ×{n}', + '特效': '효과', + '缩放': '확대/축소', + '缩放 · {name}': '확대/축소 · {name}', + '关键帧缩放': '키프레임 확대/축소', + '人声': '음성', + '已应用人声隔离': '음성 분리를 적용했습니다', + '入场转场 · {name}': '시작 트랜지션 · {name}', + '透明度 {pct}% @ {sec}s — 拖动改帧/值 · 右键删除': '불투명도 {pct}% @ {sec}s — 드래그하여 프레임/값 변경 · 우클릭하여 삭제', + '音量 {pct}% @ {sec}s — 拖动改帧/值 · 右键删除': '볼륨 {pct}% @ {sec}s — 드래그하여 프레임/값 변경 · 우클릭하여 삭제', + 'AI 多机位同步': 'AI 멀티캠 동기화', + '复制': '복제', + '切分': '분할', + '已应用效果': '적용된 효과', + '已应用效果({n})': '적용된 효과 ({n})', + '点击移除': '클릭하여 제거', + '复制效果': '효과 복사', + '粘贴效果': '효과 붙여넣기', + '变速': '속도', + '变速({rate}×)': '속도 ({rate}×)', + '导出 MG 动画': 'MG 애니메이션 내보내기', + '转为视频': '비디오로 변환', + '删除': '삭제', + '删除({n})': '삭제 ({n})', + '波纹删除(合缝)': '리플 삭제 (간격 메우기)', + '波纹删除({n})': '리플 삭제 ({n})', + '转场 · {name}(入)': '트랜지션 · {name} (시작)', + '转场 · {name}(出)': '트랜지션 · {name} (끝)', + '关键帧': '키프레임', + '标记': '마커', + '批注…': '메모…', + '时长': '길이', + '秒': '초', + '(区间)': ' (구간)', + '(点)': ' (지점)', + '完成': '완료', + '入出点区间': '시작/종료 구간', + '入点 (I)': '시작 지점 (I)', + '出点 (O)': '종료 지점 (O)', + '单击切换 · 双击重命名': '클릭하여 전환 · 더블클릭하여 이름 변경', + '序列 {n}': '시퀀스 {n}', + '删除该序列': '이 시퀀스 삭제', + '+序列': '+ 시퀀스', + '复制当前序列': '현재 시퀀스 복제', + '竖屏副本': '세로 사본', + '把当前序列复制为 9:16 竖屏(长转短)': '현재 시퀀스를 9:16 세로 영상으로 복제 (롱폼→숏폼)', + '{kind}只能用在视频 / 图片片段上(GIF/MG 不走 GL 特效管线)': '{kind}은(는) 비디오 / 이미지 클립에만 적용할 수 있습니다 (GIF/MG는 GL 효과 파이프라인을 거치지 않음)', + '缩放只能用在画面片段上': '확대/축소는 화면 클립에만 적용할 수 있습니다', + '转场挂在两段的接缝上:请拖到「后一个」片段,它前面要有相邻同轨片段': '트랜지션은 두 클립의 경계에 적용됩니다. ‘뒤쪽’ 클립에 드롭하세요. 같은 트랙에서 바로 앞에 인접한 클립이 있어야 합니다', + '「{name}」只在视频/图片片段间有完整效果,MG/文字等片段上会显示为叠化': '‘{name}’은(는) 비디오/이미지 클립 사이에서만 완전히 적용되며, MG/텍스트 클립에서는 크로스 디졸브로 대체됩니다', + '插件转场「{name}」未安装或已卸载': '플러그인 트랜지션 ‘{name}’이(가) 설치되지 않았거나 제거되었습니다', + '多机位同步中…': '멀티캠 동기화 중…', + '正在做音频对齐…': '오디오 정렬 중…', + '对 {n} 个片段做音频对齐': '클립 {n}개 오디오 정렬', + '先框选 2 个及以上视频/音频片段': '먼저 비디오/오디오 클립을 2개 이상 선택하세요', + '多机位同步只支持带媒体的视频/音频片段': '멀티캠 동기화는 미디어가 있는 비디오/오디오 클립만 지원합니다', + '已同步 {n} 个片段': '클립 {n}개를 동기화했습니다', + '已同步 {n} 个片段,跳过 {m} 个': '클립 {n}개를 동기화하고 {m}개를 건너뛰었습니다', + '已经对齐(偏移小于 1 帧)': '이미 동기화되어 있습니다 (오프셋 1프레임 미만)', + '无法对齐所选片段(置信度过低或解码失败)': '선택한 클립을 정렬할 수 없습니다 (신뢰도 부족 또는 디코딩 실패)', + '多机位同步失败': '멀티캠 동기화 실패', + '取消同步锁定': '동기화 잠금 해제', + '取消链接音视频': '오디오·비디오 연결 해제', + '同步锁定所选片段': '선택한 클립 동기화 잠금', + '复制字幕': '자막 복사', + '多机位组 · {n} 机位 · {method}': '멀티캠 그룹 · 카메라 {n}대 · {method}', + '多机位组已保存({method})': '멀티캠 그룹을 저장했습니다 ({method})', + '多机位组已保存({method}),跳过 {m} 个': '멀티캠 그룹을 저장했습니다 ({method}), {m}개 건너뜀', + '字幕显示(暂无字幕或文字素材,先转写或让 Agent 生成)': '자막 표시 (자막이나 텍스트 미디어가 아직 없습니다. 먼저 전사하거나 에이전트에게 생성을 요청하세요)', + '字幕显示(画面有 {n} 个文字素材,无字幕轨数据;关闭会一并隐藏)': '자막 표시 (화면에 텍스트 미디어 {n}개, 자막 트랙 데이터 없음. 끄면 함께 숨겨집니다)', + '对 {n} 个片段按时间码、采集时钟或音频依次对齐': '타임코드, 촬영 시각 또는 오디오 순으로 클립 {n}개 정렬', + '已重新链接文件': '파일을 다시 연결했습니다', + '插入字幕': '자막 삽입', + '插入素材': '미디어 삽입', + '插入音频': '오디오 삽입', + '无法对齐所选片段(缺少时间码且音频置信度过低)': '선택한 클립을 정렬할 수 없습니다 (타임코드가 없고 오디오 신뢰도가 너무 낮음)', + '正在读取时间码、采集时钟或音频…': '타임코드, 촬영 시각 또는 오디오 읽는 중…', + '此类型没有可滑移的源区间': '이 유형에는 슬립할 수 있는 소스 구간이 없습니다', + '添加到 AI 对话框({n})': 'AI 채팅에 추가 ({n})', + '清空轨道': '트랙 비우기', + '清空轨道会删除其中的片段、字幕和转场,确认继续吗?': '트랙을 비우면 포함된 클립, 자막, 트랜지션이 삭제됩니다. 계속하시겠습니까?', + '源素材已变化,旧的人声隔离结果已丢弃。请重试。': '소스 미디어가 변경되어 이전 음성 분리 결과를 폐기했습니다. 다시 시도하세요.', + '滑移模式 (U):保持时间线位置和时长,仅拖动源素材区间': '슬립 모드 (U): 타임라인 위치와 길이는 유지하고 소스 구간만 드래그', + '移动字幕': '자막 이동', + '粘贴字幕': '자막 붙여넣기', + '翻译全部': '모두 번역', + '自动闪避': '자동 더킹', + '请重新选择同类型文件': '같은 유형의 파일을 다시 선택하세요', + '轨道菜单': '트랙 메뉴', + '返回{title}': '{title}(으)로 돌아가기', + '重新链接文件失败': '파일 다시 연결 실패', + '链接所选音视频': '선택한 오디오·비디오 연결', + '闭合缝隙': '간격 메우기', + '转场菜单': '트랜지션 메뉴', + '{n} 秒': '{n}초', + '删除转场': '트랜지션 제거', +} as Record; diff --git a/src/i18n/dict/ko/topbar.ts b/src/i18n/dict/ko/topbar.ts new file mode 100644 index 000000000..6bebe479e --- /dev/null +++ b/src/i18n/dict/ko/topbar.ts @@ -0,0 +1,20 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '切换界面语言': 'UI 언어 전환', + '返回工程列表': '프로젝트 목록으로 돌아가기', + '双击重命名': '두 번 클릭하여 이름 바꾸기', + '编辑快捷键': '단축키 편집', + '撤销': '실행 취소', + '重做': '다시 실행', + '设计风格(品牌)': '디자인 스타일 (브랜드)', + '历史版本': '버전 기록', + '切换面板布局': '패널 레이아웃 전환', + '导出 MP4': 'MP4 내보내기', + '导出中…': '내보내는 중…', + '导出': '내보내기', + '账户': '계정', + '窗口控制': '창 제어', + '关闭窗口': '창 닫기', + '最小化窗口': '창 최소화', + '缩放窗口': '창 확대/축소', +} as Record; diff --git a/src/i18n/dict/ko/transcript.ts b/src/i18n/dict/ko/transcript.ts new file mode 100644 index 000000000..e74528b8a --- /dev/null +++ b/src/i18n/dict/ko/transcript.ts @@ -0,0 +1,87 @@ +// KO dictionary (field fragmentation mirroring dict/en, key = Chinese original text). +export default { + '素材文件不可用,请在“我的素材”中重新链接后再转写': '미디어 파일을 사용할 수 없습니다. 전사하기 전에 ‘내 미디어’에서 다시 연결하세요.', + '无法连接转写服务,请检查网络和 AssemblyAI 配置后重试': '전사 서비스에 연결할 수 없습니다. 네트워크와 AssemblyAI 설정을 확인한 후 다시 시도하세요.', + '本地转写失败:模型未就绪或音频无法处理,请检查模型下载后重试': '로컬 전사 실패: 모델을 사용할 수 없거나 오디오를 처리할 수 없습니다. 모델 다운로드 상태를 확인한 후 다시 시도하세요.', + '本地转写失败:{detail}': '로컬 전사 실패: {detail}', + '桌面引擎的模型文件未下载,本次使用浏览器引擎': '데스크톱 엔진의 모델 파일이 다운로드되지 않아 이번에는 브라우저 엔진을 사용합니다', + '桌面原生推理不可用,已回退浏览器引擎': '데스크톱 네이티브 추론을 사용할 수 없어 브라우저 엔진으로 전환했습니다', + '桌面原生推理(whisper.cpp)未能完成转写:{reason}。回退到浏览器引擎需要 {model} 的 ONNX 模型文件,但尚未下载完整。请到 设置 → 本地模型 → 本地转写 下载该模型后重试。': '데스크톱 네이티브 추론(whisper.cpp)으로 전사를 완료하지 못했습니다: {reason}. 브라우저 엔진으로 전환하려면 {model}의 ONNX 모델 파일이 필요하지만 아직 모두 다운로드되지 않았습니다. 설정 → 로컬 모델 → 로컬 전사에서 모델을 다운로드한 후 다시 시도하세요.', + '本地转写模型 {model} 尚未下载:桌面引擎需要的 whisper.cpp 模型文件(GGML)和浏览器引擎需要的 ONNX 模型文件都未就绪。请到 设置 → 本地模型 → 本地转写 下载该模型后再试。': '로컬 전사 모델 {model}이(가) 다운로드되지 않았습니다. 데스크톱 엔진에 필요한 whisper.cpp 모델 파일(GGML)과 브라우저 엔진에 필요한 ONNX 모델 파일이 모두 준비되지 않았습니다. 설정 → 로컬 모델 → 로컬 전사에서 모델을 다운로드한 후 다시 시도하세요.', + '本地转写模型 {model} 的浏览器引擎文件(ONNX)未下载完整或校验失败。请到 设置 → 本地模型 → 本地转写 下载该模型后再试。': '로컬 전사 모델 {model}의 브라우저 엔진 파일(ONNX)이 불완전하거나 검증에 실패했습니다. 설정 → 로컬 모델 → 로컬 전사에서 모델을 다운로드한 후 다시 시도하세요.', + '{stage}失败:{detail}': '{stage} 실패: {detail}', + '音轨准备': '오디오 트랙 준비', + '音频解码': '오디오 디코딩', + '模型加载': '모델 로드', + '模型推理': '모델 추론', + '本地转写模型 {model} 超出了浏览器引擎(wasm)的内存上限。请到 设置 → 本地模型 → 本地转写 改选更小的模型(Base / Small),或开启「桌面原生推理加速」并下载该模型,改由没有此限制的 whisper.cpp 运行。': '로컬 전사 모델 {model}이(가) 브라우저 엔진(wasm)의 메모리 한도를 초과했습니다. 설정 → 로컬 모델 → 로컬 전사에서 더 작은 모델(Base / Small)을 선택하거나, ‘데스크톱 네이티브 추론 가속’을 켜고 이 모델을 다운로드하여 메모리 제한이 없는 whisper.cpp로 실행하세요.', + '本地转写模型 {model} 超出了浏览器引擎(wasm)的内存上限。请到 设置 → 本地模型 → 本地转写 改选更小的模型(Base / Small),或改用桌面版,由没有此限制的 whisper.cpp 原生运行。': '로컬 전사 모델 {model}이(가) 브라우저 엔진(wasm)의 메모리 한도를 초과했습니다. 설정 → 로컬 모델 → 로컬 전사에서 더 작은 모델(Base / Small)을 선택하거나, 메모리 제한 없이 whisper.cpp로 네이티브 실행되는 데스크톱 앱을 사용하세요.', + '停顿': '발화 사이 멈춤', + '段落视图': '단락 보기', + '片段视图': '세그먼트 보기', + '点词删除 = 剪掉那段音频': '단어를 클릭해 삭제 = 해당 오디오 잘라내기', + '先转写该轨音频': '먼저 이 트랙의 오디오를 전사하세요', + '编辑': '편집', + '导入 SRT': 'SRT 가져오기', + 'SRT 导入失败': 'SRT 가져오기 실패', + 'SRT 文件中没有有效字幕。': 'SRT 파일에서 유효한 자막을 찾지 못했습니다.', + '停顿时长': '발화 사이 멈춤 길이', + '去掉填充词(嗯 / 呃 / um…)': '군더더기 말 제거 (음 / 어 / um…)', + '已压缩 {count} 处长停顿到 {sec}s(约省 {saved}s)': '발화 사이의 긴 멈춤 {count}곳을 {sec}초로 줄였습니다 (약 {saved}초 단축)', + ' · 去填充词 {n}': ' · 군더더기 말 {n}개 제거', + '应用': '적용', + '转写轨道': '전사 트랙', + '时间线上还没有可转写的音视频轨': '타임라인에 전사할 수 있는 오디오 또는 비디오 트랙이 아직 없습니다', + '点词删除/恢复(当前段)。已删': '단어를 클릭해 삭제/복원 (현재 클립). 삭제한', + '词': '단어', + '还原全部': '모두 복원', + '选择模式:拖选一段词句作为引用(松开即添加到聊天)': '선택 모드: 단어를 드래그해 인용 (놓으면 채팅에 추가)', + '还没有可转写的轨道': '전사할 수 있는 트랙이 아직 없습니다', + '把口播 / 配音或带人声的视频加到时间线后,再打开文字稿。': '내레이션 / 보이스오버 또는 음성이 있는 비디오를 타임라인에 추가한 후 전사 텍스트를 여세요.', + '转写词级文字稿': '단어 단위 전사 텍스트 생성', + '本地转写未做说话人分离,全部内容归为同一说话人。': '로컬 전사는 화자를 분리하지 않으므로 모든 내용이 한 화자로 처리됩니다.', + '多语言词级转写 · 本地模型 · 该轨共 {n} 段会逐段转写(免费、离线、素材不出本机)。转写后可点词删减(删词=剪音频)。': '다국어 단어 단위 전사 · 온디바이스 모델 · 이 트랙의 클립 {n}개를 하나씩 전사합니다 (무료, 오프라인, 미디어가 이 기기를 벗어나지 않음). 전사 후 단어를 클릭해 잘라낼 수 있습니다 (단어 삭제 = 오디오 잘라내기).', + '多语言词级转写 · 说话人分离 · 该轨共 {n} 段会逐段上传。转写后可点词删减(删词=剪音频)。': '다국어 단어 단위 전사 · 화자 분리 · 이 트랙의 클립 {n}개를 하나씩 업로드합니다. 전사 후 단어를 클릭해 잘라낼 수 있습니다 (단어 삭제 = 오디오 잘라내기).', + '包含疑似背景音乐(已跳过 {n} 段)': '배경 음악으로 추정되는 클립 포함 ({n}개 건너뜀)', + '该轨只有背景音乐类素材。打开「包含疑似背景音乐」或换到配音轨。': '이 트랙에는 배경 음악 클립만 있습니다. ‘배경 음악으로 추정되는 클립 포함’을 켜거나 보이스오버 트랙으로 전환하세요.', + '转写中…': '전사 중…', + '转写 {alias}({n} 段)': '{alias} 전사 (클립 {n}개)', + '跳转到片段': '클립으로 이동', + ' · {n}词': ' · {n}단어', + ' · {n} 词': ' · {n}단어', + ' · 未转写': ' · 전사 안 됨', + '上一段': '이전 클립', + '下一段': '다음 클립', + '重新转写': '다시 전사', + '列出全部 {n} 段正文(默认只看当前段,避免列表过长)': '클립 {n}개 전체 표시 (기본적으로 목록이 길어지지 않도록 현재 클립만 표시)', + '拖动卡片以重排时间线该轨片段顺序': '카드를 드래그해 타임라인에서 이 트랙의 클립 순서 변경', + ' · 已重排语段': ' · 발화 순서 변경됨', + '尚未转写此段': '이 클립은 아직 전사되지 않았습니다', + '已转写 {done}/{total} 段': '클립 {done}/{total}개 전사 완료', + ' · 可点「重新转写」补全失败段': ' · ‘다시 전사’를 클릭해 실패한 클립 보완', + ' · 正文仅显示当前段': ' · 현재 클립만 표시 중', + '恢复此词': '이 단어 복원', + '删除此词': '이 단어 삭제', + '这段还没有转写文本。': '이 클립에는 아직 전사 텍스트가 없습니다.', + '拖动以重排语段(同步播放顺序)': '드래그해 발화 블록 순서 변경 (재생 순서도 함께 변경)', + '当前仅一段,无法重排': '블록이 하나뿐이라 순서를 바꿀 수 없습니다', + '气口 {clock}': '간격 {clock}', + '点击调整气口时长': '클릭하여 간격 길이 조정', + ' · 已删除': ' · 삭제됨', + '删除气口(压掉这段静音)': '간격 삭제 (무음 구간 제거)', + '恢复原始气口': '원래 간격 복원', + '恢复': '복원', + '原始 {clock}': '원래 {clock}', + '压到 0.2s': '최대 0.2초로 줄이기', + '压到 0.5s': '최대 0.5초로 줄이기', + '删气口': '간격 삭제', + '还原': '초기화', + '上传 {label}…': '{label} 업로드 중…', + '上传音频…': '오디오 업로드 중…', + '转写 {label}…': '{label} 전사 중…', + '({i}/{total}) 上传 {label}…': '({i}/{total}) {label} 업로드 중…', + '({i}/{total}) 转写 {label}…': '({i}/{total}) {label} 전사 중…', + '已完成 {ok}/{total} 段;失败:{fails}': '클립 {ok}/{total}개 완료, 실패: {fails}', + ' · 已失效': ' · 만료됨', + ' · 转写已失效,仅供查看': ' · 전사가 만료되어 보기만 가능', +} as Record; diff --git a/src/i18n/dictRegistry.ts b/src/i18n/dictRegistry.ts index 06110d95e..516aab070 100644 --- a/src/i18n/dictRegistry.ts +++ b/src/i18n/dictRegistry.ts @@ -1,5 +1,5 @@ -// The four locale dictionaries are ~560 kB of source. Importing them statically -// put all four in the entry chunk, so every user downloaded and parsed three +// The locale dictionaries are ~560 kB+ of source. Importing them statically +// put all of them in the entry chunk, so every user downloaded and parsed // languages they cannot read before the first frame. Each locale is fetched on // demand instead. // @@ -12,7 +12,7 @@ import type { Locale } from './locale'; export interface LocaleDicts { /** UI copy for the active locale. */ readonly ui: Record; - /** UI copy consulted when `ui` has no entry (Italian falls back to English). */ + /** UI copy consulted when `ui` has no entry (Italian and Korean fall back to English). */ readonly uiFallback: Record; /** Display names for **data** (template/sound/music names). */ readonly data: Record; @@ -51,6 +51,13 @@ async function fetchDicts(locale: Locale): Promise { ]); return { ui: ru.RU, uiFallback: EMPTY, data: enData.default, dataFallback: EMPTY }; } + if (locale === 'ko') { + const [ko, koData, en, enData] = await Promise.all([ + import('./dict/ko'), import('./dict/ko/templates-data'), + import('./dict/en'), import('./dict/en/templates-data'), + ]); + return { ui: ko.KO, uiFallback: en.EN, data: koData.default, dataFallback: enData.default }; + } const [it, itData, en, enData] = await Promise.all([ import('./dict/it'), import('./dict/it/templates-data'), import('./dict/en'), import('./dict/en/templates-data'), diff --git a/src/i18n/dictRegistry.verify.ts b/src/i18n/dictRegistry.verify.ts index 5c9686470..5e797fe99 100644 --- a/src/i18n/dictRegistry.verify.ts +++ b/src/i18n/dictRegistry.verify.ts @@ -1,8 +1,8 @@ // Locale dictionaries moved from static imports to a per-locale lazy fetch, so // t()/tData() now read a table that may not be loaded yet. This pins the lookup // semantics that were previously inlined in locale.ts, per language: -// t: zh → key · en → EN · it → IT then EN · ru → RU only (no EN fallback) -// tData: zh → ZH_DATA · en → EN_DATA · it → IT_DATA then EN_DATA · ru → EN_DATA +// t: zh → key · en → EN · it → IT then EN · ru → RU only (no EN fallback) · ko → KO then EN +// tData: zh → ZH_DATA · en → EN_DATA · it → IT_DATA then EN_DATA · ru → EN_DATA · ko → KO_DATA then EN_DATA // and the "never go blank" contract while a dictionary is still in flight. // npx tsx src/i18n/dictRegistry.verify.ts import assert from 'node:assert/strict'; @@ -21,9 +21,11 @@ const { localeDicts } = await import('./dictRegistry.ts'); const { EN } = await import('./dict/en'); const { IT } = await import('./dict/it'); const { RU } = await import('./dict/ru'); +const { KO } = await import('./dict/ko'); const { ZH_DATA } = await import('./dict/zh'); const EN_DATA = (await import('./dict/en/templates-data')).default; const IT_DATA = (await import('./dict/it/templates-data')).default; +const KO_DATA = (await import('./dict/ko/templates-data')).default; /** A key the reference dictionary translates and the compared one does not. */ function onlyIn(has: Record, lacks: Record): string { @@ -83,6 +85,22 @@ function onlyIn(has: Record, lacks: Record): str assert.equal(tData(dataKey), EN_DATA[dataKey], 'ru data names still read EN_DATA'); } +// ── ko: Korean first, English for anything not translated yet ─────────────── +{ + setLocale('ko'); + await ensureLocaleDict('ko'); + const korean = Object.keys(KO)[0]!; + assert.equal(t(korean), KO[korean], 'ko reads the Korean dictionary'); + const builtIn = Object.keys(ZH_DATA)[0]!; + assert.equal(tData(builtIn), KO_DATA[builtIn], 'ko translates English-key data names'); + const selfMade = Object.keys(EN_DATA)[0]!; + assert.equal(tData(selfMade), KO_DATA[selfMade], 'ko translates Chinese-key data names'); + // KO currently covers every EN key (ko/coverage.verify.ts), so pin the wiring: + // a key added to EN before Korean catches up must show English, not Chinese. + assert.equal(localeDicts('ko').uiFallback, EN, 'ko is wired to fall back to EN for UI copy'); + assert.equal(localeDicts('ko').dataFallback, EN_DATA, 'ko is wired to fall back to EN_DATA for data names'); +} + // ── zh: the key language needs no UI table, only data names ───────────────── { setLocale('zh'); diff --git a/src/i18n/locale.ts b/src/i18n/locale.ts index e15e1f1fa..ce35dc7c1 100644 --- a/src/i18n/locale.ts +++ b/src/i18n/locale.ts @@ -4,15 +4,15 @@ // Rules: Use useT() (subscription switching) in React components; pure helper modules can directly import { t } // — As long as the component that renders its output calls useT(), it will be recalculated when switching languages. // LLM interface (systemPrompt/tool ​​description/skill content) and persistent dynamic history tags do not enter i18n. -// Default language: the saved choice wins; otherwise the system language (zh/ru), and English for everything else. +// Default language: the saved choice wins; otherwise the system language (zh/it/ru/ko), and English for everything else. import { useSyncExternalStore } from 'react'; import { ensureLocaleDict, localeDictReady, localeDicts } from './dictRegistry'; export { ensureLocaleDict } from './dictRegistry'; -export type Locale = 'zh' | 'en' | 'it' | 'ru'; +export type Locale = 'zh' | 'en' | 'it' | 'ru' | 'ko'; -export const ALL_LOCALES: readonly Locale[] = ['zh', 'en', 'it', 'ru']; +export const ALL_LOCALES: readonly Locale[] = ['zh', 'en', 'it', 'ru', 'ko']; const STORAGE_KEY = 'cc.locale'; const DOCUMENT_LANG: Record = { @@ -20,6 +20,7 @@ const DOCUMENT_LANG: Record = { en: 'en', it: 'it', ru: 'ru', + ko: 'ko', }; function systemLocale(): Locale { @@ -28,6 +29,7 @@ function systemLocale(): Locale { if (tag.startsWith('zh')) return 'zh'; if (tag.startsWith('it')) return 'it'; if (tag.startsWith('ru')) return 'ru'; + if (tag.startsWith('ko')) return 'ko'; return 'en'; } catch { return 'en'; @@ -37,7 +39,7 @@ function systemLocale(): Locale { function readInitial(): Locale { try { const stored = localStorage.getItem(STORAGE_KEY); - if (stored === 'zh' || stored === 'en' || stored === 'it' || stored === 'ru') return stored; + if (stored === 'zh' || stored === 'en' || stored === 'it' || stored === 'ru' || stored === 'ko') return stored; } catch { // Private mode / storage disabled → system language below. } @@ -58,10 +60,11 @@ export function subscribeLocale(onChange: () => void): () => void { return () => { subscribers.delete(onChange); }; } -export function localeLanguageName(locale: Locale): 'Chinese' | 'English' | 'Italian' | 'Russian' { +export function localeLanguageName(locale: Locale): 'Chinese' | 'English' | 'Italian' | 'Russian' | 'Korean' { if (locale === 'zh') return 'Chinese'; if (locale === 'it') return 'Italian'; if (locale === 'ru') return 'Russian'; + if (locale === 'ko') return 'Korean'; return 'English'; } diff --git a/src/i18n/locale.verify.ts b/src/i18n/locale.verify.ts index ea402a37a..faeded522 100644 --- a/src/i18n/locale.verify.ts +++ b/src/i18n/locale.verify.ts @@ -21,5 +21,8 @@ assert.equal(documentElement.lang, 'it', 'the persisted locale must set the init setLocale('zh'); assert.equal(persistedLocale, 'zh'); assert.equal(documentElement.lang, 'zh-CN'); +setLocale('ko'); +assert.equal(persistedLocale, 'ko'); +assert.equal(documentElement.lang, 'ko'); console.log('locale.verify: persisted and changed locales update the document language');