diff --git a/frontend/scripts/check-i18n-parity.mjs b/frontend/scripts/check-i18n-parity.mjs index 02191c02e..c2cc2d418 100644 --- a/frontend/scripts/check-i18n-parity.mjs +++ b/frontend/scripts/check-i18n-parity.mjs @@ -285,6 +285,24 @@ const ZH_TW_COGNATES = [ 'EC984C,#6CD4BC,A66EB9,D87694', ]; +// Korean: script difference means almost nothing is identical. +// Allow loanwords/acronyms, format strings, and proper nouns that stay verbatim. +const KO_COGNATES = [ + 'OK', 'Bambu', 'N/A', + '({{count}}/8)', '(25%, 50%, 75%)', + 'Custom Headers (JSON)', + 'Box label (62 × 29 mm)', + 'Avery L7160 — A4 sheet (38.1 × 63.5 mm × 21)', + 'Avery 5160 — US Letter sheet (25.4 × 66.7 mm × 30)', + 'EC984C,#6CD4BC,A66EB9,D87694', + '{{weight}}g', // unit suffix format string + 'MakerWorld: {{designer}}', // brand + placeholder + 'email', // OIDC claim name placeholder + '{{printer}}: {{error}}', // pure placeholders + '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', // pure placeholders + 'Obico ML API URL', // product name (Obico) +]; + // Spanish cognates — words/phrases that are genuinely identical in Spanish. const ES_COGNATES = [ 'Error', 'Firmware', 'General', 'Control', 'Total', 'total', 'Material', @@ -306,6 +324,7 @@ const IDENTICAL_TO_EN_ALLOWED = { fr: new Set(FR_COGNATES), it: new Set(IT_COGNATES), ja: new Set(JA_COGNATES), + ko: new Set(KO_COGNATES), es: new Set(ES_COGNATES), 'pt-BR': new Set(PT_BR_COGNATES), 'zh-CN': new Set(ZH_CN_COGNATES), diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 83d022e1d..cf1252993 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -9,6 +9,7 @@ import es from './locales/es'; import fr from './locales/fr'; import ja from './locales/ja'; import it from './locales/it'; +import ko from './locales/ko'; import ptBR from './locales/pt-BR'; import zhCN from './locales/zh-CN'; import zhTW from './locales/zh-TW'; @@ -20,6 +21,7 @@ const resources = { fr: { translation: fr }, ja: { translation: ja }, it: { translation: it }, + ko: { translation: ko }, 'pt-BR': { translation: ptBR }, 'zh-CN': { translation: zhCN }, 'zh-TW': { translation: zhTW }, @@ -31,7 +33,7 @@ i18n .init({ resources, fallbackLng: 'en', - supportedLngs: ['en', 'de', 'es', 'fr', 'ja', 'it', 'pt-BR', 'zh-CN', 'zh-TW'], + supportedLngs: ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'pt-BR', 'zh-CN', 'zh-TW'], detection: { // Order of detection methods @@ -61,6 +63,7 @@ export const availableLanguages = [ { code: 'fr', name: 'French', nativeName: 'Français' }, { code: 'ja', name: 'Japanese', nativeName: '日本語' }, { code: 'it', name: 'Italian', nativeName: 'Italiano' }, + { code: 'ko', name: 'Korean', nativeName: '한국어' }, { code: 'pt-BR', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' }, { code: 'zh-CN', name: 'Chinese (Simplified)', nativeName: '简体中文' }, { code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '繁體中文' }, diff --git a/frontend/src/i18n/locales/ko.ts b/frontend/src/i18n/locales/ko.ts new file mode 100644 index 000000000..f3300429e --- /dev/null +++ b/frontend/src/i18n/locales/ko.ts @@ -0,0 +1,5725 @@ +export default { + nav: { + printers: '프린터', + archives: '아카이브', + queue: '대기열', + stats: '통계', + profiles: '프로필', + maintenance: '유지보수', + projects: '프로젝트', + inventory: '필라멘트', + files: '파일 관리자', + makerworld: 'MakerWorld', + notifications: '알림', + settings: '설정', + system: '시스템', + collapseSidebar: '사이드바 접기', + expandSidebar: '사이드바 펼치기', + update: '업데이트', + updateAvailable: '업데이트 가능: v{{version}}', + updateAvailableBanner: '버전 {{version}}이(가) 출시되었습니다!', + viewUpdate: '업데이트 보기', + viewOnGithub: 'GitHub에서 보기', + keyboardShortcuts: '키보드 단축키 (?)', + switchToLight: '라이트 모드로 전환', + switchToDark: '다크 모드로 전환', + switchToSystem: '기기 설정으로 전환', + smartSwitches: '스마트 스위치', + logout: '로그아웃', + installApp: '앱 설치', + installAppSuccess: 'Bambuddy가 설치되었습니다' + }, + common: { + save: '저장', + saving: '저장 중...', + cancel: '취소', + delete: '삭제', + edit: '편집', + add: '추가', + close: '닫기', + confirm: '확인', + loading: '로딩 중...', + error: '오류', + errorLoading: '데이터 로딩 오류', + retry: '재시도', + success: '성공', + warning: '경고', + enabled: '활성화됨', + disabled: '비활성화됨', + yes: '예', + no: '아니요', + on: '켜짐', + off: '꺼짐', + all: '전체', + none: '없음', + search: '검색', + filter: '필터', + sort: '정렬', + refresh: '새로고침', + download: '다운로드', + upload: '업로드', + uploading: '업로드 중...', + uploadFailed: '업로드 실패', + actions: '작업', + status: '상태', + name: '이름', + description: '설명', + date: '날짜', + time: '시간', + hours: '시간', + minutes: '분', + seconds: '초', + days: '일', + enable: '활성화', + disable: '비활성화', + permissions: '권한', + noPrinters: '등록된 프린터가 없습니다', + noData: '데이터가 없습니다', + linkNotFound: '링크를 찾을 수 없습니다', + required: '필수', + optional: '선택', + dismiss: '닫기', + apply: '적용', + reset: '초기화', + export: '내보내기', + import: '가져오기', + clear: '지우기', + selectAll: '전체 선택', + deselectAll: '전체 해제', + noChange: '— 변경 없음 —', + unchanged: '변경 없음', + unassigned: '미할당', + unknown: '알 수 없음', + unknownError: '알 수 없는 오류', + today: '오늘', + tomorrow: '내일', + asap: '즉시', + overdue: '기한 초과', + now: '지금', + collapse: '접기', + expand: '펼치기', + viewArchive: '아카이브 보기', + viewInFileManager: '파일 관리자에서 보기', + addedBy: '{{username}}님이 추가함', + prints: '인쇄', + more: '+{{count}}개 더', + ascending: '오름차순', + descending: '내림차순', + back: '뒤로', + copy: '복사', + copied: '복사됨!', + printer: '프린터', + remove: '제거', + type: '유형', + print: '인쇄', + rename: '이름 변경', + move: '이동', + create: '만들기', + duplicate: '복제', + left: '왼쪽', + right: '오른쪽' + }, + printers: { + title: '프린터', + addPrinter: '프린터 추가', + editPrinter: '프린터 편집', + deletePrinter: '프린터 삭제', + printerName: '프린터 이름', + serialNumber: '일련번호', + ipAddress: 'IP 주소 / 호스트명', + accessCode: '액세스 코드', + model: '모델', + nozzleCount: '노즐 수', + autoArchive: '자동 아카이브', + status: { + available: '사용 가능', + idle: '대기 중', + printing: '인쇄 중', + paused: '일시정지', + offline: '오프라인', + problem: '문제 발생', + error: '오류', + finished: '완료', + unknown: '알 수 없음' + }, + temperatures: { + nozzle: '노즐', + bed: '베드', + chamber: '챔버' + }, + progress: '{{percent}}% 완료', + timeRemaining: '{{time}} 남음', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + maintenanceOk: '유지보수 정상', + maintenanceWarning: '{{count}}개 경고', + maintenanceWarning_plural: '{{count}}개 경고', + maintenanceDue: '{{count}}개 예정', + maintenanceDue_plural: '{{count}}개 예정', + sort: { + name: '이름', + status: '상태', + model: '모델', + location: '위치', + ascending: '오름차순 정렬', + descending: '내림차순 정렬' + }, + cardSize: { + small: '작은 카드', + medium: '중간 카드', + large: '큰 카드', + extraLarge: '아주 큰 카드' + }, + hideOffline: '오프라인 숨기기', + nextAvailable: '다음 가용', + powerOn: '전원 켜기', + offlinePrintersWithPlugs: '스마트 플러그가 연결된 오프라인 프린터', + noPrintersConfigured: '아직 설정된 프린터가 없습니다', + search: '프린터 검색...', + noSearchResults: '검색 또는 필터 조건에 맞는 프린터가 없습니다', + filter: { + allStatuses: '모든 상태', + allLocations: '모든 위치' + }, + toolbar: { + filters: '필터', + view: '보기', + actions: '작업' + }, + readyToPrint: '인쇄 준비 완료', + external: '외부', + extL: '외부-L', + extR: '외부-R', + deleteArchives: '인쇄 아카이브 삭제', + noLabel: '라벨 없음', + printPreview: '인쇄 미리보기', + width: '너비', + height: '높이', + noObjectsFound: '객체를 찾을 수 없습니다', + objectsLoadedOnPrintStart: '인쇄 시작 시 객체가 로드됩니다', + willBeSkipped: '건너뛸 예정', + name: '이름', + serialCannotBeChanged: '일련번호는 변경할 수 없습니다', + locationHelp: '프린터 그룹화 및 대기열 작업 필터링에 사용됩니다', + wifiSignal: { + veryWeak: '매우 약함', + weak: '약함', + fair: '보통', + good: '좋음', + excellent: '매우 좋음' + }, + maintenanceUpToDate: '모든 유지보수 최신 상태 - 클릭하여 보기', + chamberLightOn: '챔버 조명 켜기', + chamberLightOff: '챔버 조명 끄기', + files: '파일', + browseFiles: '프린터 파일 탐색', + autoOffAfterPrint: '인쇄 후 자동 전원 끄기', + autoOffExecuted: '자동 끄기 실행됨 - 초기화하려면 프린터를 켜세요', + hmsErrors: 'HMS 오류', + viewHmsErrors: '{{count}}개 HMS 오류 보기', + resume: '재개', + pause: '일시정지', + stop: '정지', + camera: '카메라', + skipObject: '객체 건너뛰기', + reconnect: '재연결', + forceRefresh: '강제 새로고침', + forceRefreshSuccess: '새로고침 요청됨', + mqttDebug: 'MQTT 디버그', + printerInformation: '프린터 정보', + copyToClipboard: '복사', + copied: '복사됨!', + state: '상태', + wifiSignalLabel: 'WiFi 신호', + developerMode: '개발자 모드', + enabled: '활성화됨', + disabled: '비활성화됨', + addedOn: '추가됨', + sdCard: 'SD 카드', + inserted: '삽입됨', + notInserted: '삽입되지 않음', + totalPrintHours: '인쇄 시간', + activeNozzle: '활성: {{nozzle}} 노즐', + nozzleRack: '노즐 랙', + nozzleDocked: '도킹됨', + nozzleMounted: '장착됨', + nozzleActive: '활성', + nozzleIdle: '대기', + nozzleDiameter: '직경', + nozzleType: '유형', + nozzleStatus: '상태', + nozzleFilament: '필라멘트', + nozzleWear: '마모', + nozzleMaxTemp: '최대 온도', + nozzleSerial: '일련번호', + nozzleHardenedSteel: '경화강', + nozzleStainlessSteel: '스테인리스강', + nozzleTungstenCarbide: '텅스텐 카바이드', + nozzleFlow: '유량', + nozzleHighFlow: '고유량', + nozzleStandardFlow: '표준', + firmwareUpdate: '펌웨어 업데이트', + firmwareInstructions: '프린터 터치스크린에서', + firmwareNav: '이동', + settings: '설정', + firmware: '펌웨어', + discoverPrinters: '프린터 검색', + searching: '검색 중...', + manualEntry: '수동 입력', + addFromCloud: '클라우드에서 추가', + toast: { + printerDeleted: '프린터가 삭제되었습니다', + missingSpoolAssignment: '{{printer}}에서 인쇄가 시작되었습니다. 슬롯 할당 누락: {{slots}}', + printerAdded: '프린터가 추가되었습니다', + printerUpdated: '프린터가 업데이트되었습니다', + failedToDelete: '프린터 삭제 실패', + failedToAdd: '프린터 추가 실패', + failedToUpdate: '프린터 업데이트 실패', + commandSent: '명령이 전송되었습니다', + failedToSendCommand: '명령 전송 실패', + turnedOn: '{{name}} 켜짐', + failedToPowerOn: '{{name}} 전원 켜기 실패', + scriptTriggered: '스크립트가 실행되었습니다', + printStopped: '인쇄가 정지되었습니다', + printPaused: '인쇄가 일시정지되었습니다', + printResumed: '인쇄가 재개되었습니다', + referenceDeleted: '참조가 삭제되었습니다', + detectionAreaSaved: '감지 영역이 저장되었습니다', + failedToRunScript: '스크립트 실행 실패', + failedToStopPrint: '인쇄 정지 실패', + failedToPausePrint: '인쇄 일시정지 실패', + failedToResumePrint: '인쇄 재개 실패', + failedToControlChamberLight: '챔버 조명 제어 실패', + failedToSetSpeed: '인쇄 속도 설정 실패', + failedToUpdateSetting: '설정 업데이트 실패', + failedToSkipObjects: '객체 건너뛰기 실패', + failedToRereadRfid: 'RFID 재읽기 실패', + failedToCheckPlate: '플레이트 확인 실패', + failedToUpdateLabel: '라벨 업데이트 실패', + failedToDeleteReference: '참조 삭제 실패', + failedToSaveDetectionArea: '감지 영역 저장 실패', + plateCheckEnabled: '플레이트 확인 활성화됨', + plateCheckDisabled: '플레이트 확인 비활성화됨', + calibrationSaved: '캘리브레이션이 저장되었습니다!', + calibrationFailed: '캘리브레이션 실패', + rfidRereadInitiated: 'RFID 재읽기가 시작되었습니다', + loadInitiated: '필라멘트 로딩 중…', + unloadInitiated: '필라멘트 언로딩 중…', + failedToLoad: '필라멘트 로드 실패', + failedToUnload: '필라멘트 언로드 실패', + connectionFailedNotAdded: '프린터에 연결할 수 없습니다. IP, 시리얼 번호, 액세스 코드를 확인하고 LAN 전용 모드가 켜져 있는지 확인하세요. 프린터가 추가되지 않았습니다.' + }, + connection: { + connected: '연결됨', + offline: '오프라인' + }, + plateStatus: { + markCleared: '플레이트 비움으로 표시', + cleared: '플레이트 비워짐', + notCleared: '플레이트 미비움', + inUse: '플레이트 사용 중' + }, + queue: { + inQueue: '대기열에 {{count}}개', + inQueue_plural: '대기열에 {{count}}개' + }, + controls: '제어', + rfid: { + reread: 'RFID 재읽기' + }, + ams: { + load: '로드', + unload: '언로드' + }, + bedJog: { + title: '빌드 플레이트 이동', + bed: '베드', + step: '이동 거리 (mm)', + up: '플레이트 위로', + down: '플레이트 아래로', + disabledWhilePrinting: '인쇄 중 비활성화됨', + notHomedTitle: '프린터 홈 설정 필요', + notHomedMessage: '마지막 인쇄 이후 홈 설정이 되지 않았습니다. 안전한 위치 지정을 위해 자동 홈 설정을 먼저 실행하거나, 그냥 이동하세요 — 소프트 엔드스톱이 무시됩니다.', + homeZ: '자동 홈 설정', + moveAnyway: '그냥 이동', + homingStarted: '프린터 자동 홈 설정 중…' + }, + permission: { + noAdd: '프린터를 추가할 권한이 없습니다', + noEdit: '프린터를 편집할 권한이 없습니다', + noDelete: '프린터를 삭제할 권한이 없습니다', + noControl: '프린터를 제어할 권한이 없습니다', + noFiles: '프린터 파일에 접근할 권한이 없습니다', + noAmsRfid: 'AMS RFID를 재읽기할 권한이 없습니다', + noSmartPlugControl: '스마트 플러그를 제어할 권한이 없습니다', + noCamera: '카메라를 볼 권한이 없습니다' + }, + modal: { + addTitle: '프린터 추가', + editTitle: '프린터 편집', + myPrinter: '내 프린터', + selectModel: '모델 선택...', + locationGroup: '위치 / 그룹 (선택사항)', + locationPlaceholder: '예: 작업실, 사무실, 지하실', + autoArchiveLabel: '완료된 인쇄 자동 아카이브', + fromPrinterSettings: '프린터 설정에서', + modelOptional: '모델 (선택사항)', + saveChanges: '변경사항 저장' + }, + skipObjects: { + tooltip: '객체 건너뛰기', + onlyWhilePrinting: '객체 건너뛰기 (인쇄 중에만)', + requiresMultiple: '객체 건너뛰기 (2개 이상 필요)', + title: '객체 건너뛰기', + matchIdsInfo: '프린터 화면의 ID와 일치', + printerShowsIds: '프린터 화면에서 빌드 플레이트의 객체 ID를 표시합니다', + skipSelected: '선택 항목 건너뛰기', + skipping: '건너뛰는 중...', + noObjectsSelected: '선택된 객체 없음', + selectObjectsToSkip: '현재 인쇄에서 건너뛸 객체를 선택하세요', + skipped: '건너뜀', + objectsSkipped: '객체가 건너뛰어졌습니다', + activeCount: '{{count}}개 활성', + waitForLayer: '객체를 건너뛰려면 2층 이상을 기다리세요 (현재 {{layer}}층)', + skip: '건너뛰기', + confirmTitle: '객체를 건너뛰시겠습니까?', + confirmMessage: '\"{{name}}\"을(를) 건너뛰시겠습니까? 이 작업은 취소할 수 없습니다.' + }, + confirm: { + deleteTitle: '프린터 삭제', + deleteMessage: '\"{{name}}\"을(를) 삭제하시겠습니까? 모든 연결 설정이 제거됩니다.', + deleteArchivesNote: '이 프린터의 모든 인쇄 기록이 영구적으로 삭제됩니다.', + keepArchivesNote: '인쇄 기록은 유지되지만 이 프린터와 연결이 해제됩니다.', + stopTitle: '인쇄 정지', + stopMessage: '\"{{name}}\"의 현재 인쇄를 정지하시겠습니까? 인쇄 작업이 취소됩니다.', + stopButton: '인쇄 정지', + pauseTitle: '인쇄 일시정지', + pauseMessage: '\"{{name}}\"의 현재 인쇄를 일시정지하시겠습니까?', + pauseButton: '인쇄 일시정지', + resumeTitle: '인쇄 재개', + resumeMessage: '\"{{name}}\"의 인쇄를 재개하시겠습니까?', + resumeButton: '인쇄 재개', + powerOnTitle: '프린터 전원 켜기', + powerOnMessage: '\"{{name}}\"의 전원을 켜시겠습니까?', + powerOnButton: '전원 켜기', + powerOffTitle: '프린터 전원 끄기', + powerOffMessage: '\"{{name}}\"의 전원을 끄시겠습니까?', + powerOffWarning: '경고: \"{{name}}\"이(가) 현재 인쇄 중입니다! 전원을 끄시겠습니까? 인쇄가 중단되고 프린터가 손상될 수 있습니다.', + powerOffButton: '전원 끄기', + haToggleTitle: '\"{{name}}\" 토글', + haToggleMessage: 'Home Assistant 엔티티 {{entity}}를 토글하시겠습니까? 현재 켜져 있으면 전원이 꺼질 수 있습니다.', + haToggleWarning: '경고: \"{{name}}\"이(가) 현재 인쇄 중입니다! {{entity}}를 토글하면 전원이 차단되어 인쇄가 중단될 수 있습니다. 계속하시겠습니까?', + haToggleButton: '토글' + }, + bulk: { + select: '선택', + selectAll: '전체 선택', + selectByLocation: '위치별 선택', + selected: '{{count}}개 선택됨', + actions: { + stop: '정지', + pause: '일시정지', + resume: '재개', + clearPlate: '베드 비우기', + clearHMS: '알림 지우기' + }, + confirm: { + stopTitle: '{{count}}개 인쇄 정지', + stopMessage: '{{count}}개 프린터의 활성 인쇄를 취소합니다. 이 작업은 취소할 수 없습니다.', + stopButton: '모두 정지', + pauseTitle: '{{count}}개 인쇄 일시정지', + pauseMessage: '{{count}}개 프린터의 활성 인쇄를 일시정지합니다.', + pauseButton: '모두 일시정지', + clearPlateTitle: '{{count}}개 인쇄 베드 비우기', + clearPlateMessage: '{{count}}개 프린터의 인쇄 베드를 비우고 대기열 작업을 시작할 수 있습니다.', + clearPlateButton: '모두 비우기' + }, + success: '{{count}}개 프린터에서 {{action}} 완료', + partial: '{{succeeded}}개 성공, {{failed}}개 실패', + noneApplicable: '선택된 프린터 중 이 작업에 적합한 상태의 프린터가 없습니다', + selectByState: '상태별 선택' + }, + discovery: { + title: '프린터 검색', + searching: '검색 중...', + scanning: '스캔 중...', + scanProgress: '스캔 중... {{scanned}}/{{total}}', + foundPrinters: '{{count}}개 프린터 발견', + noPrintersFound: '프린터를 찾을 수 없습니다', + noPrintersFoundSubnet: '지정된 서브넷에서 프린터를 찾을 수 없습니다.', + noPrintersFoundNetwork: '네트워크에서 프린터를 찾을 수 없습니다.', + allConfigured: '검색된 모든 프린터가 이미 설정되어 있습니다.', + alreadyAdded: '이미 추가됨', + select: '선택', + manualEntry: '수동 입력', + addFromCloud: '클라우드에서 추가', + subnetToScan: '스캔할 서브넷', + dockerNote: 'Docker가 감지되었습니다. CIDR 표기법으로 프린터의 서브넷을 입력하세요. docker-compose.yml에 network_mode: host가 필요합니다.', + scanSubnet: '서브넷에서 프린터 스캔', + discoverNetwork: '네트워크에서 프린터 검색', + scanningSubnet: 'Bambu 프린터를 위해 서브넷 스캔 중...', + scanningNetwork: '네트워크 스캔 중...', + serialRequired: '일련번호 필수', + unknown: '알 수 없음', + failedToStart: '검색 시작 실패' + }, + drying: { + start: '건조 시작', + stop: '건조 정지', + temperature: '온도', + duration: '시간', + hours: '시간', + timeRemaining: '{{time}} 남음', + active: '건조 중', + notSupported: '건조 지원 안 됨', + powerRequired: '건조를 활성화하려면 AMS 전원 어댑터를 연결하세요', + startingDrying: '건조 시작 중...', + stoppingDrying: '건조 정지 중...', + rotateTray: '건조 중 스풀 회전' + }, + filaments: '필라멘트', + openCameraOverlay: '카메라 오버레이 열기', + openCameraWindow: '새 창에서 카메라 열기', + firmwareUpdateAvailable: '펌웨어 업데이트 가능: {{current}} → {{latest}}', + firmwareUpToDate: '펌웨어 {{version}} — 최신 상태', + firmwareUpdateButton: '업데이트', + plateDetection: { + noPermission: '프린터를 업데이트할 권한이 없습니다', + enabledClick: '플레이트 확인 활성화됨 - 클릭하여 비활성화', + disabledClick: '플레이트 확인 비활성화됨 - 클릭하여 활성화', + manageCalibration: '플레이트 감지 캘리브레이션 관리', + calibrationRequired: '캘리브레이션 필요', + calibrationInstructions: '빌드 플레이트가 완전히 비어 있는지 확인한 후 캘리브레이션을 클릭하세요.', + calibrationDescription: '캘리브레이션은 빈 플레이트의 참조 이미지를 캡처합니다. 이후 확인 시 이 참조와 비교하여 객체를 감지합니다.', + calibrationTip: '팁: 다른 플레이트에 대해 최대 5개의 캘리브레이션을 저장할 수 있습니다. 확인 시 시스템이 자동으로 가장 잘 맞는 것을 사용합니다.', + plateEmpty: '플레이트가 비어 있는 것으로 보입니다', + objectsDetected: '플레이트에 객체가 감지되었습니다', + confidence: '신뢰도', + difference: '차이', + analysisPreview: '분석 미리보기:', + analysisLegend: '초록 박스 = 감지 영역, 빨간 오버레이 = 캘리브레이션과의 차이', + savedReferences: '저장된 참조 ({{count}}/{{max}})', + deleteReference: '참조 삭제', + labelPlaceholder: '라벨...', + clickToEdit: '{{label}} - 클릭하여 편집', + clickToAddLabel: '클릭하여 라벨 추가' + }, + speed: { + title: '인쇄 속도', + silent: '조용함 (50%)', + standard: '표준 (100%)', + sport: '스포츠 (124%)', + ludicrous: '루디크러스 (166%)' + }, + airduct: { + title: '에어덕트 모드', + cooling: '냉각', + heating: '가열' + }, + noSdCard: 'SD 없음', + door: { + open: '열림', + closed: '닫힘' + }, + fans: { + partCooling: '파트 냉각 팬', + auxiliary: '보조 팬', + chamber: '챔버 팬' + }, + clickToViewHmsErrors: 'HMS 오류 보기 클릭', + estimatedCompletion: '예상 완료 시간', + plateNumber: '플레이트 {{number}}', + slotOptions: '슬롯 옵션', + amsPopup: { + friendlyName: 'AMS 이름', + friendlyNamePlaceholder: '예: AMS 친숙한 이름', + serialNumber: '일련번호', + firmwareVersion: '펌웨어', + save: '저장', + clear: '지우기', + noEditPermission: 'AMS 유닛 이름을 변경할 권한이 없습니다' + }, + firmwareModal: { + title: '펌웨어 업데이트', + titleUpToDate: '펌웨어 정보', + currentVersion: '현재:', + latestVersion: '최신:', + releaseNotes: '릴리스 노트', + checkingPrereqs: '전제 조건 확인 중...', + sdCardReady: 'SD 카드 준비됨. 아래를 클릭하여 펌웨어를 업로드하세요.', + uploadedSuccess: 'SD 카드에 펌웨어가 업로드되었습니다!', + applyInstructions: '프린터에서 업데이트를 적용하려면:', + step1: '프린터 터치스크린에서 설정으로 이동하세요', + step2: '펌웨어로 이동하세요', + step3: 'SD 카드에서 업데이트를 선택하세요', + step4: '업데이트에 10-20분이 소요됩니다', + done: '완료', + starting: '시작 중...', + uploadFirmware: '펌웨어 업로드', + uploadFailed: '업로드 시작 실패: {{error}}', + uploadedToast: '펌웨어 업로드됨! 프린터 화면에서 업데이트를 시작하세요.', + availableVersions: '사용 가능한 버전', + usable: '사용 가능', + unavailable: '사용 불가', + installed: '설치됨', + newerBadge: '최신', + olderBadge: '이전', + currentBadge: '현재' + }, + accessCodePlaceholder: '현재 값을 유지하려면 비워두세요', + roi: { + title: '감지 영역 (ROI)', + xStart: 'X 시작', + yStart: 'Y 시작', + width: '너비', + height: '높이', + instruction: '빌드 플레이트에 집중할 감지 영역을 조정하세요. 미리보기의 초록 박스가 현재 영역을 표시합니다.' + }, + developerModeWarning: '개발자 LAN 모드가 활성화되지 않음: {{names}}. 일부 기능이 작동하지 않을 수 있습니다.', + howToEnable: '활성화 방법', + incompatibleFile: '이 파일은 {{slicedFor}}용으로 슬라이싱되었지만, 이 프린터는 {{printerModel}}입니다', + dropNotPrintable: '.gcode 및 .gcode.3mf 파일만 인쇄할 수 있습니다', + dropToPrint: '놓아서 인쇄', + cannotPrint: '프린터 사용 중', + addPreflight: { + checking: '연결 확인 중...', + warning: '일부 연결 확인이 실패했습니다. 이 프린터가 오프라인으로 표시될 수 있습니다. 아래 항목을 검토하고 수정하거나 그냥 저장하세요.', + back: '뒤로', + saveAnyway: '그냥 저장' + } + }, + archives: { + title: '인쇄 아카이브', + searchPlaceholder: '아카이브 검색...', + filterByPrinter: '프린터별 필터', + filterByStatus: '상태별 필터', + sortBy: '정렬 기준', + sortNewest: '최신순', + sortOldest: '오래된순', + sortName: '이름', + sortDuration: '시간', + sortLargest: '큰 것 먼저', + sortSmallest: '작은 것 먼저', + sortSize: '크기', + noArchives: '아카이브를 찾을 수 없습니다', + noArchivesSearch: '검색 조건에 맞는 아카이브가 없습니다', + originalPrintNotVisible: '원본 인쇄가 보이지 않음 - 필터를 지워보세요', + noArchivesYet: '아직 아카이브가 없습니다', + prints: '인쇄', + pagination: { + showing: '표시 중', + to: '~', + of: '/', + show: '표시', + page: '페이지', + all: '전체' + }, + loadingArchives: '아카이브 로딩 중...', + releaseToUpload: '놓아서 업로드', + showAll: '모두 보기', + showFavoritesOnly: '즐겨찾기만 보기', + gridView: '그리드 보기', + listView: '목록 보기', + calendarView: '달력 보기', + logView: '인쇄 로그', + manageTags: '태그 관리', + showFailedPrints: '실패한 인쇄 표시', + hideFailedPrints: '실패한 인쇄 숨기기', + hideDuplicates: '중복 숨기기', + viewOriginalPrint: '원본 인쇄 보기 클릭 (#{{id}})', + printTime: '인쇄 시간', + filamentUsed: '사용된 필라멘트', + cost: '비용', + reprint: '재인쇄', + preview: '미리보기', + deleteArchive: '아카이브 삭제', + deleteConfirm: '이 아카이브를 삭제하시겠습니까?', + favorite: '즐겨찾기', + unfavorite: '즐겨찾기에서 제거', + viewDetails: '상세 보기', + status: { + completed: '완료', + failed: '실패', + stopped: '정지됨' + }, + toast: { + source3mfAttached: '소스 3MF 첨부됨: {{filename}}', + failedUploadSource3mf: '소스 3MF 업로드 실패', + source3mfRemoved: '소스 3MF 제거됨', + failedRemoveSource3mf: '소스 3MF 제거 실패', + f3dAttached: 'F3D 첨부됨: {{filename}}', + failedUploadF3d: 'F3D 업로드 실패', + f3dRemoved: 'F3D 제거됨', + failedRemoveF3d: 'F3D 제거 실패', + timelapseAttached: '타임랩스 첨부됨: {{filename}}', + timelapseAlreadyAttached: '타임랩스가 이미 첨부됨', + noMatchingTimelapse: '일치하는 타임랩스를 찾을 수 없습니다', + failedScanTimelapse: '타임랩스 스캔 실패', + failedAttachTimelapse: '타임랩스 첨부 실패', + timelapseRemoved: '타임랩스 제거됨', + failedRemoveTimelapse: '타임랩스 제거 실패', + timelapseUploaded: '타임랩스 업로드됨: {{filename}}', + failedUploadTimelapse: '타임랩스 업로드 실패', + archiveDeleted: '아카이브가 삭제되었습니다', + failedDeleteArchive: '아카이브 삭제 실패', + addedToFavorites: '즐겨찾기에 추가됨', + removedFromFavorites: '즐겨찾기에서 제거됨', + projectUpdated: '프로젝트가 업데이트되었습니다', + failedUpdateProject: '프로젝트 업데이트 실패', + linkCopied: '링크가 클립보드에 복사되었습니다', + failedCopyLink: '링크 복사 실패', + photoDeleted: '사진이 삭제되었습니다', + failedDeletePhoto: '사진 삭제 실패', + failedDeleteArchives: '아카이브 삭제 실패', + failedUpdateFavorites: '즐겨찾기 업데이트 실패', + exportDownloaded: '내보내기 다운로드됨', + exportFailed: '내보내기 실패' + }, + menu: { + print: '인쇄', + schedule: '예약', + openInBambuStudio: '슬라이서에서 열기', + slice: '슬라이스', + externalLink: '외부 링크', + viewOnMakerWorld: 'MakerWorld에서 보기', + preview3d: '3D 미리보기', + viewTimelapse: '타임랩스 보기', + scanForTimelapse: '타임랩스 검색', + uploadTimelapse: '타임랩스 업로드', + removeTimelapse: '타임랩스 제거', + downloadSource3mf: '소스 3MF 다운로드', + uploadSource3mf: '소스 3MF 업로드', + replaceSource3mf: '소스 3MF 교체', + removeSource3mf: '소스 3MF 제거', + uploadF3d: 'F3D 업로드', + replaceF3d: 'F3D 교체', + downloadF3d: 'F3D 다운로드', + removeF3d: 'F3D 제거', + download: '다운로드', + copyDownloadLink: '다운로드 링크 복사', + qrCode: 'QR 코드', + viewPhotos: '사진 보기', + viewPhotosCount: '사진 보기 ({{count}})', + projectPage: '프로젝트 페이지', + addToFavorites: '즐겨찾기에 추가', + removeFromFavorites: '즐겨찾기에서 제거', + edit: '편집', + goToProject: '프로젝트로 이동: {{name}}', + addToProject: '프로젝트에 추가', + removeFromProject: '프로젝트에서 제거', + loading: '로딩 중...', + noProjectsAvailable: '사용 가능한 프로젝트 없음', + searchProjects: '프로젝트 검색…', + select: '선택', + deselect: '선택 해제', + delete: '삭제', + printLog: '인쇄 기록' + }, + permission: { + noReprint: '이 아카이브를 재인쇄할 권한이 없습니다', + noAddToQueue: '대기열에 추가할 권한이 없습니다', + noUpdateArchives: '아카이브를 업데이트할 권한이 없습니다', + noUploadFiles: '파일을 업로드할 권한이 없습니다', + noDownload: '아카이브를 다운로드할 권한이 없습니다', + noCopyLink: '다운로드 링크를 복사할 권한이 없습니다', + noDelete: '이 아카이브를 삭제할 권한이 없습니다', + noCreate: '아카이브를 만들 권한이 없습니다' + }, + platePicker: { + title: '미리 볼 플레이트 선택', + hint: '이 아카이브에는 여러 플레이트가 있습니다. G코드 뷰어에서 열 플레이트를 선택하세요.', + plateLabel: '플레이트 {{index}}', + objectCount: '{{count}}개 객체', + objectCount_plural: '{{count}}개 객체', + noGcode: '이 아카이브에는 미리 볼 슬라이싱된 G코드가 없습니다. Bambu Studio에서 먼저 슬라이싱하세요.' + }, + card: { + previousPlate: '이전 플레이트', + nextPlate: '다음 플레이트', + plateNumber: '플레이트 {{index}}', + moreOptions: '더 많은 옵션은 우클릭', + addToFavorites: '즐겨찾기에 추가', + removeFromFavorites: '즐겨찾기에서 제거', + cancelled: '취소됨', + failed: '실패', + duplicate: '중복', + duplicateTitle: '이 모델은 이전에 인쇄된 적이 있습니다', + openSource3mf: 'Bambu Studio에서 소스 3MF 열기 (더 많은 옵션은 우클릭)', + downloadF3d: 'Fusion 360 디자인 파일 다운로드', + viewTimelapse: '타임랩스 보기', + viewPhoto: '사진 1장 보기', + viewPhotos: '사진 {{count}}장 보기', + openFolder: '폴더 열기: {{name}}', + slicedFile: '슬라이싱된 파일 - 인쇄 준비 완료', + sourceFile: '소스 파일만 - AMS 매핑 없음', + gcode: 'GCODE', + source: '소스', + project: '프로젝트: {{name}}', + estimated: '예상: {{time}}', + actual: '실제: {{time}}', + accuracy: '정확도: {{percent}}%', + filament: '{{weight}}g', + layer: '{{count}}층', + layers: '{{count}}층', + object: '{{count}}개 객체', + objects: '{{count}}개 객체', + slicedFor: '{{model}}용으로 슬라이싱됨', + uploadedBy: '업로드한 사용자', + noPermissionReprint: '재인쇄 권한이 없습니다', + noFileForReprint: '3MF 파일 없음 — 인쇄 기록 시 프린터에서 파일을 다운로드할 수 없었습니다', + noPermissionEdit: '아카이브를 편집할 권한이 없습니다', + noPermissionDelete: '아카이브를 삭제할 권한이 없습니다', + reprint: '재인쇄', + schedulePrint: '인쇄 예약', + schedule: '예약', + openInBambuStudio: '슬라이서에서 열기', + openInBambuStudioToSlice: '슬라이스하려면 슬라이서에서 열기', + slice: '슬라이스', + externalLink: '외부 링크', + makerWorld: 'MakerWorld: {{designer}}', + viewProject: '프로젝트 보기', + noExternalLink: '외부 링크 없음', + preview3d: '3D 미리보기', + download: '다운로드', + edit: '편집', + delete: '삭제', + runsBadge: '{{count}}회 인쇄', + runsBadgeTitle: '총 {{count}}회 인쇄 — {{successful}}회 성공, {{failed}}회 실패. 전체 인쇄 기록을 보려면 클릭하세요.' + }, + modal: { + deleteArchive: '아카이브 삭제', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + deleteButton: '삭제', + removeSource3mf: '소스 3MF 제거', + removeSource3mfConfirm: '\"{{name}}\"에서 소스 3MF 파일을 제거하시겠습니까? 원본 슬라이서 프로젝트 파일이 삭제됩니다.', + removeButton: '제거', + removeF3d: 'F3D 제거', + removeF3dConfirm: '\"{{name}}\"에서 Fusion 360 디자인 파일을 제거하시겠습니까?', + removeTimelapse: '타임랩스 제거', + removeTimelapseConfirm: '\"{{name}}\"에서 타임랩스 영상을 제거하시겠습니까?', + timelapse: '{{name}} - 타임랩스', + selectTimelapse: '타임랩스 선택', + selectTimelapseDesc: '자동 일치 항목 없음. 이 인쇄의 타임랩스를 선택하세요:', + deleteArchives: '아카이브 삭제', + deleteArchivesConfirm: '{{count}}개 아카이브를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + deleteCount: '{{count}}개 삭제', + deletePurgeStats: '빠른 통계에서도 이 인쇄 항목 제거 (필라멘트, 시간, 비용, 에너지)' + }, + page: { + title: '아카이브', + printsCount: '{{total}}개 중 {{filtered}}개 인쇄', + dropFilesHere: '.3mf 파일을 여기에 놓으세요', + releaseToUpload: '놓아서 업로드', + only3mfSupported: '.3mf 파일만 지원됩니다', + close: '닫기', + selected: '{{count}}개 선택됨', + selectAll: '전체 선택', + tags: '태그', + project: '프로젝트', + favorite: '즐겨찾기', + delete: '삭제', + toggledFavorites: '{{count}}개 아카이브의 즐겨찾기가 변경됨', + failedUpdateFavorites: '즐겨찾기 업데이트 실패', + archivesDeleted: '{{count}}개 아카이브가 삭제됨', + failedDeleteArchives: '아카이브 삭제 실패', + photoDeleted: '사진이 삭제됨', + failedDeletePhoto: '사진 삭제 실패' + }, + list: { + name: '이름', + printer: '프린터', + date: '날짜', + size: '크기', + actions: '작업', + hasTimelapse: '타임랩스 있음' + }, + log: { + date: '날짜', + printName: '인쇄 이름', + printer: '프린터', + user: '사용자', + status: '상태', + duration: '소요 시간', + filament: '필라멘트', + allPrinters: '모든 프린터', + allUsers: '모든 사용자', + allStatuses: '모든 상태', + cancelled: '취소됨', + skipped: '건너뜀', + dateFrom: '시작', + dateTo: '종료', + noEntries: '인쇄 로그 항목이 없습니다', + showing: '{{total}}개 중 {{count}}개 표시', + rowsPerPage: '행', + page: '페이지', + prev: '이전', + next: '다음', + clearLog: '로그 지우기', + clearLogTitle: '인쇄 로그 지우기', + clearLogConfirm: '모든 인쇄 로그 항목이 영구적으로 삭제됩니다. 아카이브와 대기열 항목은 영향받지 않습니다. 이 작업은 취소할 수 없습니다. 계속하시겠습니까?', + clearLogButton: '모두 지우기', + cleared: '{{count}}개 로그 항목이 지워졌습니다', + clearFailed: '인쇄 로그 지우기 실패' + }, + runLog: { + title: '인쇄 기록', + modalTitle: '인쇄 기록 — {{name}}', + modalTitleFallback: '이 아카이브', + empty: '이 아카이브에 대해 기록된 인쇄 이벤트가 없습니다.', + col: { + date: '날짜', + status: '상태', + duration: '소요 시간', + filament: '필라멘트', + cost: '비용' + }, + status: { + completed: '완료', + failed: '실패', + cancelled: '취소됨', + stopped: '중지됨', + skipped: '건너뜀', + printing: '인쇄 중' + } + } + }, + queue: { + title: '인쇄 대기열', + subtitle: '인쇄 작업을 예약하고 관리하세요', + addToQueue: '대기열에 추가', + print: '인쇄', + reprint: '재인쇄', + schedulePrint: '인쇄 예약', + editQueueItem: '대기열 항목 편집', + printToPrinters: '{{count}}개 프린터에 인쇄', + queueToPrinters: '{{count}}개 프린터에 대기', + queueSelectedPlates: '{{count}}개 플레이트 대기', + selectAllPlates: '{{count}}개 플레이트 전체 선택', + deselectAll: '전체 해제', + printQueued: '인쇄가 대기열에 추가됨', + itemsQueued: '{{count}}개 항목이 대기열에 추가됨', + sending: '전송 중...', + sendingProgress: '{{current}}/{{total}} 전송 중...', + adding: '추가 중...', + addingProgress: '{{current}}/{{total}} 추가 중...', + savingProgress: '{{current}}/{{total}} 저장 중...', + clearQueue: '대기열 지우기', + clearHistory: '기록 지우기', + emptyQueue: '대기열이 비어 있습니다', + position: '위치', + scheduledTime: '예약 시간', + moveUp: '위로 이동', + moveDown: '아래로 이동', + startNow: '지금 시작', + printingInProgress: '인쇄 중...', + viewArchive: '아카이브 보기', + viewInFileManager: '파일 관리자에서 보기', + itemCount: '{{count}}개 항목', + itemCount_plural: '{{count}}개 항목', + dragToReorder: '드래그하여 순서 변경 (즉시만)', + reorderHint: '위치는 즉시 항목에만 영향을 줍니다. 예약된 항목은 설정된 시간에 실행됩니다.', + sjf: { + label: 'SJF', + tooltip: '최단 작업 우선 — 스케줄러가 짧은 인쇄를 우선합니다' + }, + addedBy: '{{name}}님이 추가함', + nextInQueue: '다음 대기', + clearPlateSuccess: '플레이트 비워짐 — 다음 인쇄 준비 완료', + plateNumber: '플레이트 {{index}}', + quantity: '수량', + quantityHint: '{{count}}개 대기열 항목 생성', + activeBatches: '활성 배치', + batchProgress: '{{total}}개 중 {{completed}}개 완료', + cancelBatch: '나머지 취소', + batchCancelled: '남은 배치 항목이 취소되었습니다', + cancelBatchConfirmTitle: '배치 취소', + cancelBatchConfirmMessage: '이 배치의 남은 대기 항목을 모두 취소하시겠습니까?', + batch: '배치', + sections: { + currentlyPrinting: '현재 인쇄 중', + queued: '대기 중', + history: '기록' + }, + status: { + pending: '대기 중', + waiting: '기다리는 중', + printing: '인쇄 중', + paused: '일시정지', + completed: '완료', + failed: '실패', + skipped: '건너뜀', + cancelled: '취소됨' + }, + summary: { + printing: '인쇄 중', + queued: '대기 중', + totalTime: '총 대기열 시간', + totalWeight: '총 대기열 무게', + history: '기록' + }, + filter: { + allPrinters: '모든 프린터', + unassigned: '미할당', + allStatus: '모든 상태', + allLocations: '모든 위치', + any: '전체' + }, + sort: { + byPosition: '위치별 정렬', + byName: '이름별 정렬', + byPrinter: '프린터별 정렬', + bySchedule: '예약별 정렬', + byDate: '날짜별 정렬', + ascendingOldest: '오름차순 (오래된 것 먼저)', + descendingNewest: '내림차순 (최신 것 먼저)' + }, + badges: { + staged: '준비됨', + requiresPrevious: '이전 성공 필요', + autoPowerOff: '자동 전원 끄기', + gcodeInjection: 'G코드' + }, + empty: { + title: '예약된 인쇄 없음', + description: '아카이브 페이지의 컨텍스트 메뉴에서 \"예약\" 옵션을 사용하거나 파일을 드래그 앤 드롭하여 시작하세요.' + }, + time: { + asap: '즉시', + overdue: '기한 초과', + now: '지금', + lessThanMinute: '1분 이내', + inMinutes: '{{count}}분 후', + inHours: '{{count}}시간 후' + }, + actions: { + stopPrint: '인쇄 정지', + startPrint: '인쇄 시작', + requeue: '재대기' + }, + bulkEdit: { + title: '{{count}}개 항목 편집', + title_plural: '{{count}}개 항목 편집', + description: '변경된 설정만 선택된 항목에 적용됩니다.', + printer: '프린터', + noChange: '— 변경 없음 —', + queueOptions: '대기열 옵션', + staged: '준비됨 (수동 시작)', + autoPowerOff: '인쇄 후 자동 전원 끄기', + requirePrevious: '이전 성공 필요', + printOptions: '인쇄 옵션', + bedLevelling: '베드 레벨링', + flowCalibration: '유량 캘리브레이션', + vibrationCalibration: '진동 캘리브레이션', + layerInspection: '첫 번째 층 검사', + timelapse: '타임랩스', + useAms: 'AMS 사용', + applyChanges: '변경사항 적용', + selectAll: '전체 선택', + deselectAll: '전체 해제', + selected: '{{count}}개 선택됨', + editSelected: '선택 항목 편집', + cancelSelected: '선택 항목 취소' + }, + confirm: { + cancelTitle: '예약된 인쇄 취소', + cancelMessage: '\"{{name}}\"을(를) 취소하시겠습니까?', + stopTitle: '인쇄 정지', + stopMessage: '\"{{name}}\"의 현재 인쇄를 정지하시겠습니까? 프린터의 인쇄 작업이 취소됩니다.', + removeTitle: '기록에서 제거', + removeMessage: '대기열 기록에서 \"{{name}}\"을(를) 제거하시겠습니까?', + clearHistoryTitle: '기록 지우기', + clearHistoryMessage: '기록에서 {{count}}개 항목을 모두 제거하시겠습니까?', + cancelButton: '인쇄 취소', + stopButton: '인쇄 정지', + thisPrint: '이 인쇄', + thisItem: '이 항목' + }, + toast: { + cancelled: '대기열 항목이 취소되었습니다', + cancelFailed: '항목 취소 실패', + removed: '대기열 항목이 제거되었습니다', + removeFailed: '항목 제거 실패', + stopped: '인쇄가 정지되었습니다', + stopFailed: '인쇄 정지 실패', + released: '인쇄가 대기열에 릴리스되었습니다', + startFailed: '인쇄 시작 실패', + reorderFailed: '대기열 순서 변경 실패', + historyCleared: '{{count}}개 기록 항목이 지워졌습니다', + clearHistoryFailed: '기록 지우기 실패', + updateFailed: '항목 업데이트 실패', + bulkCancelled: '{{count}}개 항목이 취소되었습니다', + bulkCancelFailed: '항목 취소 실패' + }, + timeline: { + listView: '목록', + timelineView: '타임라인', + unassigned: '미할당', + noData: '이 날에 예약된 인쇄 없음', + allDoneBy: '모든 인쇄 예상 완료 시간: {{time}}', + staged: '준비됨', + filterAll: '모두 표시', + filterPrinting: '인쇄 중', + filterQueued: '대기 중', + time: { + anyMoment: '잠시 후', + minutesLeft: '{{minutes}}분 남음', + hoursLeft: '{{hours}}시간 남음', + hoursMinutesLeft: '{{hours}}시간 {{minutes}}분 남음' + }, + day: { + previous: '이전 날', + next: '다음 날', + today: '오늘' + } + }, + permissions: { + noStopPrint: '인쇄를 정지할 권한이 없습니다', + noStartPrint: '인쇄를 시작할 권한이 없습니다', + noEdit: '이 대기열 항목을 편집할 권한이 없습니다', + noCancel: '이 대기열 항목을 취소할 권한이 없습니다', + noRequeue: '항목을 재대기할 권한이 없습니다', + noRemove: '이 대기열 항목을 제거할 권한이 없습니다', + noClearHistory: '모든 기록을 지울 권한이 없습니다', + noEditItems: '대기열 항목을 편집할 권한이 없습니다', + noCancelItems: '대기열 항목을 취소할 권한이 없습니다' + }, + filamentShort: { + rowBadge: '할당된 스풀의 필라멘트가 부족합니다', + rowTooltip: '디스패치 스케줄러가 이 항목을 표시했습니다. 재생 버튼을 클릭하여 슬롯별 부족량을 확인하고 인쇄 여부를 결정하세요.', + confirmTitle: '필라멘트 부족', + confirmIntro: '할당된 스풀이 하나 이상의 슬롯을 채울 수 없습니다. 그래도 인쇄하시겠습니까?', + lineItem: '슬롯 {{slot}}: {{required}}g 필요, {{remaining}}g 남음', + unknown: '알 수 없음', + printAnyway: '그냥 인쇄' + } + }, + backgroundDispatch: { + unknownFile: '알 수 없는 파일', + unknownPrinter: '알 수 없는 프린터', + startingPrints: '인쇄 시작 중', + progressSummary: '{{complete}}/{{total}} 완료 • 전송됨: {{dispatched}} • 처리 중: {{processing}}', + expandDetails: '전송 상세 펼치기', + collapseDetails: '전송 상세 접기', + dismissToast: '전송 알림 닫기', + cancelDispatchJob: '전송 작업 취소', + cancel: '취소', + cancelling: '취소 중…', + awaitingPrinter: '프린터 대기 중…', + status: { + dispatched: '전송됨', + processing: '처리 중', + completed: '완료', + failed: '실패', + cancelled: '취소됨' + }, + toast: { + cancellingUpload: '업로드 취소 중...', + cancelled: '전송이 취소되었습니다', + cancelFailed: '전송 취소 실패', + completeWithFailures: '백그라운드 전송 완료: {{completed}}개 성공, {{failed}}개 실패', + completeSuccess: '백그라운드 전송 완료: {{completed}}개 성공', + printStartedRemaining: '{{completed}}개 인쇄 시작, {{remaining}}개 더 전송 중...' + } + }, + stats: { + title: '대시보드', + subtitle: '위젯을 드래그하여 정렬하세요. 눈 아이콘을 클릭하여 숨기세요.', + overview: '개요', + totalPrints: '총 인쇄 수', + successRate: '성공률', + totalPrintTime: '총 인쇄 시간', + printTime: '인쇄 시간', + totalFilament: '총 사용 필라멘트', + filamentUsed: '사용된 필라멘트', + filamentCost: '필라멘트 비용', + totalCost: '총 비용', + energyUsed: '사용된 에너지', + energyCost: '에너지 비용', + energyWarmingUpTooltip: '에너지 추적이 시간별 스냅샷을 수집 중입니다. 날짜 범위 합계는 선택한 범위 이전에 하나 이상의 스냅샷이 존재하면 정확해집니다. 초기 값이 적게 집계될 수 있습니다.', + averagePrintTime: '평균 인쇄 시간', + printsPerDay: '일일 인쇄 수', + byPrinter: '프린터별', + printsByPrinter: '프린터별 인쇄', + byMaterial: '재료별', + byMonth: '월별', + last7Days: '최근 7일', + last30Days: '최근 30일', + last90Days: '최근 90일', + allTime: '전체 기간', + quickStats: '빠른 통계', + printActivity: '인쇄 활동', + filamentTypes: '필라멘트 종류', + filamentTrends: '필라멘트 추세', + failureAnalysis: '실패 분석', + timeAccuracy: '시간 정확도', + successful: '성공:', + failed: '실패:', + cancelled: '취소됨:', + perfectEstimate: '100% = 완벽한 예상', + noTimeAccuracyData: '아직 시간 정확도 데이터 없음', + noFilamentData: '필라멘트 데이터 없음', + noPrinterData: '프린터 데이터 없음', + noPrintData: '인쇄 데이터 없음', + noPrintDataLast30Days: '최근 30일 인쇄 데이터 없음', + failureReasons: '실패 원인', + topFailureReasons: '주요 실패 원인', + failedPrintsCount: '{{total}}개 인쇄 중 {{failed}}개 실패', + lastWeekRate: '지난 주: {{rate}}%', + resetLayout: '레이아웃 초기화', + recalculateCosts: '비용 재계산', + recalculateCostsHint: '현재 필라멘트 가격으로 모든 아카이브 비용 재계산', + exportStats: '통계 내보내기', + exportAsCsv: 'CSV로 내보내기', + exportAsExcel: 'Excel로 내보내기', + hiddenCount: '{{count}}개 숨겨짐', + exportDownloaded: '내보내기 다운로드됨', + exportFailed: '내보내기 실패', + layoutReset: '레이아웃이 초기화되었습니다', + recalculatedCosts: '{{count}}개 아카이브의 비용이 재계산되었습니다', + recalculateFailed: '비용 재계산 실패', + loadingStats: '통계 로딩 중...', + noPermissionResetLayout: '레이아웃을 초기화할 권한이 없습니다', + noPermissionRecalculate: '비용을 재계산할 권한이 없습니다', + noPrintDataInRange: '선택한 범위에 인쇄 데이터 없음', + periodFilament: '기간 필라멘트', + periodCost: '기간 비용', + avgPerPrint: '인쇄당 평균', + usageOverTime: '시간별 사용량', + filamentByWeight: '무게', + printDuration: '인쇄 시간', + printerUtilization: '프린터 사용률', + filamentSuccess: '재료별 성공률', + printHabits: '인쇄 습관', + printTimeOfDay: '시간대별 인쇄', + colorDistribution: '색상 분포', + noColorData: '색상 데이터 없음', + records: '기록', + longestPrint: '최장 인쇄', + heaviestPrint: '가장 무거운 인쇄', + mostExpensivePrint: '가장 비싼 인쇄', + busiestDay: '가장 바쁜 날', + successStreak: '연속 성공', + streakPrint: '연속 인쇄', + streakPrints: '{{count}}번 연속 인쇄', + printerStats: '프린터 통계', + hours: '시간', + avgPrints: '평균 인쇄', + noArchiveData: '인쇄 데이터 없음', + filamentByTime: '시간', + avgWeight: '평균 무게', + avgTime: '평균 시간', + filamentByPrints: '인쇄', + timeframe: { + today: '오늘', + "this-week": '이번 주', + "this-month": '이번 달', + "last-7": '최근 7일', + "last-30": '최근 30일', + "last-90": '최근 90일', + "this-year": '올해', + "all-time": '전체 기간', + custom: '사용자 지정 범위', + from: '시작', + to: '종료' + }, + allUsers: '모든 사용자', + noUser: '사용자 없음 (시스템)', + filterByUser: '사용자별 필터' + }, + maintenance: { + title: '유지보수', + overview: '개요', + allOk: '모든 유지보수 최신 상태', + dueCount: '{{count}}개 항목 예정', + dueCount_plural: '{{count}}개 항목 예정', + warningCount: '{{count}}개 경고', + warningCount_plural: '{{count}}개 경고', + totalPrintTime: '총 인쇄 시간', + nextMaintenance: '다음 유지보수', + nothingDue: '예정 없음', + tasks: '작업', + lastPerformed: '마지막 수행', + interval: '간격', + hoursRemaining: '{{hours}}시간 남음', + hoursOverdue: '{{hours}}시간 초과', + markDone: '완료로 표시', + performMaintenance: '유지보수 수행', + history: '기록', + noHistory: '유지보수 기록 없음', + editPrintHours: '인쇄 시간 편집', + currentHours: '현재 시간', + statusTab: '상태', + settingsTab: '설정', + overdueCount: '{{count}}개 초과', + dueSoonCount: '{{count}}개 곧 예정', + dueSoon: '곧 예정', + allGood: '모두 정상', + overdueBy: '{{duration}} 초과', + dueIn: '{{duration}} 후 예정', + timeLeft: '{{duration}} 남음', + day: '1일', + days: '{{count}}일', + week: '1주', + weeks: '{{count}}주', + month: '1개월', + months: '{{count}}개월', + year: '1년', + maintenanceTypes: '유지보수 유형', + maintenanceTypesDescription: '시스템 유형 및 사용자 지정 유지보수 작업', + addCustomType: '사용자 지정 유형 추가', + restoreDefaults: '기본 작업 복원', + intervalType: '간격 유형', + intervalValue: '간격 ({{type}})', + icon: '아이콘', + documentationLink: '문서 링크 (선택사항)', + assignToPrinters: '프린터에 할당', + selectAtLeastOnePrinter: '최소 한 개의 프린터를 선택하세요', + addType: '유형 추가', + custom: '사용자 지정', + printHours: '인쇄 시간', + calendarDays: '달력 일수', + exampleName: '예: HEPA 필터 교체', + viewDocumentation: '문서 보기', + timeBasedInterval: '시간 기반 간격', + intervalOverrides: '간격 재정의', + intervalOverridesDescription: '특정 프린터의 간격 사용자 지정', + assignedToPrinters: '할당된 프린터:', + noPrintersAssigned: '할당된 프린터 없음', + addPrinterShort: '추가:', + printersAssignedClick: '{{count}}개 프린터 할당됨 - 클릭하여 관리', + removeFromPrinter: '이 프린터에서 제거', + types: { + lubricateCarbonRods: '카본 로드 윤활', + lubricateRails: '리니어 레일 윤활', + cleanNozzle: '노즐/핫엔드 청소', + checkBelts: '벨트 장력 확인', + cleanBuildPlate: '빌드 플레이트 청소', + checkExtruder: '압출기 기어 확인', + checkCooling: '냉각 팬 확인', + generalInspection: '일반 점검', + cleanCarbonRods: '카본 로드 청소', + lubricateSteelRods: '스틸 로드 윤활', + cleanSteelRods: '스틸 로드 청소', + cleanLinearRails: '리니어 레일 청소', + checkPtfeTube: 'PTFE 튜브 확인', + replaceHepaFilter: 'HEPA 필터 교체', + replaceCarbonFilter: '활성탄 필터 교체', + lubricateLeftNozzleRail: '좌측 노즐 레일 윤활' + }, + maintenanceComplete: '유지보수가 완료로 표시되었습니다', + typeUpdated: '유지보수 유형이 업데이트되었습니다', + typeDeleted: '유지보수 유형이 삭제되었습니다', + defaultsRestored: '{{count}}개 기본 작업이 복원되었습니다', + printHoursUpdated: '인쇄 시간이 업데이트되었습니다', + printerAssigned: '프린터가 할당되었습니다', + printerRemoved: '프린터가 제거되었습니다', + deleteTypeConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + deleteSystemTypeTitle: '기본 유지보수 작업을 삭제하시겠습니까?', + deleteSystemTypeMessage: '기본 유지보수 작업 \"{{name}}\"을(를) 삭제하시겠습니까?', + noPermissionUpdate: '유지보수 항목을 업데이트할 권한이 없습니다', + noPermissionPerform: '유지보수를 수행할 권한이 없습니다', + noPermissionEditTypes: '유지보수 유형을 편집할 권한이 없습니다', + noPermissionDeleteTypes: '유지보수 유형을 삭제할 권한이 없습니다', + noPermissionEditHours: '인쇄 시간을 편집할 권한이 없습니다', + noPermissionRemovePrinter: '프린터 할당을 제거할 권한이 없습니다', + noPermissionAssignPrinter: '프린터를 할당할 권한이 없습니다', + noPermissionEditIntervals: '간격을 편집할 권한이 없습니다', + configureSettings: '유지보수 유형 및 간격 설정' + }, + settings: { + title: '설정', + general: '일반', + tabs: { + general: '일반', + smartPlugs: '스마트 플러그', + notifications: '알림', + queue: '워크플로우', + filament: '필라멘트', + network: '네트워크', + apiKeys: 'API 키', + virtualPrinter: '가상 프린터', + spoolbuddy: 'SpoolBuddy', + failureDetection: '실패 감지', + users: '인증', + backup: '백업', + emailAuth: '이메일 인증', + ldap: 'LDAP', + twoFa: '이중 인증', + oidc: 'SSO / OIDC', + security: '보안' + }, + spoolbuddy: { + infoTitle: 'SpoolBuddy 기기', + infoBody: 'SpoolBuddy 키오스크는 하트비트를 통해 자동으로 등록됩니다. 더 이상 사용하지 않거나 데몬 충돌로 인한 중복이 있는 경우 여기서 기기를 등록 해제하세요.', + duplicatesTitle: '{{count}}개 기기 등록됨', + duplicatesBody: '첫 번째로 등록된 기기만 키오스크 UI에서 사용됩니다. 충돌로 인한 오래된 중복이 있으면 등록 해제하세요 — 온라인 기기는 다음 하트비트에서 자동으로 재등록됩니다.', + empty: '아직 등록된 SpoolBuddy 기기가 없습니다.', + online: '온라인', + offline: '오프라인', + unregister: '등록 해제', + unregisterSuccess: '기기 등록 해제됨', + unregisterError: '기기 등록 해제 실패', + confirmTitle: 'SpoolBuddy 기기를 등록 해제하시겠습니까?', + confirmBody: '데이터베이스에서 \"{{hostname}}\" ({{deviceId}})를 제거합니다. 기기가 온라인이면 다음 하트비트에서 자동으로 재등록됩니다.', + ipAddress: 'IP 주소', + firmware: '펌웨어', + lastSeen: '마지막 확인', + daemonUptime: '데몬 가동 시간', + systemUptime: '시스템 가동 시간', + never: '없음', + nfc: 'NFC', + scale: '저울', + cpuTemp: 'CPU 온도', + memory: '메모리', + disk: '디스크', + update: '업데이트', + updateConfirmTitle: 'Spoolbuddy 데몬을 업데이트하시겠습니까?', + updateConfirmBody: '\"{{hostname}}\"에서 소프트웨어 업데이트를 실행하시겠습니까? 업데이트가 적용되면 데몬이 재시작됩니다.', + restartBrowser: '브라우저 재시작', + restartBrowserConfirmTitle: '키오스크 브라우저를 재시작하시겠습니까?', + restartBrowserConfirmBody: '\"{{hostname}}\"의 키오스크 브라우저를 재시작하시겠습니까? 화면이 잠시 꺼집니다.', + restartDaemon: '데몬 재시작', + restartDaemonConfirmTitle: 'Spoolbuddy 데몬을 재시작하시겠습니까?', + restartDaemonConfirmBody: '\"{{hostname}}\"의 Spoolbuddy 데몬을 재시작하시겠습니까? 기기가 몇 초 동안 오프라인 상태가 됩니다.', + reboot: '재부팅', + rebootConfirmTitle: '기기를 재부팅하시겠습니까?', + rebootConfirmBody: '\"{{hostname}}\"을(를) 재부팅하시겠습니까? 기기가 약 1분 동안 오프라인 상태가 됩니다.', + shutdown: '종료', + shutdownConfirmTitle: '기기를 종료하시겠습니까?', + shutdownConfirmBody: '\"{{hostname}}\"을(를) 종료하시겠습니까? 다시 켜려면 물리적 접근이 필요합니다.', + commandConfirm: '확인', + commandQueued: '명령이 대기열에 추가됨', + commandError: '명령 전송 실패', + cpuLoad: 'CPU 부하' + }, + ldap: { + title: 'LDAP 인증', + enabledDesc: 'LDAP 인증이 활성화되어 있습니다', + disabledDesc: 'LDAP 인증이 비활성화되어 있습니다', + disabledHint: '아래에서 LDAP 설정을 구성하고 저장한 후 활성화하세요.', + enabled: 'LDAP 인증 활성화됨', + disabled: 'LDAP 인증 비활성화됨', + feature1: '사용자가 LDAP 자격 증명으로 로그인 가능', + feature2: '로컬 관리자 계정이 대체 수단으로 유지됨', + feature3: 'LDAP 그룹이 로그인 시 Bambuddy 그룹에 매핑됨', + serverConfig: 'LDAP 서버 설정', + serverUrl: '서버 URL', + serverUrlHint: 'SSL에는 ldaps://, StartTLS에는 ldap:// 사용', + security: '보안', + securityHint: 'StartTLS는 일반 연결을 TLS로 업그레이드합니다. LDAPS는 처음부터 TLS를 사용합니다.', + bindDn: '바인드 DN (서비스 계정)', + bindPassword: '바인드 비밀번호', + searchBase: '검색 기반 DN', + userFilter: '사용자 검색 필터', + userFilterHint: '{username}은 로그인 사용자명으로 대체됩니다. OpenLDAP의 경우 (uid={username})을 사용하세요.', + autoProvision: '사용자 자동 프로비저닝', + autoProvisionHint: '첫 LDAP 로그인 시 자동으로 Bambuddy 계정 생성', + defaultGroup: '기본 그룹', + defaultGroupNone: '— 없음 (대체 없음) —', + defaultGroupHint: 'LDAP 사용자가 인증되었지만 매핑된 LDAP 그룹에 없을 때 할당되는 대체 그룹. 비워두면 매핑되지 않은 사용자에게 권한이 없습니다.', + groupMapping: '그룹 매핑 (JSON)', + groupMappingHint: 'LDAP 그룹 DN을 Bambuddy 그룹에 매핑합니다. 사용 가능한 그룹: ', + testConnection: '연결 테스트', + settingsSaved: 'LDAP 설정이 저장되었습니다', + errors: { + serverRequired: 'LDAP 서버 URL이 필요합니다', + searchBaseRequired: '검색 기반 DN이 필요합니다', + enableAuthFirst: '먼저 인증을 활성화하세요', + configureLdapFirst: '먼저 LDAP 설정을 저장하세요' + }, + advanced: '고급' + }, + email: { + smtpSettings: 'SMTP 설정', + smtpHost: 'SMTP 서버', + smtpPort: 'SMTP 포트', + security: '보안', + authentication: '인증', + username: '사용자명', + password: '비밀번호', + fromEmail: '발신 이메일', + fromName: '발신자 이름', + testConnection: 'SMTP 연결 테스트', + testRecipient: '테스트 수신자 이메일', + sendTest: '테스트 이메일 전송', + sending: '전송 중...', + save: '설정 저장', + saving: '저장 중...', + advancedAuth: '고급 인증', + advancedAuthEnabled: '고급 인증이 활성화되어 있습니다', + advancedAuthEnabledDesc: '이메일 기반 사용자 관리 기능이 활성화되어 있습니다. 신규 사용자는 이메일로 자동 생성된 비밀번호를 받으며, 사용자는 비밀번호 찾기 기능으로 비밀번호를 재설정할 수 있습니다.', + advancedAuthDisabled: '고급 인증이 비활성화되어 있습니다', + advancedAuthDisabledDesc: '이메일 기반 사용자 관리 기능을 활성화하려면 고급 인증을 활성화하세요.', + enable: '활성화', + disable: '비활성화', + feature1: '비밀번호가 자동 생성되어 신규 사용자에게 이메일로 전송됨', + feature2: '사용자가 사용자명 또는 이메일로 로그인 가능', + feature3: '비밀번호 찾기 기능 사용 가능', + feature4: '관리자가 이메일로 사용자 비밀번호 재설정 가능', + errors: { + requiredFields: '모든 필수 항목을 입력하세요', + usernameRequired: '인증이 활성화된 경우 사용자명이 필요합니다', + enterTestEmail: '테스트 이메일 주소를 입력하세요', + smtpServerAndEmail: '테스트 전에 SMTP 서버와 발신 이메일을 입력하세요', + usernamePasswordRequired: '인증이 활성화된 경우 사용자명과 비밀번호가 필요합니다', + configureSmtpFirst: '먼저 SMTP 설정을 구성하고 테스트하세요', + enableAuthFirst: '이메일 기반 기능을 사용하려면 먼저 인증을 활성화하세요.' + }, + success: { + settingsSaved: 'SMTP 설정이 성공적으로 저장되었습니다' + }, + securityOptions: { + starttls: 'STARTTLS (포트 587)', + ssl: 'SSL/TLS (포트 465)', + none: '없음 (포트 25)' + }, + authOptions: { + enabled: '활성화됨', + disabled: '비활성화됨' + } + }, + appearance: '모양', + notifications: '알림', + smartPlugs: '스마트 플러그', + spoolman: 'Spoolman', + updates: '업데이트', + language: '언어', + languageDescription: '선호하는 언어를 선택하세요', + theme: '테마', + themeLight: '라이트', + themeDark: '다크', + themeSystem: '시스템', + defaultView: '기본 보기', + defaultViewDescription: '앱을 열 때 표시할 페이지', + checkForUpdates: '업데이트 확인', + autoUpdate: '자동 업데이트', + currentVersion: '현재 버전', + latestVersion: '최신 버전', + upToDate: '최신 상태입니다', + updateAvailable: '업데이트 가능', + notificationLanguage: '알림 언어', + notificationLanguageDescription: '푸시 알림 언어', + bedCooledThreshold: '베드 냉각 임계값', + bedCooledThresholdDescription: '인쇄 후 베드가 냉각된 것으로 간주되는 온도', + userNotificationsEnabled: '사용자 알림', + userNotificationsEnabledDescription: '사용자 알림 메뉴 및 인쇄 작업 이벤트에 대한 이메일 알림을 활성화합니다. 고급 인증이 필요합니다.', + userNotificationsDisabledHint: '사용자 알림을 사용하려면 고급 인증을 활성화하세요.', + notificationProviders: '알림 제공자', + addProvider: '제공자 추가', + editProvider: '제공자 편집', + providerType: '제공자 유형', + testNotification: '알림 테스트', + testSuccess: '테스트 알림이 성공적으로 전송되었습니다', + testFailed: '테스트 알림 전송 실패', + quietHours: '방해 금지 시간', + quietHoursDescription: '이 시간 동안 방해하지 않음', + quietHoursStart: '시작', + quietHoursEnd: '종료', + events: { + title: '알림 이벤트', + printStart: '인쇄 시작됨', + printComplete: '인쇄 완료됨', + printFailed: '인쇄 실패', + printStopped: '인쇄 정지됨', + printProgress: '진행 마일스톤', + printProgressDescription: '25%, 50%, 75%에 알림', + printerOffline: '프린터 오프라인', + printerError: '프린터 오류', + filamentLow: '필라멘트 부족', + maintenanceDue: '유지보수 예정', + maintenanceDueDescription: '유지보수가 필요할 때 알림' + }, + smartPlug: { + title: '스마트 플러그', + add: '스마트 플러그 추가', + edit: '스마트 플러그 편집', + name: '이름', + ipAddress: 'IP 주소', + linkedPrinter: '연결된 프린터', + autoOn: '자동 켜기', + autoOnDescription: '인쇄 시작 시 켜기', + autoOff: '자동 끄기', + autoOffDescription: '인쇄 완료 후 끄기', + offDelay: '끄기 지연', + offDelayMinutes: '인쇄 후 분', + offDelayTemp: '노즐 온도 이하일 때', + currentState: '현재 상태', + turnOn: '켜기', + turnOff: '끄기' + }, + filamentTracking: '필라멘트 추적', + filamentTrackingDesc: '필라멘트 스풀을 추적하는 방법을 선택하세요. 내장 인벤토리를 사용하거나 외부 Spoolman 서버에 연결할 수 있습니다.', + filamentChecks: '필라멘트 확인', + disableFilamentWarnings: '필라멘트 경고 비활성화', + disableFilamentWarningsDesc: '인쇄 또는 대기열 추가 시 필라멘트 부족 경고 표시 안 함', + preferLowestFilament: '남은 필라멘트가 가장 적은 것 우선', + preferLowestFilamentDesc: '여러 스풀이 일치할 때 남은 필라멘트가 가장 적은 것 사용', + trackingModeBuiltIn: '내장 인벤토리', + trackingModeBuiltInDesc: 'RFID 자동 매칭 및 사용량 추적 포함', + trackingModeSpoolmanDesc: '외부 필라멘트 관리 서버', + builtInFeatureRfid: 'AMS의 Bambu Lab RFID 스풀 자동 감지', + builtInFeatureUsage: '인쇄당 필라멘트 소비량 추적', + builtInFeatureCatalog: '스풀, 색상, K 팩터 프로필 관리', + builtInFeatureThirdParty: '서드파티 스풀을 인벤토리 스풀에 할당 가능', + amsSyncButton: 'AMS에서 무게 동기화', + amsSyncTitle: 'AMS에서 스풀 무게 동기화', + amsSyncMessage: '연결된 프린터의 현재 AMS 잔여% 값으로 모든 인벤토리 스풀 무게를 덮어씁니다. 손상된 무게 데이터를 복구하는 데 사용하세요. 프린터가 온라인이어야 합니다.', + amsSyncing: '동기화 중...', + amsSyncSuccess: '{{synced}}개 스풀 동기화됨, {{skipped}}개 건너뜀', + amsSyncError: 'AMS에서 무게 동기화 실패', + spoolmanAmsSyncButton: 'AMS에서 Spoolman 무게 동기화', + spoolmanAmsSyncTitle: 'AMS에서 Spoolman 스풀 무게 동기화', + spoolmanAmsSyncMessage: '연결된 프린터의 현재 AMS 잔여% 값으로 모든 Spoolman 스풀 무게를 업데이트합니다. 프린터가 온라인이어야 합니다.', + spoolmanAmsSyncing: '동기화 중...', + spoolmanAmsSyncSuccess: '{{synced}}개 스풀 동기화됨, {{skipped}}개 건너뜀', + spoolmanAmsSyncError: 'AMS에서 Spoolman 무게 동기화 실패', + spoolmanAmsSyncErrorUnreachable: 'Spoolman 무게 동기화 실패 (Spoolman 접근 불가)', + spoolmanAmsSyncErrorNotConfigured: 'Spoolman 무게 동기화 실패 (Spoolman 미설정)', + spoolmanNotConfigured: 'Spoolman 미설정', + spoolmanFilamentCatalogTitle: 'Spoolman 필라멘트 카탈로그', + spoolmanFilamentCatalogDesc: 'Spoolman 인스턴스의 필라멘트 이름 및 공 무게. 이름과 스풀 무게는 여기서 편집 가능하며 다른 속성은 Spoolman에서 직접 관리됩니다.', + spoolmanUrl: 'Spoolman URL', + spoolmanUrlHint: 'Spoolman 서버의 URL (예: http://localhost:7912)', + spoolmanConnected: '연결됨', + spoolmanDisconnected: '연결 끊김', + status: '상태', + connect: '연결', + disconnect: '연결 해제', + howSyncWorks: '동기화 작동 방식', + syncInfoRfidOnly: 'RFID가 있는 공식 Bambu Lab 스풀만 동기화됨', + syncInfoAutoCreate: '새 스풀은 첫 번째 동기화 시 Spoolman에 자동 생성됨', + syncInfoThirdPartySkipped: '비 Bambu Lab 스풀 (서드파티, 리필)은 건너뜀', + linkingExistingSpools: '기존 스풀 연결', + linkingExistingSpoolsDesc: '기존 Spoolman 스풀을 AMS에 연결하려면 AMS 슬롯 위에 마우스를 올리고 \"Spoolman에 연결\"을 클릭하세요.', + syncMode: '동기화 모드', + syncModeAuto: '자동', + syncModeManual: '수동만', + syncModeAutoDesc: '변경이 감지되면 AMS 데이터가 자동으로 동기화됨', + syncModeManualDesc: '수동으로 트리거할 때만 동기화', + syncAmsData: 'AMS 데이터 동기화', + syncAmsDataDesc: '프린터 AMS 데이터를 Spoolman에 수동으로 동기화', + allPrinters: '모든 프린터', + noDefaultPrinter: '기본값 없음 (매번 묻기)', + sidebarOrder: '사이드바 순서', + saveThumbnails: '썸네일 저장', + captureFinishPhoto: '완료 사진 캡처', + noPrintersConfigured: '설정된 프린터 없음', + archiveMode: { + always: '항상 아카이브 항목 생성', + never: '아카이브 항목 생성 안 함', + ask: '매번 묻기' + }, + checkForUpdatesLabel: '업데이트 확인', + checkPrinterFirmware: '프린터 펌웨어 확인', + includeBetaUpdates: '베타 버전 포함', + includeBetaUpdatesDesc: '업데이트 확인 시 베타 및 사전 릴리스 버전에 대해 알림', + enableRetry: '재시도 활성화', + homeAssistantDescription: 'Home Assistant를 통해 스마트 플러그 제어', + environmentManagedLabel: '(환경 변수 관리)', + autoEnabledViaEnv: '환경 변수를 통해 자동 활성화됨', + urlFromEnvReadOnly: 'HA_URL 환경 변수에서 값 설정됨 (읽기 전용)', + tokenFromEnvReadOnly: 'HA_TOKEN 환경 변수에서 값 설정됨 (읽기 전용)', + mqttConnectedTo: '연결됨', + prometheusDescription: 'Prometheus 형식으로 프린터 데이터 노출', + noSmartPlugsTitle: '설정된 스마트 플러그 없음', + noSmartPlugsDescription: '에너지 사용량 추적 및 전원 제어 자동화를 위해 Tasmota 기반 스마트 플러그를 추가하세요.', + noProvidersTitle: '설정된 제공자 없음', + noProvidersDescription: '알림을 받으려면 제공자를 추가하세요.', + noTemplatesAvailable: '사용 가능한 템플릿 없음. 기본 템플릿을 시드하려면 백엔드를 재시작하세요.', + apiPermissionView: '프린터 상태 및 대기열 보기', + apiPermissionEdit: '인쇄 대기열에서 항목 추가 및 제거', + apiKeysEmptyTitle: 'API 키 없음', + apiKeysEmptyDescription: '외부 서비스와 통합하려면 API 키를 만드세요.', + noUsersFound: '사용자를 찾을 수 없습니다', + noGroupsFound: '그룹을 찾을 수 없습니다', + noGroupsAvailable: '사용 가능한 그룹 없음', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + systemGroupWarning: '시스템 그룹 이름은 변경할 수 없습니다', + authDisabledTitle: '인증이 비활성화되어 있습니다', + authDisabledFeature1: '시스템 접근 시 로그인 필요', + authDisabledFeature2: '그룹 기반 권한으로 여러 사용자 생성', + authDisabledFeature3: '50개 이상의 세분화된 권한으로 접근 제어', + userHasCreated: '이 사용자가 만든 항목:', + userItemsQuestion: '이 항목들을 어떻게 처리하시겠습니까?', + deleteUserConfirm: '이 사용자를 삭제하시겠습니까?', + actionCannotBeUndone: '이 작업은 취소할 수 없습니다.', + addFirstSmartPlug: '첫 번째 스마트 플러그 추가', + providers: '제공자', + log: '로그', + testAll: '모두 테스트', + testResults: '테스트 결과', + testPassedCount: '{{count}}개 통과', + testFailedCount: '{{count}}개 실패', + messageTemplates: '메시지 템플릿', + messageTemplatesDescription: '각 이벤트에 대한 알림 메시지를 사용자 지정하세요.', + apiKeys: 'API 키', + apiKeysDescription: '외부 통합 및 웹훅을 위한 API 키를 만드세요.', + createKey: '키 만들기', + apiKeyCreated: 'API 키가 성공적으로 생성되었습니다', + apiKeyCopyWarning: '지금 이 키를 복사하세요 - 다시 표시되지 않습니다!', + useInApiBrowser: 'API 브라우저에서 사용', + createNewApiKey: '새 API 키 만들기', + keyName: '키 이름', + keyNamePlaceholder: '예: Home Assistant, OctoPrint', + readStatus: '상태 읽기', + readStatusDescription: '프린터 상태 및 대기열 보기', + manageQueue: '대기열 관리', + manageQueueDescription: '인쇄 대기열에서 항목 추가 및 제거', + controlPrinter: '프린터 제어', + controlPrinterDescription: '인쇄 일시정지, 재개, 정지', + manageLibrary: '라이브러리 관리', + manageLibraryDescription: '라이브러리 파일 업로드, 이름 변경 및 삭제; MakerWorld에서 모델 가져오기', + manageInventory: '재고 관리', + manageInventoryDescription: '스풀 및 재고 레코드 생성, 업데이트 및 삭제. SpoolBuddy 키오스크(NFC 스캔, 저울 측정값, 키오스크 시스템 명령)에 필요합니다.', + libraryBadge: '라이브러리', + inventoryBadge: '재고', + cloudAccess: '클라우드 접근 허용', + cloudAccessDescription: '사용자를 대신하여 Bambu Cloud 프리셋 및 필라멘트를 읽습니다. Bambu Cloud에 로그인되어 있어야 합니다.', + cloudBadge: '클라우드', + legacyKey: '레거시', + legacyKeyTooltip: '사용자별 소유권 이전에 생성됨. 클라우드 접근을 사용하려면 재생성하세요', + unnamedKey: '이름 없는 키', + lastUsed: '마지막 사용', + read: '읽기', + control: '제어', + createFirstKey: '첫 번째 키 만들기', + webhookEndpoints: '웹훅 엔드포인트', + webhookApiKeyHint: 'X-API-Key 헤더에 API 키를 사용하세요.', + webhook: { + getAllStatus: '모든 프린터 상태 가져오기', + getSpecificStatus: '특정 프린터 상태 가져오기', + addToQueue: '인쇄 대기열에 추가', + pausePrint: '인쇄 일시정지', + resumePrint: '인쇄 재개', + stopPrint: '인쇄 정지' + }, + apiBrowser: 'API 브라우저', + apiBrowserDescription: '사용 가능한 모든 API 엔드포인트를 탐색하고 테스트하세요.', + apiKeyForTesting: '테스트용 API 키', + apiKeyPlaceholder: '인증된 엔드포인트를 테스트하려면 API 키를 여기에 붙여넣으세요...', + apiKeyHint: '이 키는 요청과 함께 X-API-Key 헤더로 전송됩니다.', + deleteApiKeyTitle: 'API 키 삭제', + deleteApiKeyMessage: '이 API 키를 삭제하시겠습니까? 이 키를 사용하는 모든 통합이 작동을 멈춥니다.', + deleteKey: '키 삭제', + amsDisplayThresholds: 'AMS 표시 임계값', + amsThresholdsDescription: 'AMS 습도 및 온도 표시기의 색상 임계값을 설정하세요.', + humidity: '습도', + goodGreen: '좋음 (녹색)', + fairOrange: '보통 (주황색)', + aboveFairBad: '보통 임계값 초과 시 빨간색 (나쁨)으로 표시', + fairAlsoDryingThreshold: '이 임계값은 자동 건조 활성화 시 트리거로도 사용됨', + temperature: '온도', + goodBlue: '좋음 (파란색)', + aboveFairHot: '보통 임계값 초과 시 빨간색 (뜨거움)으로 표시', + historyRetention: '기록 보존', + keepSensorHistory: '센서 기록 보존 기간', + historyRetentionDescription: '오래된 습도 및 온도 데이터가 자동으로 삭제됩니다', + defaultPrintOptions: '기본 인쇄 옵션', + defaultPrintOptionsDescription: '새 인쇄 시작 시 기본값을 설정하세요. 인쇄 대화 상자에서 인쇄별로 재정의할 수 있습니다.', + defaultBedLevelling: '베드 레벨링', + defaultBedLevellingDesc: '인쇄 전 자동 베드 레벨링', + defaultFlowCali: '유량 캘리브레이션', + defaultFlowCaliDesc: '압출 유량 캘리브레이션', + defaultVibrationCali: '진동 캘리브레이션', + defaultVibrationCaliDesc: '링잉 아티팩트 감소', + defaultLayerInspect: '첫 번째 층 검사', + defaultLayerInspectDesc: '첫 번째 층 AI 검사', + defaultTimelapse: '타임랩스', + defaultTimelapseDesc: '타임랩스 영상 녹화', + staggeredStart: '엇갈린 시작', + staggeredStartDescription: '다중 프린터 일괄 시작 시 기본 그룹 크기 및 간격. 인쇄 모달에서 배치별로 재정의할 수 있습니다.', + plateClear: '플레이트 비움 확인', + requirePlateClear: '플레이트 비움 확인 필요', + requirePlateClearDescription: '활성화하면 스케줄러가 완료된 작업이 있는 프린터에서 대기 중인 인쇄를 시작하기 전에 프린터별 플레이트 비움 확인을 기다립니다.', + gcodeInjection: 'G코드 주입', + gcodeInjectionDescription: '자동 인쇄 시스템을 위한 인쇄 시작 및/또는 종료 시 주입할 사용자 지정 G코드를 설정하세요.', + gcodeInjectionNoPrinters: '프린터가 없습니다. G코드 스니펫을 설정하려면 프린터를 추가하세요.', + gcodeStartLabel: '시작 G코드', + gcodeEndLabel: '종료 G코드', + gcodeStartPlaceholder: '인쇄 시작 전 앞에 추가되는 G코드...', + gcodeEndPlaceholder: '인쇄 종료 후 뒤에 추가되는 G코드...', + staggerGroupSize: '그룹 크기', + staggerGroupSizeHelp: '그룹당 동시에 시작할 프린터 수', + staggerInterval: '간격 (분)', + staggerIntervalHelp: '각 그룹 시작 사이의 지연', + queueDrying: '대기열 자동 건조', + queueDryingDescription: '대기 중인 인쇄 사이에 프린터가 유휴 상태일 때 AMS 필라멘트를 자동으로 건조합니다.', + queueDryingEnabled: '자동 건조 활성화', + queueDryingEnabledDescription: '프린터가 유휴 상태이고 습도가 임계값 초과 시 자동으로 AMS 건조 시작', + queueDryingBlock: '건조 완료까지 대기', + queueDryingBlockDescription: '건조가 완료될 때까지 인쇄 대기열을 차단합니다. 끄면 인쇄가 건조보다 우선합니다.', + ambientDryingEnabled: '주변 건조', + ambientDryingEnabledDescription: '대기 중인 인쇄가 없어도 습도가 임계값을 초과하면 유휴 프린터에서 자동으로 필라멘트 건조', + dryingPresets: '건조 프리셋', + dryingPresetsDescription: '필라멘트 유형별 온도 및 시간. AMS 2 Pro는 낮은 온도, AMS-HT는 높은 온도를 지원합니다.', + dryingFilament: '필라멘트', + printModal: '인쇄 모달', + expandCustomMapping: '사용자 지정 매핑 기본 펼침', + expandCustomMappingDescription: '여러 프린터에 인쇄할 때 프린터별 AMS 매핑을 펼친 상태로 표시', + authentication: '인증', + authEnabledDescription: '인스턴스가 사용자 인증으로 보안됨', + authDisabledDescription: '로그인 필요 및 사용자 접근 관리를 위해 활성화', + authDisabledMessage: '사용자 계정 생성, 권한 관리, Bambuddy 인스턴스 보안을 위해 인증을 활성화하세요.', + enableAuthentication: '인증 활성화', + currentUser: '현재 사용자', + changePassword: '비밀번호 변경', + admin: '관리자', + users: '사용자', + addUser: '사용자 추가', + groups: '그룹', + addGroup: '그룹 추가', + system: '시스템', + noDescription: '설명 없음', + userCount: '{{count}}명의 사용자', + permissionCount: '{{count}}개 권한', + createUser: '사용자 만들기', + username: '사용자명', + enterUsername: '사용자명 입력', + password: '비밀번호', + enterPassword: '비밀번호 입력 (최소 6자)', + confirmPassword: '비밀번호 확인', + confirmPasswordPlaceholder: '비밀번호 확인', + viewReleaseOnGitHub: 'GitHub에서 릴리스 보기', + turnAllPlugsOn: '모든 플러그 켜기', + turnAllPlugsOff: '모든 플러그 끄기', + clearNotificationLogs: '알림 로그 지우기', + clearLogsMessage: '30일보다 오래된 모든 알림 로그를 영구적으로 삭제합니다. 이 작업은 취소할 수 없습니다.', + clearLogs: '로그 지우기', + resetUiPreferences: 'UI 기본 설정 초기화', + resetUiPreferencesMessage: '모든 UI 기본 설정을 기본값으로 초기화합니다: 사이드바 순서, 테마, 대시보드 레이아웃, 보기 모드, 정렬 기본 설정. 프린터, 아카이브, 서버 설정은 영향받지 않습니다. 지운 후 페이지가 새로고침됩니다.', + resetPreferences: '기본 설정 초기화', + deleteGroupTitle: '그룹 삭제', + deleteGroupMessage: '이 그룹을 삭제하시겠습니까? 이 그룹의 사용자는 이 권한을 잃게 됩니다.', + deleteGroup: '그룹 삭제', + disableAuthenticationTitle: '인증 비활성화', + disableAuthenticationMessage: '인증을 비활성화하시겠습니까? 이렇게 하면 로그인 없이 Bambuddy 인스턴스에 접근할 수 있게 됩니다. 모든 사용자는 데이터베이스에 유지되지만 인증은 비활성화됩니다.', + disableAuthentication: '인증 비활성화', + configureBambuddy: 'Bambuddy 설정', + systemDefault: '시스템 기본값', + archiveSettings: '아카이브 설정', + newWindow: '새 창', + embeddedOverlay: '내장 오버레이', + preferredSlicer: '선호하는 슬라이서', + preferredSlicerDescription: '파일을 열 슬라이서 앱을 선택하세요', + orcaslicerKnownIssuesWarning: 'OrcaSlicer 2.3.2 / 2.4.0-dev에는 Bambu 제작 3MF 파일 슬라이싱을 차단하는 알려진 CLI 버그가 있습니다. 업스트림 수정이 출시될 때까지 Bambu Studio를 사용하는 것이 좋습니다.', + useSlicerApi: '슬라이서 API 사용', + useSlicerApiDescription: '켜면 \"슬라이스\" 작업이 앱 내 슬라이서 모달을 열고 슬라이서 API 사이드카를 호출합니다. 끄면 URI 스킴을 통해 데스크톱 슬라이서로 전달합니다.', + slicerCard: '슬라이서', + orcaslicerApiUrl: 'OrcaSlicer 사이드카 URL', + bambuStudioApiUrl: 'Bambu Studio 사이드카 URL', + slicerApiUrlDescription: '슬라이서 API 사이드카 컨테이너의 URL. SLICER_API_URL / BAMBU_STUDIO_API_URL 환경 변수 기본값을 사용하려면 비워두세요.', + slicerBundles: { + title: '슬라이서 번들', + description: 'BambuStudio에서 내보낸 프린터 프리셋 번들(.bbscfg)을 가져오세요. 가져온 후 슬라이스 요청이 JSON 프로필 트리플렛을 다시 업로드하지 않고 번들에서 이름으로 프리셋을 선택할 수 있습니다.', + uploadButton: '번들 업로드', + uploading: '업로드 중…', + loading: '번들 로딩 중…', + empty: '아직 가져온 번들 없음.', + summary: '{{processCount}}개 프로세스 · {{filamentCount}}개 필라멘트 프리셋', + delete: '삭제', + uploadSuccess: '{{name}} 가져옴', + uploadError: '번들 업로드 실패: {{message}}', + deleteSuccess: '번들 제거됨', + deleteError: '번들 삭제 실패: {{message}}', + confirmDeleteTitle: '이 번들을 제거하시겠습니까?', + confirmDeleteMessage: '\"{{name}}\"을(를) 참조하는 슬라이스 요청은 번들이 재가져오기될 때까지 실패합니다.' + }, + externalCameras: '외부 카메라', + costTracking: '비용 추적', + printsOnly: '인쇄만', + totalConsumption: '총 소비', + dataManagement: '데이터 관리', + storageUsage: '저장소 사용량', + storageUsageDescription: '카테고리별 데이터 사용량 분류', + storageUsageTotal: '총계', + storageUsageErrors: '오류', + storageUsageOtherBreakdown: '기타 (정적 자산, 스크립트, 구성 파일 포함)', + storageUsageSystem: '시스템', + storageUsageData: '데이터', + storageUsageUnavailable: '저장소 사용량 정보 불가', + clearNotificationLogsDescription: '30일보다 오래된 알림 로그 삭제', + resetUiPreferencesDescription: '사이드바 순서, 테마, 보기 모드, 레이아웃 기본 설정 초기화. 프린터, 아카이브, 설정은 영향받지 않습니다.', + enableHomeAssistant: 'Home Assistant 활성화', + enableMqtt: 'MQTT 활성화', + useTls: 'TLS 사용', + enableMetricsEndpoint: '메트릭 엔드포인트 활성화', + availableMetrics: '사용 가능한 메트릭', + editUser: '사용자 편집', + deleteUserTitle: '사용자 삭제', + groupName: '그룹 이름', + leaveEmptyForAnonymous: '익명으로 두려면 비워두세요', + leaveEmptyForNoAuth: '인증 없이 두려면 비워두세요', + enterNewPassword: '새 비밀번호 입력', + confirmNewPassword: '새 비밀번호 확인', + enterGroupName: '그룹 이름 입력', + enterDescriptionOptional: '설명 입력 (선택사항)', + enterCurrentPassword: '현재 비밀번호 입력', + enterNewPasswordMin6: '새 비밀번호 입력 (최소 6자)', + toast: { + keyCopied: '키가 클립보드에 복사되었습니다', + copyFailed: '키 복사 실패', + keyAddedToBrowser: 'API 브라우저에 키가 추가되었습니다', + clearLogsFailed: '로그 지우기 실패', + uiPreferencesReset: 'UI 기본 설정이 초기화되었습니다. 새로고침 중...', + authDisabled: '인증이 성공적으로 비활성화되었습니다', + authDisableFailed: '인증 비활성화 실패', + apiKeyCreated: 'API 키가 생성되었습니다', + apiKeyDeleted: 'API 키가 삭제되었습니다', + userCreated: '사용자가 성공적으로 생성되었습니다', + userUpdated: '사용자가 성공적으로 업데이트되었습니다', + userDeleted: '사용자가 성공적으로 삭제되었습니다', + groupCreated: '그룹이 성공적으로 생성되었습니다', + groupUpdated: '그룹이 성공적으로 업데이트되었습니다', + groupDeleted: '그룹이 성공적으로 삭제되었습니다', + fillRequiredFields: '모든 필수 항목을 입력하세요', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + passwordTooShort: '비밀번호는 최소 6자여야 합니다', + enterGroupName: '그룹 이름을 입력하세요', + settingsSaved: '설정이 저장되었습니다', + noPermissionUpdate: '설정을 변경할 권한이 없습니다', + cameraSettingsSaved: '카메라 설정이 저장되었습니다', + enterCameraUrl: '카메라 URL을 입력하세요', + passwordChanged: '비밀번호가 성공적으로 변경되었습니다', + connectionFailed: '연결 실패', + testFailed: '테스트 실패', + cameraConnected: '카메라 연결됨{{resolution}}', + passwordNeedsUppercase: '비밀번호에 대문자가 최소 1개 포함되어야 합니다', + passwordNeedsLowercase: '비밀번호에 소문자가 최소 1개 포함되어야 합니다', + passwordNeedsDigit: '비밀번호에 숫자가 최소 1개 포함되어야 합니다', + passwordNeedsSpecial: '비밀번호에 특수문자가 최소 1개 포함되어야 합니다' + }, + testConnection: '연결 테스트', + catalog: { + spoolCatalog: '스풀 카탈로그', + spoolCatalogDescription: '브랜드/유형별 빈 스풀 무게. 스풀 추가 시 자동 무게 조회에 사용됩니다.', + searchCatalog: '카탈로그 검색...', + addNewEntry: '새 항목 추가', + namePlaceholder: '이름 (예: Bambu Lab - Plastic)', + weight: '무게', + type: '유형', + default: '기본', + custom: '사용자 지정', + noMatch: '검색에 일치하는 항목 없음', + empty: '카탈로그에 항목 없음', + deleteEntry: '항목 삭제', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + resetCatalog: '카탈로그 초기화', + resetConfirm: '카탈로그를 기본값으로 초기화하시겠습니까? 모든 사용자 지정 항목이 제거됩니다.', + loadFailed: '스풀 카탈로그 로드 실패', + nameWeightRequired: '이름과 무게가 필요합니다', + entryAdded: '항목이 추가되었습니다', + addFailed: '항목 추가 실패', + entryUpdated: '항목이 업데이트되었습니다', + updateFailed: '항목 업데이트 실패', + entryDeleted: '항목이 삭제되었습니다', + deleteFailed: '항목 삭제 실패', + resetSuccess: '카탈로그가 기본값으로 초기화되었습니다', + resetFailed: '카탈로그 초기화 실패', + exported: '{{count}}개 항목이 내보내졌습니다', + imported: '{{added}}개 항목 가져옴 ({{skipped}}개 건너뜀)', + importFailed: '가져오기 실패: 잘못된 JSON 형식', + exportTooltip: 'JSON으로 카탈로그 내보내기', + importTooltip: 'JSON에서 카탈로그 가져오기', + resetTooltip: '기본값으로 초기화', + selectedCount: '{{count}}개 선택됨', + deleteSelected: '선택 항목 삭제', + bulkDeleteConfirm: '{{count}}개 항목을 삭제하시겠습니까?', + bulkDeleted: '{{count}}개 항목이 삭제되었습니다', + bulkDeleteFailed: '항목 삭제 실패', + material: '재료', + spoolWeight: '스풀 무게', + color: '색상', + updateSpoolWeight: '스풀 무게 업데이트', + filamentUpdated: '필라멘트가 업데이트되었습니다', + filamentUpdateFailed: '필라멘트 업데이트 실패', + filamentUpdateInvalid: '잘못된 필라멘트 데이터', + keepExistingSpoolWeight: '기존 스풀에 이전 무게 유지', + keepExistingSpoolWeightDesc: '이 필라멘트 유형으로 이미 생성된 스풀은 이전 공 무게를 유지합니다. 새 스풀은 업데이트된 값을 사용합니다.', + applyToAllSpools: '모든 스풀에 적용', + applyToAllSpoolsDesc: '이 필라멘트 유형의 모든 무게 계산이 즉시 새 공 무게를 사용합니다.' + }, + colorCatalog: { + title: '색상 카탈로그', + description: '제조사/재료별 필라멘트 색상. 스풀 추가 시 자동 색상 조회에 사용됩니다.', + searchColors: '색상 검색...', + allManufacturers: '모든 제조사', + addNewColor: '새 색상 추가', + manufacturer: '제조사', + colorName: '색상 이름', + hex: '헥스', + materialOptional: '재료 (선택사항)', + showing: '{{total}}개 중 {{filtered}}개 색상 표시', + noMatch: '검색에 일치하는 색상 없음', + empty: '카탈로그에 색상 없음', + deleteColor: '색상 삭제', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + resetCatalog: '색상 카탈로그 초기화', + resetConfirm: '카탈로그를 기본값으로 초기화하시겠습니까? 모든 사용자 지정 색상이 제거됩니다.', + sync: '동기화', + starting: '시작 중...', + syncTooltip: 'FilamentColors.xyz에서 동기화 (2000개 이상 색상, 약 1분 소요)', + loadFailed: '색상 카탈로그 로드 실패', + fieldsRequired: '제조사, 색상 이름, 헥스 색상이 필요합니다', + colorAdded: '색상이 추가되었습니다', + addFailed: '색상 추가 실패', + colorUpdated: '색상이 업데이트되었습니다', + updateFailed: '색상 업데이트 실패', + colorDeleted: '색상이 삭제되었습니다', + deleteFailed: '색상 삭제 실패', + resetSuccess: '색상 카탈로그가 기본값으로 초기화되었습니다', + resetFailed: '카탈로그 초기화 실패', + syncUpToDate: '이미 최신 상태 ({{count}}개 색상 확인됨)', + syncComplete: '{{added}}개 새 색상 추가됨 ({{skipped}}개 이미 존재)', + syncError: '동기화 오류', + syncFailed: 'FilamentColors.xyz에서 동기화 실패', + exported: '{{count}}개 색상이 내보내졌습니다', + imported: '{{added}}개 색상 가져옴 ({{skipped}}개 건너뜀)', + importFailed: '가져오기 실패: 잘못된 JSON 형식', + selectedCount: '{{count}}개 선택됨', + deleteSelected: '선택 항목 삭제', + bulkDeleteConfirm: '{{count}}개 색상을 삭제하시겠습니까?', + bulkDeleted: '{{count}}개 색상이 삭제되었습니다', + bulkDeleteFailed: '색상 삭제 실패' + }, + dateFormat: '날짜 형식', + dateFormatUs: '미국 (MM/DD/YYYY)', + dateFormatEu: '유럽 (DD/MM/YYYY)', + dateFormatIso: 'ISO (YYYY-MM-DD)', + timeFormat: '시간 형식', + timeFormat12: '12시간 (오후 3:30)', + timeFormat24: '24시간 (15:30)', + defaultPrinter: '기본 프린터', + defaultPrinterDescription: '업로드, 재인쇄 등 작업에서 이 프린터를 미리 선택합니다.', + slicerBambuStudio: 'Bambu Studio', + slicerOrcaSlicer: 'OrcaSlicer', + sidebarOrderDescription: '사이드바의 항목을 드래그하여 순서를 변경하세요. 여기서 기본 순서로 초기화하세요.', + setDefault: '기본값 설정', + sidebarOrderSetDefaultHint: '기본값 설정은 현재 메뉴 순서를 사용자 지정하지 않은 사용자에게 적용합니다.', + sidebarDefaultSet: '기본 메뉴 순서가 설정되었습니다.', + sidebarDefaultCleared: '기본 메뉴 순서가 지워졌습니다.', + sidebarDefaultFailed: '기본 메뉴 순서 설정 실패.', + reset: '초기화', + darkMode: '다크 모드', + lightMode: '라이트 모드', + active: '(활성)', + background: '배경', + accent: '강조', + style: '스타일', + bgNeutral: '중립', + bgWarm: '따뜻함', + bgCool: '시원함', + bgOled: 'OLED 블랙', + bgSlate: '슬레이트 블루', + bgForest: '포레스트 그린', + accentGreen: '그린', + accentTeal: '틸', + accentBlue: '블루', + accentOrange: '오렌지', + accentPurple: '퍼플', + accentRed: '레드', + styleClassic: '클래식', + styleGlow: '글로우', + styleVibrant: '비브런트', + themeToggleHint: '사이드바의 태양/달 아이콘으로 다크 모드와 라이트 모드를 전환하세요.', + autoArchivePrints: '인쇄 자동 아카이브', + autoArchiveDescription: '인쇄 완료 시 3MF 파일 자동 저장', + saveThumbnailsDescription: '3MF 파일에서 미리보기 이미지 추출 및 저장', + captureFinishPhotoDescription: '인쇄 완료 시 프린터 카메라로 사진 촬영', + ffmpegNotInstalled: 'ffmpeg 미설치', + ffmpegRequired: '카메라 캡처에 ffmpeg가 필요합니다. macOS에서는 brew install ffmpeg, Linux에서는 apt install ffmpeg로 설치하세요.', + camera: '카메라', + cameraViewMode: '카메라 보기 모드', + cameraOverlayDescription: '카메라가 메인 화면의 크기 조절 가능한 오버레이에서 열립니다', + cameraWindowDescription: '카메라가 별도의 브라우저 창에서 열립니다', + externalCamerasDescription: '내장 프린터 카메라를 교체할 외부 카메라를 설정하세요. MJPEG 스트림, RTSP, HTTP 스냅샷, USB 카메라(V4L2)를 지원합니다.', + cameraPlaceholderUsb: '장치 경로 (/dev/video0)', + cameraPlaceholderUrl: '카메라 URL (rtsp://... 또는 http://...)', + cameraTypeMjpeg: 'MJPEG 스트림', + cameraTypeRtsp: 'RTSP 스트림', + cameraTypeSnapshot: 'HTTP 스냅샷', + cameraTypeUsb: 'USB 카메라 (V4L2)', + cameraSnapshotUrl: '스냅샷 URL (선택사항)', + cameraSnapshotUrlPlaceholder: 'http://192.168.1.61:1984/api/frame.jpeg?src=printer', + cameraSnapshotUrlHelp: '알림 썸네일, 완료 사진, 타임랩스, 플레이트 감지에 사용되는 단일 프레임 URL.', + cameraRotation: '회전', + test: '테스트', + connected: '연결됨', + disconnected: '연결 끊김', + currency: '통화', + defaultFilamentCost: '기본 필라멘트 비용 (kg당)', + electricityCost: 'kWh당 전기 비용', + energyDisplayMode: '에너지 표시 모드', + energyModePrintDescription: '대시보드가 인쇄 중 사용된 에너지 합계를 표시', + energyModeTotalDescription: '대시보드가 스마트 플러그의 전체 에너지를 표시', + fileManager: '파일 관리자', + createArchiveEntry: '인쇄 시 아카이브 항목 생성', + createArchiveEntryDescription: '파일 관리자에서 인쇄할 때 선택적으로 아카이브 항목 생성', + lowDiskSpaceWarning: '디스크 공간 부족 경고', + lowDiskSpaceDescription: '여유 디스크 공간이 이 임계값 아래로 떨어지면 경고 표시', + printerFirmware: '프린터 펌웨어', + checkFirmwareDescription: 'Bambu Lab의 프린터 펌웨어 업데이트 확인', + bambuddySoftware: 'Bambuddy 소프트웨어', + autoCheckDescription: '시작 시 자동으로 새 버전 확인', + checkNow: '지금 확인', + updateAvailableVersion: '업데이트 가능: v{{version}}', + releaseNotes: '릴리스 노트', + updateViaDocker: 'Docker Compose로 업데이트:', + updateViaHomeAssistant: '업데이트는 Home Assistant 수퍼바이저에서 관리됩니다. Home Assistant에서 설정 → 애드온 → Bambuddy를 열어 새 버전을 설치하세요.', + installUpdate: '업데이트 설치', + latestVersionRunning: '최신 버전을 실행 중입니다', + failedToCheckUpdates: '업데이트 확인 실패: {{error}}', + backupRestore: '백업 및 복원', + backupRestoreDescription: '설정 내보내기/가져오기 및 GitHub 백업 설정', + goToBackup: '백업으로 이동', + externalUrl: '외부 URL', + externalUrlDescription: 'Bambuddy에 접근할 수 있는 외부 URL. 알림 이미지 및 외부 통합에 사용됩니다.', + bambuddyUrl: 'Bambuddy URL', + externalUrlHint: '프로토콜과 포트를 포함하세요 (예: http://192.168.1.100:8000)', + ftpRetry: 'FTP 재시도', + ftpRetryDescription: '프린터 WiFi가 불안정할 때 FTP 작업을 재시도합니다.', + autoRetryDescription: '실패한 FTP 작업 자동 재시도', + retryAttempts: '재시도 횟수', + retryDelay: '재시도 지연', + connectionTimeout: '연결 제한 시간', + time_one: '{{count}}번', + time_other: '{{count}}번', + second_one: '{{count}}초', + second_other: '{{count}}초', + nSeconds: '{{count}}초', + increaseForWeakWifi: 'WiFi가 약한 프린터에서 늘리세요', + homeAssistant: 'Home Assistant', + homeAssistantFullDescription: 'Home Assistant의 REST API를 통해 스마트 플러그를 제어하려면 연결하세요.', + homeAssistantUrl: 'Home Assistant URL', + longLivedAccessToken: '장기 액세스 토큰', + haTokenHint: 'HA에서 토큰 생성: 프로필 → 장기 액세스 토큰 → 토큰 생성', + connectionSuccessful: '연결 성공', + connectionFailed: '연결 실패', + haConnectionSuccess: 'Home Assistant에 성공적으로 연결되었습니다.', + haConnectionFailed: 'Home Assistant 연결 실패.', + mqttPublishing: 'MQTT 게시', + mqttDescription: 'Node-RED, Home Assistant 등 자동화 시스템과 통합하기 위해 Bambuddy 이벤트를 외부 MQTT 브로커에 게시하세요.', + mqttEnableDescription: '외부 MQTT 브로커에 이벤트 게시', + brokerHostname: '브로커 호스트명', + port: '포트', + usernameOptional: '사용자명 (선택사항)', + passwordOptional: '비밀번호 (선택사항)', + topicPrefix: '토픽 접두사', + topicPrefixHint: '토픽은 다음과 같습니다: {{prefix}}/printers//status 등', + prometheusMetrics: 'Prometheus 메트릭', + prometheusEndpointDescription: 'Prometheus/Grafana 모니터링을 위해 /api/v1/metrics에서 프린터 메트릭을 노출합니다.', + bearerTokenOptional: '베어러 토큰 (선택사항)', + bearerTokenHint: '설정하면 요청에 Authorization: Bearer 을 포함해야 합니다', + metricsConnectionStatus: '연결 상태', + metricsPrinterState: '프린터 상태 (유휴/인쇄 중/등)', + metricsPrintProgress: '인쇄 진행 0-100%', + metricsBedTemp: '베드 온도', + metricsNozzleTemp: '노즐 온도', + metricsPrintsTotal: '결과별 총 인쇄 수', + metricsMore: '...및 더 많은 것 (레이어, 팬, 대기열, 필라멘트 사용량)', + smartPlugsDescription: '에너지 사용량 추적 및 프린터 전원 제어를 자동화하기 위해 스마트 플러그(Tasmota 또는 Home Assistant)를 연결하세요.', + allOn: '모두 켜기', + allOff: '모두 끄기', + addSmartPlug: '스마트 플러그 추가', + energySummary: '에너지 요약', + currentPower: '현재 전력', + plugsOnline: '{{reachable}}/{{total}}개 플러그 온라인', + today: '오늘', + yesterday: '어제', + total: '총계', + enablePlugsForSummary: '에너지 요약을 보려면 플러그를 활성화하세요', + addNotificationProvider: '추가', + systemBadge: '(시스템)', + creating: '생성 중...', + changing: '변경 중...', + deleteUserAndItems: '사용자 및 항목 삭제', + deleteUserKeepItems: '사용자 삭제, 항목 유지 (소유자 없음)', + ok: '확인', + twoFa: { + totpTitle: '인증 앱 (TOTP)', + totpDesc: 'Google Authenticator, Aegis, Authy 같은 인증 앱을 사용하세요.', + emailOtpTitle: '이메일 OTP', + emailOtpDesc: '로그인 시 {{email}}로 일회용 코드를 전송합니다.', + emailOtpNoEmail: '이 방법을 활성화하려면 계정에 이메일 주소를 추가하세요.', + addEmailFirst: '계정에 이메일 주소가 없습니다. 이메일 OTP를 활성화하기 전에 관리자에게 추가를 요청하세요.', + setupTotp: '인증 앱 설정', + setupAuthApp: '인증 앱 설정', + setupInstructions: '아래 QR 코드를 인증 앱으로 스캔한 후 코드로 확인하세요.', + manualEntry: '스캔할 수 없나요? 이 비밀을 수동으로 입력하세요:', + scannedContinue: '코드를 스캔했습니다 — 계속', + enterCodeToConfirm: '인증 앱의 6자리 코드를 입력하여 설정을 확인하세요.', + activate: '활성화', + disableTotp: '인증기 비활성화', + disableConfirmHint: '인증기를 비활성화하려면 유효한 TOTP 코드나 백업 코드를 입력하세요.', + totpDisabled: '인증 앱이 비활성화되었습니다.', + emailOtpEnabled: '이메일 OTP가 활성화되었습니다.', + emailOtpDisabled: '이메일 OTP가 비활성화되었습니다.', + smtpRequired: '먼저 SMTP 설정을 구성하고 테스트하세요.', + invalidCode: '잘못된 코드입니다. 다시 시도하세요.', + enableEmailOtp: '이메일 OTP 활성화', + disableEmailOtp: '이메일 OTP 비활성화', + emailSetupEnterCode: '이메일 주소로 인증 코드가 전송되었습니다. 아래에 입력하여 이 받은 편지함을 소유하고 있음을 확인하세요.', + verifyAndEnable: '확인 및 활성화', + emailDisablePasswordHint: '이메일 OTP 비활성화를 확인하려면 계정 비밀번호를 입력하세요.', + passwordPlaceholder: '비밀번호 입력', + backupCodesTitle: '백업 코드 저장', + backupCodesWarning: '이 코드를 안전한 곳에 저장하세요. 각 코드는 한 번만 사용할 수 있으며 다시 표시되지 않습니다.', + backupCodesRemaining: '{{count}}개 백업 코드 남음', + savedCodes: '코드를 저장했습니다', + regenBackup: '백업 코드 재생성', + regenBackupHint: '현재 TOTP 코드를 입력하여 10개의 새 백업 코드를 생성하세요. 기존 백업 코드는 모두 무효화됩니다.', + newBackupCodes: '새 백업 코드', + linkedAccounts: '연결된 SSO 계정', + linkedAccountsDesc: '이 외부 ID 제공자가 계정에 연결되어 있습니다.', + oidcUnlinked: '계정 연결이 해제되었습니다.' + }, + oidc: { + title: 'SSO / OIDC 제공자', + desc: '외부 ID 제공자를 통해 싱글 사인온을 허용하도록 OpenID Connect 제공자를 설정하세요.', + addProvider: '제공자 추가', + newProvider: '새 제공자', + empty: '아직 설정된 OIDC 제공자가 없습니다.', + created: '제공자가 생성되었습니다.', + updated: '제공자가 업데이트되었습니다.', + deleted: '제공자가 삭제되었습니다.', + deleteTitle: '제공자 삭제', + deleteMessage: '\"{{name}}\"을(를) 삭제하시겠습니까? 연결된 모든 사용자 계정의 연결이 해제됩니다.', + form: { + name: '표시 이름', + issuerUrl: '발급자 URL', + clientId: '클라이언트 ID', + clientSecret: '클라이언트 시크릿', + scopes: '범위', + iconUrl: '아이콘 URL (선택사항)', + enabled: '활성화됨', + autoCreate: '사용자 자동 생성', + autoCreateDesc: '첫 번째 로그인 시 자동으로 로컬 계정 생성.', + autoLink: '기존 계정 자동 연결', + autoLinkDesc: '첫 번째 로그인 시 이메일 일치로 기존 로컬 계정 연결.', + secretHint: '현재 값을 유지하려면 비워두세요', + secretPlaceholder: '새 시크릿', + emailClaim: '이메일 클레임', + emailClaimDesc: '이메일 ID로 사용되는 JWT 클레임.', + emailClaimPlaceholder: 'email', + emailClaimCustomClaimAutoLinkWarning: '사용자 지정 클레임은 값이 테넌트 관리인 경우에만 자동 연결에 안전합니다. IdP가 사용자가 이 클레임을 직접 주장할 수 있게 하면 자동 연결을 활성화하지 마세요.', + requireEmailVerified: '이메일 확인 필요', + requireEmailVerifiedDesc: '제공자가 확인된 것으로 표시한 경우에만 이메일 클레임을 수락합니다.', + requireEmailVerifiedWarning: '경고: 확인 없이도 이메일이 수락됩니다. 신뢰할 수 있는 제공자에만 사용하세요.', + requireEmailVerifiedAutoLink: '이 설정을 변경하려면 먼저 자동 연결을 비활성화하세요.', + defaultGroup: '기본 그룹', + defaultGroupDesc: '자동 생성된 사용자에게 할당되는 그룹. 설정되지 않으면 Viewers로 대체됩니다.', + defaultGroupViewersFallback: 'Viewers (기본값)' + }, + refreshIcon: '아이콘 새로고침', + removeIcon: '아이콘 제거', + iconRefreshed: '아이콘이 새로고침되었습니다.', + iconRemoved: '아이콘이 제거되었습니다.', + iconFetchFailed: '공급자 URL에서 아이콘을 가져올 수 없습니다.' + }, + encryption: { + title: 'MFA 암호화 상태', + enabledFromEnv: '저장 시 암호화 활성화됨 (MFA_ENCRYPTION_KEY 환경 변수에서 키)', + enabledFromFile: '저장 시 암호화 활성화됨 (데이터 디렉토리에서 키 로드됨)', + enabledGenerated: '자동 생성된 키로 저장 시 암호화 활성화됨', + notConfigured: '저장 시 암호화가 설정되지 않음', + notConfiguredDesc: 'TOTP 시크릿 및 OIDC client_secret이 일반 텍스트로 저장됩니다. MFA_ENCRYPTION_KEY를 설정하거나 쓰기 가능한 데이터 디렉토리로 Bambuddy를 재시작하여 자동 생성하세요.', + allEncrypted: '모든 MFA 시크릿이 저장 시 암호화되어 있습니다.', + legacyRowsLabel: '레거시 일반 텍스트 행', + encryptedRowsLabel: '암호화된 행', + legacyRowsWarning: '{{count}}개 레거시 일반 텍스트 행이 감지되었습니다. 암호화된 저장소로 마이그레이션하려면 OIDC 제공자를 다시 저장하거나 사용자의 인증 앱을 재등록하세요.', + backupHint: '자동 생성된 키는 DATA_DIR/.mfa_encryption_key에 저장되며 로컬 백업 ZIP에 포함됩니다. 백업을 안전하게 보관하거나 MFA_ENCRYPTION_KEY를 명시적으로 설정하세요.', + decryptionBrokenTitle: '암호화 키 누락', + decryptionBrokenError: '암호화 키를 더 이상 사용할 수 없어 {{count}}개의 암호화된 레코드를 복호화할 수 없습니다.', + migrationErrorWarning: '시작 시 {{count}}개 레거시 행을 재암호화하지 못했습니다. 서버 로그를 확인하고 Bambuddy를 재시작하여 재시도하세요.' + }, + updateEnergyCost: '전기 요금 업데이트', + updateEnergyCostDescription: '이 키가 /settings/electricity-price에 새 kWh당 전기 요금을 POST할 수 있도록 허용합니다. Home Assistant 동적 요금 자동화(Tibber, Octopus 등)에 유용합니다. API 키로 쓸 수 있는 유일한 설정 필드입니다.', + energyCostBadge: '에너지', + passwordRequirements: '최소 8자, 대문자, 소문자, 숫자, 특수문자 각 1개 이상 포함' + }, + notification: { + printStarted: { + title: '인쇄 시작됨', + body: '{{printer}}: {{filename}} 인쇄가 시작되었습니다' + }, + printCompleted: { + title: '인쇄 완료됨', + body: '{{printer}}: {{filename}}이(가) 성공적으로 완료되었습니다' + }, + printFailed: { + title: '인쇄 실패', + body: '{{printer}}: {{filename}}이(가) 실패했습니다' + }, + printStopped: { + title: '인쇄 정지됨', + body: '{{printer}}: {{filename}}이(가) 정지되었습니다' + }, + printProgress: { + title: '인쇄 진행', + body: '{{printer}}: {{filename}} {{percent}}% 완료' + }, + printerOffline: { + title: '프린터 오프라인', + body: '{{printer}}이(가) 오프라인 상태입니다' + }, + printerError: { + title: '프린터 오류', + body: '{{printer}}: {{error}}' + }, + filamentLow: { + title: '필라멘트 부족', + body: '{{printer}}: 필라멘트가 부족합니다' + }, + maintenanceDue: { + title: '유지보수 예정', + body: '{{printer}}: {{items}} 주의 필요' + } + }, + errors: { + generic: '문제가 발생했습니다', + networkError: '네트워크 오류. 연결을 확인하세요.', + notFound: '찾을 수 없습니다', + unauthorized: '권한 없음', + serverError: '서버 오류', + validationError: '입력값을 확인하세요', + printerConnectionFailed: '프린터 연결 실패', + saveFailed: '변경사항 저장 실패', + deleteFailed: '삭제 실패', + loadFailed: '데이터 로드 실패' + }, + hmsErrors: { + title: '오류 - {{name}}', + noErrors: '오류 없음', + viewOnWiki: 'Bambu Lab 위키에서 보기', + clearInstructions: '오류를 해제하려면 프린터에서 오류를 지우세요.', + clearErrors: '오류 지우기', + clearSuccess: 'HMS 오류가 지워졌습니다', + clearFailed: 'HMS 오류 지우기 실패' + }, + mqttDebug: { + title: 'MQTT 디버그 로그', + searchPlaceholder: '토픽 또는 페이로드 검색...', + noMessages: '아직 기록된 메시지 없음', + startLoggingHint: '\"로깅 시작\"을 클릭하여 MQTT 메시지 캡처 시작', + noMessagesMatch: '필터에 일치하는 메시지 없음', + adjustFilterHint: '검색 또는 필터 기준을 조정해 보세요', + incoming: '수신', + outgoing: '송신', + loggingStopped: '로깅 정지됨', + loggingActive: '로깅 활성 - 메시지가 자동 새로고침됨', + startLogging: '로깅 시작', + stopLogging: '로깅 정지', + clearLog: '로그 지우기', + topic: '토픽', + timestamp: '타임스탬프', + direction: '방향', + all: '전체' + }, + printerFiles: { + title: '파일 관리자', + storageUsed: '사용됨:', + storageFree: '여유:', + filterPlaceholder: '파일 필터...', + deleteButton: '삭제', + deleteFiles: '{{count}}개 파일 삭제', + deleteFileConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + deleteFilesConfirm: '선택된 {{count}}개 파일을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + noFiles: '프린터에 파일 없음', + loadingFiles: '파일 로딩 중...', + failedToLoad: '파일 로드 실패', + toast: { + filesDeleted: '{{count}}개 파일이 삭제되었습니다', + deleteFailed: '삭제 실패: {{error}}' + } + }, + confirm: { + delete: '이것을 삭제하시겠습니까?', + unsavedChanges: '저장되지 않은 변경사항이 있습니다. 정말 나가시겠습니까?', + clearQueue: '대기열을 지우시겠습니까?' + }, + login: { + title: 'Bambuddy 로그인', + subtitle: '계정에 로그인하세요', + username: '사용자명', + usernamePlaceholder: '사용자명을 입력하세요', + usernameOrEmail: '사용자명 또는 이메일', + usernameOrEmailPlaceholder: '사용자명 또는 @ 이메일', + password: '비밀번호', + passwordPlaceholder: '비밀번호를 입력하세요', + signIn: '로그인', + signingIn: '로그인 중...', + rememberMe: '로그인 유지', + forgotPassword: '비밀번호를 잊으셨나요?', + loginSuccess: '성공적으로 로그인되었습니다', + loginFailed: '로그인 실패', + enterCredentials: '사용자명과 비밀번호를 입력하세요', + enterEmail: '이메일 주소를 입력하세요', + oidcLoginFailed: 'OIDC 로그인 실패', + oidcErrors: { + providerError: 'ID 제공자에서 오류가 반환되었습니다', + missingParameters: 'OIDC 콜백에 필수 매개변수가 없습니다', + invalidState: 'OIDC 상태가 잘못되었거나 이미 사용되었습니다', + stateExpired: 'OIDC 로그인 세션이 만료되었습니다 — 다시 시도하세요', + providerNotFound: 'OIDC 제공자를 찾을 수 없습니다', + discoveryFailed: 'OIDC 검색 문서를 가져오지 못했습니다', + invalidDiscovery: 'OIDC 검색 문서가 잘못되었습니다', + networkError: 'OIDC 토큰 교환 중 네트워크 오류', + badResponse: 'OIDC 토큰 교환 중 예상치 못한 응답', + noIdToken: 'OIDC 제공자가 ID 토큰을 반환하지 않았습니다', + validationFailed: 'OIDC 토큰 검증 실패', + nonceMismatch: 'OIDC 논스 불일치 — 재생 공격 가능성', + missingSubClaim: 'OIDC 토큰에 sub 클레임이 없습니다', + noLinkedAccount: 'OIDC ID에 연결된 로컬 계정이 없습니다', + accountInactive: '계정이 비활성 상태입니다', + userResolutionFailed: '계정 확인 실패', + internalError: 'OIDC 로그인 중 내부 오류 발생', + tokenExchangeFailed: 'OIDC 토큰 교환 실패' + }, + forgotPasswordTitle: '비밀번호 찾기', + forgotPasswordMessage: '비밀번호를 잊으셨다면 시스템 관리자에게 초기화를 요청하세요.', + forgotPasswordEmailMessage: '이메일 주소를 입력하면 새 비밀번호를 전송해 드립니다.', + emailAddress: '이메일 주소', + emailPlaceholder: 'your.email@example.com', + cancel: '취소', + sending: '전송 중...', + sendResetEmail: '초기화 이메일 전송', + howToReset: '비밀번호 초기화 방법:', + resetStep1: 'Bambuddy 관리자에게 문의하세요', + resetStep2: '사용자 관리에서 비밀번호 초기화를 요청하세요', + resetStep3: '관리자가 임시 비밀번호를 설정해 드립니다', + resetStep4: '새 비밀번호로 로그인하고 설정에서 변경하세요', + gotIt: '확인', + resetPassword: { + title: '새 비밀번호 설정', + subtitle: '아래에 새 비밀번호를 입력하고 확인하세요.', + newPassword: '새 비밀번호', + newPasswordPlaceholder: '최소 8자', + confirmPassword: '비밀번호 확인', + confirmPasswordPlaceholder: '새 비밀번호 반복', + saving: '저장 중…', + submit: '새 비밀번호 설정', + backToLogin: '로그인으로 돌아가기', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + passwordTooShort: '비밀번호는 최소 8자여야 합니다', + resetFailed: '비밀번호 초기화 실패. 링크가 만료되었을 수 있습니다.' + }, + twoFA: { + title: '이중 인증', + subtitle: '계정이 2FA로 보호되어 있습니다. 아래에 인증 코드를 입력하세요.', + methodAuthenticator: '인증 앱', + methodEmail: '이메일 코드', + methodBackup: '백업 코드', + instructionsTotp: '인증 앱을 열고 Bambuddy의 6자리 코드를 입력하세요.', + instructionsEmail: '이메일 주소로 6자리 코드가 전송되었습니다. 10분 후 만료됩니다.', + instructionsEmailNotSent: '아래 버튼을 클릭하여 이메일로 인증 코드를 받으세요.', + instructionsBackup: '8자리 백업 복구 코드 중 하나를 입력하세요. 각 코드는 한 번만 사용할 수 있습니다.', + sendCodeButton: '이메일로 코드 전송', + sendingCode: '전송 중...', + resendCode: '코드 재전송', + codeLabel: '인증 코드', + backupCodeLabel: '백업 코드', + codePlaceholder: '000000', + backupCodePlaceholder: 'XXXXXXXX', + verifyButton: '확인', + verifyingButton: '확인 중...', + backToLogin: '← 로그인으로 돌아가기', + orContinueWith: '또는 계속', + signInWith: '{{provider}}로 로그인', + enterCode: '인증 코드를 입력하세요', + sendCodeFailed: '인증 코드 전송 실패', + invalidCode: '잘못된 코드입니다. 다시 시도하세요.' + } + }, + setup: { + title: 'Bambuddy 설정', + subtitle: 'Bambuddy 인스턴스의 인증을 설정하세요', + enableAuth: '인증 활성화', + adminAccount: '관리자 계정', + adminAccountDesc: '관리자 사용자가 이미 있는 경우 기존 관리자 계정으로 인증이 활성화됩니다. 기존 관리자를 사용하려면 아래 필드를 비워두거나, 새 관리자 사용자를 만들려면 자격 증명을 입력하세요.', + adminUsername: '관리자 사용자명', + adminPassword: '관리자 비밀번호', + optionalIfAdminExists: '(관리자 사용자가 있는 경우 선택사항)', + adminUsernamePlaceholder: '관리자 사용자명 입력 (선택사항)', + adminPasswordPlaceholder: '관리자 비밀번호 입력 (선택사항)', + confirmPassword: '비밀번호 확인', + confirmPasswordPlaceholder: '관리자 비밀번호 확인', + settingUp: '설정 중...', + completeSetup: '설정 완료', + toast: { + authEnabledAdminCreated: '인증 활성화 및 관리자 사용자 생성됨', + authEnabledExistingAdmins: '기존 관리자 사용자로 인증 활성화됨', + setupCompleted: '설정이 완료되었습니다', + enterBothCredentials: '관리자 사용자명과 비밀번호를 모두 입력하거나, 기존 관리자 사용자를 사용하려면 둘 다 비워두세요', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + passwordTooShort: '비밀번호는 최소 6자여야 합니다' + } + }, + changePassword: { + title: '비밀번호 변경', + currentPassword: '현재 비밀번호', + currentPasswordPlaceholder: '현재 비밀번호 입력', + newPassword: '새 비밀번호', + newPasswordPlaceholder: '새 비밀번호 입력 (최소 6자)', + confirmPassword: '새 비밀번호 확인', + confirmPasswordPlaceholder: '새 비밀번호 확인', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + passwordTooShort: '비밀번호는 최소 6자여야 합니다', + changing: '변경 중...', + success: '비밀번호가 성공적으로 변경되었습니다', + failed: '비밀번호 변경 실패' + }, + plateAlert: { + title: '인쇄 일시정지됨!', + message: '빌드 플레이트에 객체가 감지되었습니다. 인쇄가 자동으로 일시정지되었습니다. 플레이트를 비우고 인쇄를 재개하세요.', + understand: '확인했습니다' + }, + camera: { + title: '카메라 보기', + invalidPrinterId: '유효하지 않은 프린터 ID', + live: '실시간', + snapshot: '스냅샷', + restartStream: '스트림 재시작', + refreshSnapshot: '스냅샷 새로고침', + fullscreen: '전체 화면', + exitFullscreen: '전체 화면 종료', + connectingToCamera: '카메라에 연결 중...', + capturingSnapshot: '스냅샷 캡처 중...', + connectionLost: '연결 끊김', + connectionFailed: '카메라 연결 실패', + reconnecting: '{{countdown}}초 후 재연결 중... (시도 {{attempt}}/{{max}})', + reconnectNow: '지금 재연결', + cameraUnavailable: '카메라를 사용할 수 없음', + cameraUnavailableDesc: '프린터가 켜져 있고 연결되어 있는지 확인하세요.', + noCamera: '사용 가능한 카메라 없음', + retry: '다시 시도', + cameraStream: '카메라 스트림', + zoomOut: '축소', + zoomIn: '확대', + resetZoom: '배율 초기화', + recording: '녹화 중', + startRecording: '녹화 시작', + stopRecording: '녹화 중지', + chamberLight: '챔버 조명 전환', + unavailable: '카메라 사용 불가', + diagnose: { + button: '진단', + modalTitle: '카메라 진단', + running: '진단 실행 중...', + runFailed: '진단 실행 실패: {{error}}', + retry: '다시 실행', + stage: { + tcp_reachable: '네트워크 연결 가능 여부', + first_frame: '프레임 캡처', + live_stream_active: '라이브 스트림 활성' + }, + summary: { + all_ok: '카메라가 정상 작동 중입니다. 모든 단계를 성공적으로 완료했습니다.', + live_stream_active_healthy: '카메라가 최근 프레임으로 스트리밍 중입니다 — 테스트가 필요 없습니다.', + printer_unreachable: '프린터에 연결할 수 없습니다. IP 주소, 네트워크 연결, 프린터 전원을 확인하세요.', + camera_port_closed: '프린터에 연결됐지만 카메라 포트가 닫혀 있습니다. 프린터 설정에서 LAN 전용 모드와 개발자 모드가 활성화되어 있는지 확인하세요.', + no_frame: '카메라에 연결됐지만 프레임이 수신되지 않았습니다. 다시 시도하거나 프린터 설정에서 카메라가 활성화되어 있는지 확인하세요.', + unknown_failure: '알 수 없는 이유로 카메라 진단에 실패했습니다. 지원 로그를 확인하세요.' + }, + meta: { + protocol: '프로토콜', + port: '포트', + profile: '프로파일' + } + } + }, + groups: { + title: '그룹 관리', + subtitle: '접근 제어를 위한 권한 그룹 관리', + backToSettings: '설정으로 돌아가기', + createGroup: '그룹 생성', + noPermission: '이 페이지에 접근할 권한이 없습니다.', + system: '시스템', + noDescription: '설명 없음', + usersCount: '{{count}}명의 사용자', + permissionsCount: '{{count}}개의 권한', + edit: '편집', + delete: '삭제', + toast: { + created: '그룹이 성공적으로 생성되었습니다', + updated: '그룹이 성공적으로 업데이트되었습니다', + deleted: '그룹이 성공적으로 삭제되었습니다', + enterGroupName: '그룹 이름을 입력해 주세요' + }, + modal: { + editGroup: '그룹 편집', + createGroup: '그룹 생성', + cancel: '취소', + saving: '저장 중...', + creating: '생성 중...', + saveChanges: '변경 사항 저장' + }, + form: { + groupName: '그룹 이름', + groupNamePlaceholder: '그룹 이름 입력', + systemGroupWarning: '시스템 그룹 이름은 변경할 수 없습니다', + description: '설명', + descriptionPlaceholder: '설명 입력 (선택사항)', + permissions: '권한 ({{count}}개 선택됨)' + }, + deleteModal: { + title: '그룹 삭제', + message: '이 그룹을 삭제하시겠습니까? 이 그룹의 사용자는 해당 권한을 잃게 됩니다.', + confirm: '그룹 삭제' + }, + editor: { + title: '그룹 편집', + createTitle: '그룹 생성', + search: '권한 검색...', + selectAll: '모두 선택', + clearAll: '모두 해제', + permissionsSelected: '{{count}}개 선택됨', + noResults: '검색과 일치하는 권한이 없습니다' + } + }, + users: { + title: '사용자 관리', + subtitle: 'Bambuddy 인스턴스에 대한 사용자 및 접근 권한 관리', + backToSettings: '설정으로 돌아가기', + createUser: '사용자 생성', + noPermission: '이 페이지에 접근할 권한이 없습니다.', + admin: '관리자', + noGroups: '그룹 없음', + active: '활성', + inactive: '비활성', + edit: '편집', + delete: '삭제', + system: '시스템', + noGroupsAvailable: '사용 가능한 그룹 없음', + table: { + username: '사용자 이름', + groups: '그룹', + status: '상태', + actions: '작업' + }, + toast: { + created: '사용자가 성공적으로 생성되었습니다', + updated: '사용자가 성공적으로 업데이트되었습니다', + deleted: '사용자가 성공적으로 삭제되었습니다', + fillRequired: '모든 필수 항목을 입력해 주세요', + passwordsDoNotMatch: '비밀번호가 일치하지 않습니다', + passwordTooShort: '비밀번호는 최소 6자 이상이어야 합니다', + ldapProvisioned: 'LDAP 사용자 \"{{username}}\"이(가) 생성되었습니다' + }, + modal: { + createUser: '사용자 생성', + editUser: '사용자 편집', + cancel: '취소', + creating: '생성 중...', + saving: '저장 중...', + saveChanges: '변경 사항 저장', + advancedAuthSubtitle: '고급 인증 사용', + tabsAriaLabel: '사용자 소스', + localTab: '로컬', + ldapTab: 'LDAP', + ldapSearchLabel: '디렉터리 검색', + ldapSearchPlaceholder: '사용자명, 이름, 이메일을 입력하세요...', + ldapMinChars: '검색하려면 최소 2자 이상 입력하세요', + ldapTypeToSearch: 'LDAP 디렉터리를 검색하려면 입력을 시작하세요', + ldapSearching: '디렉터리 검색 중...', + ldapNoResults: '디렉터리에서 일치하는 사용자가 없습니다', + ldapSearchError: '디렉터리 검색에 실패했습니다. LDAP 서버 상태를 확인하세요.', + ldapAlreadyProvisioned: '이미 생성됨', + ldapSelectedLabel: '선택됨', + ldapProvision: '사용자 생성', + ldapProvisioning: '생성 중...', + ldapErrorProvision: '생성에 실패했습니다. LDAP 서버 상태를 확인하고 다시 시도하세요.' + }, + form: { + username: '사용자 이름', + usernamePlaceholder: '사용자 이름 입력', + email: '이메일', + emailPlaceholder: 'user@example.com', + password: '비밀번호', + passwordPlaceholder: '비밀번호 입력', + confirmPassword: '비밀번호 확인', + confirmPasswordPlaceholder: '비밀번호 확인', + newPasswordPlaceholder: '새 비밀번호 입력', + confirmNewPasswordPlaceholder: '새 비밀번호 확인', + leaveBlankToKeep: '현재 비밀번호 유지 시 비워두기', + groups: '그룹', + optional: '선택사항', + autoGeneratedPassword: '안전한 비밀번호가 자동으로 생성되어 사용자에게 이메일로 전송됩니다.', + passwordManagedByAdvancedAuth: '비밀번호는 고급 인증에 의해 관리됩니다. \"비밀번호 재설정\"을 사용하여 이메일로 새 비밀번호를 전송하세요.', + resetPassword: '비밀번호 재설정', + resettingPassword: '비밀번호 재설정 중...' + }, + deleteModal: { + title: '사용자 삭제', + message: '이 사용자를 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + confirm: '사용자 삭제' + } + }, + streamOverlay: { + title: '스트림 오버레이', + invalidPrinterId: '유효하지 않은 프린터 ID', + cameraStream: '카메라 스트림', + progress: '진행률', + eta: '예상 완료', + printerIdle: '프린터 대기 중', + printerOffline: '프린터 오프라인', + status: { + printing: '인쇄 중', + paused: '일시 중지됨', + finished: '완료됨', + failed: '실패', + idle: '대기 중', + unknown: '알 수 없음' + } + }, + profiles: { + title: '프로필', + subtitle: '슬라이서 프리셋 및 압력 전진 보정 관리', + tabs: { + cloud: '클라우드 프로필', + local: '로컬 프로필', + kprofiles: 'K-프로필' + }, + localProfiles: { + title: '로컬 프로필', + subtitle: 'OrcaSlicer에서 슬라이서 프리셋 가져오기 및 관리', + import: '프로필 가져오기', + importDesc: '.bbscfg, .bbsflmt, .orca_filament, .zip 또는 .json 파일을 여기에 드롭하세요', + importing: '가져오는 중...', + search: '로컬 프리셋 검색...', + noPresets: '로컬 프리셋 없음', + badge: '로컬', + edit: '편집', + delete: '삭제', + cancel: '취소', + deleteConfirmTitle: '프리셋 삭제', + deleteConfirm: '이 프리셋을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + source: '출처', + inheritsFrom: '상속', + filamentType: '유형', + vendor: '제조사', + compatiblePrinters: '프린터', + nozzleTemp: '노즐 온도', + cost: '비용', + density: '밀도', + pressureAdvance: '압력 전진', + filament: '필라멘트', + process: '프로세스', + printer: '프린터', + toast: { + importSuccess: '{{count}}개 프리셋 가져옴', + importSkipped: '{{count}}개 프리셋 건너뜀 (중복)', + importError: '가져오기 중 {{count}}개 오류 발생', + deleted: '프리셋 삭제됨', + updated: '프리셋 업데이트됨' + }, + noSearchResults: '검색어와 일치하는 프리셋이 없습니다' + }, + connectedAs: '연결된 계정', + logout: '로그아웃', + noLogoutPermission: '로그아웃 권한이 없습니다', + failedToLoad: '프로필 불러오기 실패', + retry: '다시 시도', + time: { + justNow: '방금', + minsAgo: '{{count}}분 전', + hoursAgo: '{{count}}시간 전', + daysAgo: '{{count}}일 전' + }, + toast: { + loggedOut: '로그아웃되었습니다' + }, + login: { + title: 'Bambu 클라우드 연결', + subtitle: '기기 간 슬라이서 프리셋 동기화', + email: '이메일', + password: '비밀번호', + region: '지역', + regionGlobal: '글로벌', + regionChina: '중국', + verificationCode: '인증 코드', + totpCode: '인증앱 코드', + checkEmail: '이메일({{email}})로 전송된 6자리 코드를 확인하세요', + enterTotpHint: '인증앱에서 6자리 코드를 입력하세요', + accessToken: '액세스 토큰', + accessTokenHint: 'Bambu Studio에서 Bambu Lab 액세스 토큰을 붙여넣으세요', + back: '뒤로', + loginButton: '로그인', + verifyButton: '인증', + setTokenButton: '토큰 설정', + useToken: '액세스 토큰 대신 사용', + useEmail: '이메일로 로그인', + toast: { + loggedIn: '성공적으로 로그인되었습니다', + codeSent: '이메일로 인증 코드가 전송되었습니다', + enterTotp: '인증앱에서 코드를 입력하세요', + tokenSet: '토큰이 성공적으로 설정되었습니다' + } + }, + presets: { + myPreset: '내 프리셋 (편집 가능)', + duplicate: '복제', + editable: '편집 가능', + failedToLoadDetails: '프리셋 세부 정보 불러오기 실패', + deleteConfirm: '이 프리셋을 삭제하시겠습니까?', + deleteWarning: 'Bambu 클라우드에서 \"{{name}}\"을(를) 영구적으로 삭제합니다. 이 작업은 취소할 수 없습니다.', + noDuplicatePermission: '프리셋 복제 권한이 없습니다', + noEditPermission: '프리셋 편집 권한이 없습니다', + noDeletePermission: '프리셋 삭제 권한이 없습니다', + types: { + filament: '필라멘트 프리셋', + printer: '프린터 프리셋', + process: '프로세스 프리셋' + }, + toast: { + deleted: '프리셋 삭제됨', + created: '프리셋 생성됨', + updated: '프리셋 업데이트됨', + duplicated: '프리셋 복제됨', + fieldAdded: '\"{{key}}\" 필드 추가됨', + exported: '프리셋 내보냄' + }, + baseLabel: '기본: {{name}}', + currentLabel: '현재: {{name}}', + newPreset: '새 프리셋', + editPreset: '프리셋 편집', + duplicatePreset: '프리셋 복제', + createNewPreset: '새 프리셋 생성', + customizeSettings: '새 프리셋의 설정 사용자 지정', + compareWithBase: '기본 프리셋과 비교', + compare: '비교', + basePreset: '기본 프리셋', + selectBasePreset: '기본 프리셋 선택...', + presetName: '프리셋 이름', + myCustomPreset: '내 사용자 지정 프리셋', + inheritsFrom: '상속 출처', + dropJsonToImport: 'JSON 파일을 드롭하여 가져오기', + tabs: { + common: '공통', + allFields: '모든 필드' + }, + availableFields: '사용 가능한 필드', + searchFieldsPlaceholder: '필드 검색...', + noMatchingFields: '일치하는 필드 없음', + allFieldsAdded: '모든 필드 추가됨', + addCustomField: '사용자 지정 필드 추가', + yourOverrides: '내 재정의', + noOverridesYet: '아직 재정의 없음', + clickFieldsToAdd: '왼쪽 필드를 클릭하여 추가', + saveAsTemplate: '템플릿으로 저장', + jsonTip: '팁: 이 모달 어디서나 .json 파일을 드래그 앤 드롭하여 설정을 가져올 수 있습니다' + }, + cloudView: { + searchPlaceholder: '프리셋 검색...', + templates: '템플릿', + refresh: '새로고침', + newPreset: '새 프리셋', + clearFilters: '필터 초기화', + compareMode: '비교 모드', + selectAnotherPreset: '다른 {{type}} 프리셋 선택', + clickTwoPresets: '같은 유형의 프리셋 두 개를 클릭하여 비교', + selectFirst: '1. 첫 번째 선택', + selectSecond: '2. 두 번째 선택', + compareNow: '지금 비교', + lastSynced: '마지막 동기화:', + showingCount: '{{total}}개 중 {{showing}}개 표시', + noPresetsFound: '프리셋을 찾을 수 없음', + columns: { + filament: '필라멘트', + process: '프로세스', + printer: '프린터' + }, + noFilamentPresets: '필라멘트 프리셋 없음', + noProcessPresets: '프로세스 프리셋 없음', + noPrinterPresets: '프린터 프리셋 없음', + filters: { + type: '유형', + owner: '소유자', + printer: '프린터', + nozzle: '노즐', + filament: '필라멘트', + layer: '레이어', + all: '전체', + myPresets: '내 프리셋', + builtIn: '기본 제공', + process: '프로세스' + }, + noTemplatesPermission: '템플릿 관리 권한이 없습니다', + noRefreshPermission: '프로필 새로고침 권한이 없습니다', + noCreatePermission: '프리셋 생성 권한이 없습니다' + }, + templates: { + title: '빠른 템플릿', + noTemplates: '아직 템플릿 없음', + createFirst: '프리셋 편집기에서 템플릿을 생성하세요', + typeFilter: '유형:', + deleteTitle: '템플릿 삭제', + deleteWarning: '이 작업은 취소할 수 없습니다', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + namePlaceholder: '템플릿 이름', + descriptionPlaceholder: '설명', + settingsJson: '설정 (JSON)', + fieldsCount: '{{count}}개 필드', + shownInModals: '모달에 표시됨', + hiddenInModals: '모달에서 숨겨짐', + apply: '적용', + toast: { + deleted: '템플릿 삭제됨', + updated: '템플릿 업데이트됨', + created: '템플릿 생성됨', + applied: '템플릿 적용됨' + } + } + }, + support: { + debugLoggingActive: '디버그 로깅이 활성화되어 있습니다', + manageLogs: '관리', + collectItem7: '프린터 연결 및 펌웨어 버전', + collectItem8: '통합 상태 (Spoolman, MQTT, HA)', + collectItem9: '네트워크 인터페이스 (서브넷만)', + collectItem10: 'Python 패키지 버전', + collectItem11: '데이터베이스 상태 확인', + collectItem12: 'Docker 환경 세부 정보', + bundleGenerating: '번들 생성 중...', + bundleStepConnection: '프린터 연결 확인 실행 중', + bundleStepVirtualPrinters: '가상 프린터 설정 확인 실행 중', + bundleStepLogScan: '알려진 문제가 있는지 최근 로그 스캔 중', + bundleStepBuild: '지원 번들 ZIP 빌드 중' + }, + fileManager: { + title: '파일 관리자', + subtitle: '인쇄 파일 정리 및 관리', + uploadFiles: '파일 업로드', + newFolder: '새 폴더', + folderName: '폴더 이름', + folderNamePlaceholder: '예: 기능성 부품', + renameFile: '파일 이름 바꾸기', + renameFolder: '폴더 이름 바꾸기', + invalidFilenameChar: '\"{{char}}\" 문자는 인쇄 파일 이름에 허용되지 않습니다. 프린터 SD 카드가 거부하는 문자: < > : \" / \\ | ? *', + moveFiles: '{{count}}개 파일 이동', + rootNoFolder: '루트 (폴더 없음)', + current: '현재', + linkFolder: '폴더 연결', + linkFolderDescription: '\"{{name}}\"을(를) 프로젝트 또는 아카이브에 연결하여 빠른 접근.', + project: '프로젝트', + archive: '아카이브', + noProjectsFound: '프로젝트를 찾을 수 없음', + noArchivesFound: '아카이브를 찾을 수 없음', + unlink: '연결 해제', + link: '연결', + dragDropFiles: '파일을 여기에 드래그 앤 드롭', + dropFilesHere: '파일을 여기에 드롭', + orClickToBrowse: '또는 클릭하여 탐색', + allFileTypesSupported: '모든 파일 형식 지원. ZIP 파일은 압축 해제됩니다.', + zipFilesDetected: 'ZIP 파일 감지됨', + zipExtractOptions: 'ZIP 파일이 압축 해제됩니다. 폴더 구조 처리 방법을 선택하세요:', + preserveZipStructure: 'ZIP에서 폴더 구조 유지', + createFolderFromZip: 'ZIP 파일 이름으로 폴더 생성', + stlThumbnailGeneration: 'STL 썸네일 생성', + zipMayContainStl: 'ZIP 파일에 STL 파일이 포함될 수 있습니다. 압축 해제 중 썸네일을 생성할 수 있습니다.', + thumbnailsCanBeGenerated: 'STL 파일의 썸네일을 생성할 수 있습니다. 대형 모델은 처리 시간이 더 걸릴 수 있습니다.', + generateThumbnailsForStl: 'STL 파일의 썸네일 생성', + threemfDetected: '3MF 파일 감지됨', + threemfExtractionInfo: '프린터 모델, 재료, 색상 및 인쇄 설정이 3MF 파일에서 자동으로 추출됩니다.', + willBeExtracted: '추출 예정', + filesExtracted: '{{count}}개 파일 추출됨', + uploadComplete: '업로드 완료: {{succeeded}}개 성공', + uploadFailed: '업로드 실패', + zipFilesFailed: '{{count}}개 파일 실패', + uploading: '업로드 중...', + changeLink: '링크 변경...', + linkTo: '연결 대상...', + linkToProjectOrArchive: '프로젝트 또는 아카이브에 연결', + addToQueue: '대기열에 추가', + schedulePrint: '예약', + generateThumbnail: '썸네일 생성', + generateThumbnails: '썸네일 생성', + generateThumbnailsForMissing: '썸네일이 없는 STL 파일의 썸네일 생성', + gridView: '격자 보기', + listView: '목록 보기', + lowDiskSpaceWarning: '디스크 공간 부족 경고', + lowDiskSpaceDetails: '전체 {{total}} 중 {{free}}만 남음. 임계값은 설정에서 {{threshold}}GB로 설정됩니다.', + files: '파일', + folders: '폴더', + size: '크기', + free: '여유', + allFiles: '모든 파일', + wrap: '줄 바꿈', + enableTextWrapping: '텍스트 줄 바꿈 활성화', + disableTextWrapping: '텍스트 줄 바꿈 비활성화', + collapse: '접기', + collapseFoldersByDefault: '기본적으로 폴더 접기', + expandFoldersByDefault: '기본적으로 폴더 펼치기', + dragToResizeTooltip: '드래그하여 크기 조정, 더블클릭하여 초기화', + searchFiles: '파일 검색...', + allTypes: '모든 유형', + prints: '인쇄물', + ascending: '오름차순', + descending: '내림차순', + resultsCount: '전체 {{total}}개 중 {{showing}}개', + selectAll: '모두 선택', + deselectAll: '모두 선택 해제', + selected: '{{count}}개 선택됨', + adding: '추가 중...', + loadingFiles: '파일 불러오는 중...', + folderIsEmpty: '폴더가 비어 있음', + noFilesYet: '파일 없음', + folderEmptyDescription: '파일을 업로드하거나 이 폴더로 이동하여 시작하세요.', + noFilesDescription: '파일을 업로드하여 인쇄 관련 파일을 정리하세요.', + noMatchingFiles: '일치하는 파일 없음', + noMatchingFilesDescription: '현재 검색 또는 필터 조건과 일치하는 파일이 없습니다.', + clearFilters: '필터 초기화', + printedCount: '{{count}}회 인쇄됨', + uploadedBy: '업로드한 사람', + deleteFolder: '폴더 삭제', + deleteFile: '파일 삭제', + deleteFilesCount: '{{count}}개 파일 삭제', + deleteFolderConfirm: '이 폴더를 삭제하시겠습니까? 안의 모든 파일도 삭제됩니다.', + deleteFileConfirm: '이 파일을 삭제하시겠습니까?', + deleteFilesConfirm: '선택한 {{count}}개 파일을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + deleting: '삭제 중...', + noPermissionRenameFolder: '폴더 이름 변경 권한이 없습니다', + noPermissionLinkFolder: '폴더 연결 권한이 없습니다', + noPermissionDeleteFolder: '폴더 삭제 권한이 없습니다', + noPermissionPrint: '인쇄 권한이 없습니다', + noPermissionAddToQueue: '대기열 추가 권한이 없습니다', + noPermissionSlice: '파일 슬라이싱 권한이 없습니다', + noPermissionDownload: '파일 다운로드 권한이 없습니다', + noPermissionRenameFile: '파일 이름 변경 권한이 없습니다', + noPermissionGenerateThumbnail: '썸네일 생성 권한이 없습니다', + noPermissionDeleteFile: '파일 삭제 권한이 없습니다', + noPermissionCreateFolder: '폴더 생성 권한이 없습니다', + noPermissionUpload: '파일 업로드 권한이 없습니다', + noPermissionMoveFiles: '파일 이동 권한이 없습니다', + noPermissionDeleteFiles: '파일 삭제 권한이 없습니다', + linkExternal: '외부 연결', + linkExternalFolder: '외부 폴더 연결', + linkExternalFolderDescription: '호스트 디렉토리(NAS, USB, 네트워크 공유)를 파일 관리자에 마운트합니다. 파일은 복사되지 않고 원래 경로에서 직접 접근합니다.', + externalFolderNamePlaceholder: '예: NAS 인쇄물', + externalPath: '호스트 경로', + externalPathHelp: 'Docker 호스트의 디렉토리 절대 경로. 컨테이너에 바인드 마운트되어야 합니다.', + readOnly: '읽기 전용', + readOnlyHelp: '업로드 및 삭제 방지', + showHiddenFiles: '숨김 파일 표시 (dotfiles)', + externalFolder: '외부 폴더', + scanFolder: '스캔', + toast: { + folderCreated: '폴더 생성됨', + folderDeleted: '폴더 삭제됨', + fileDeleted: '파일 삭제됨', + filesDeleted: '{{count}}개 파일 삭제됨', + filesMoved: '파일 이동됨', + folderLinked: '폴더 연결됨', + folderUnlinked: '폴더 연결 해제됨', + externalFolderLinked: '외부 폴더 연결 및 스캔됨', + folderScanned: '스캔 완료: {{added}}개 추가, {{removed}}개 제거', + addedToQueue: '{{count}}개 파일을 대기열에 추가함', + addedToQueuePartial: '{{added}}개 추가됨, {{failed}}개 실패', + failedToAddToQueue: '파일 추가 실패: {{error}}', + fileRenamed: '파일 이름 변경됨', + folderRenamed: '폴더 이름 변경됨', + thumbnailsGenerated: '{{count}}개 썸네일 생성됨', + thumbnailsGeneratedPartial: '{{succeeded}}개 썸네일 생성됨, {{failed}}개 실패', + noStlMissingThumbnails: '썸네일이 없는 STL 파일 없음', + failedToGenerateThumbnails: '썸네일 생성 실패: {{error}}', + thumbnailGenerated: '썸네일 생성됨', + failedToGenerateThumbnail: '썸네일 생성 실패: {{error}}' + } + }, + projects: { + title: '프로젝트', + subtitle: '3D 인쇄 프로젝트 정리 및 추적', + newProject: '새 프로젝트', + editProject: '프로젝트 편집', + deleteProject: '프로젝트 삭제', + projectName: '프로젝트 이름', + description: '설명', + noProjects: '프로젝트 없음', + noProjectsFiltered: '{{status}} 프로젝트 없음', + noProjectsFilteredHelp: '{{status}} 프로젝트가 없습니다. 상태가 변경되면 여기에 표시됩니다.', + createFirst: '첫 번째 프로젝트를 만들어 관련 인쇄물을 정리하고 진행 상황을 추적하며 빌드를 관리하세요.', + createFirstButton: '첫 번째 프로젝트 만들기', + create: '만들기', + files: '파일', + prints: '인쇄물', + plates: '플레이트', + parts: '부품', + lastModified: '마지막 수정', + deleteConfirm: '이 프로젝트를 삭제하시겠습니까? 아카이브 및 대기열 항목은 연결 해제되지만 삭제되지는 않습니다.', + addFiles: '파일 추가', + removeFile: '파일 제거', + viewDetails: '세부 정보 보기', + namePlaceholder: '예: Voron 2.4 빌드', + descriptionPlaceholder: '선택적 설명...', + urlLabel: 'URL', + urlPlaceholder: 'https://makerworld.com/...', + urlInvalid: 'URL은 http:// 또는 https://로 시작해야 합니다', + openExternalUrl: '프로젝트 URL 열기', + coverImageLabel: '커버 사진', + coverImageAlt: '프로젝트 커버 사진', + coverImageUpload: '업로드', + coverImageReplace: '교체', + coverImageRemove: '제거', + color: '색상', + targetPlates: '목표 플레이트', + targetPlatesPlaceholder: '예: 25', + targetPlatesHelp: '인쇄 작업 수', + targetParts: '목표 부품', + targetPartsPlaceholder: '예: 150', + targetPartsHelp: '필요한 총 개체 수', + tagsLabel: '태그 (쉼표로 구분)', + tagsPlaceholder: '예: voron, 기능성, 선물', + dueDate: '마감일', + priority: '우선순위', + priorityLow: '낮음', + priorityNormal: '보통', + priorityHigh: '높음', + priorityUrgent: '긴급', + statusActive: '활성', + statusCompleted: '완료됨', + statusArchived: '보관됨', + done: '완료', + completed: '완료됨', + failed: '실패', + inQueue: '대기 중', + noPrintsYet: '인쇄물 없음', + printJobs: '인쇄 작업 (플레이트)', + partsPrinted: '인쇄된 부품', + failedParts: '실패한 부품', + import: '가져오기', + export: '내보내기', + importProject: '프로젝트 가져오기', + exportAll: '모든 프로젝트 내보내기', + loading: '프로젝트 불러오는 중...', + noEditPermission: '프로젝트 편집 권한이 없습니다', + noDeletePermission: '프로젝트 삭제 권한이 없습니다', + noCreatePermission: '프로젝트 생성 권한이 없습니다', + noImportPermission: '프로젝트 가져오기 권한이 없습니다', + noExportPermission: '프로젝트 내보내기 권한이 없습니다', + toast: { + created: '프로젝트 생성됨', + updated: '프로젝트 업데이트됨', + deleted: '프로젝트 삭제됨', + imported: '프로젝트 가져옴', + multipleImported: '{{count}}개 프로젝트 가져옴', + importFailed: '가져오기 실패', + exported: '프로젝트 내보냄 (메타데이터만)' + } + }, + projectDetail: { + notFound: '프로젝트를 찾을 수 없음', + backToProjects: '프로젝트로 돌아가기', + export: '내보내기', + exportProject: '프로젝트 내보내기', + noExportPermission: '프로젝트 내보내기 권한이 없습니다', + noEditPermission: '프로젝트 편집 권한이 없습니다', + partOf: '속한 프로젝트:', + priorityLabel: '우선순위:', + noPrints: '이 프로젝트에 아직 인쇄물이 없습니다', + status: { + active: '활성', + completed: '완료됨', + archived: '보관됨' + }, + priority: { + low: '낮음', + normal: '보통', + high: '높음', + urgent: '긴급' + }, + dueDate: { + overdue: '기한 초과', + today: '오늘 마감', + daysLeft: '{{count}}일 남음' + }, + progress: { + platesProgress: '플레이트 진행률', + partsProgress: '부품 진행률', + printJobs: '인쇄 작업', + parts: '부품', + percentComplete: '{{percent}}% 완료', + remaining: '{{count}}개 남음' + }, + stats: { + printJobs: '인쇄 작업', + total: '합계', + failed: '{{count}}개 실패', + partsPrinted: '{{count}}개 부품 인쇄됨', + printTime: '인쇄 시간', + filamentUsed: '사용된 필라멘트' + }, + cost: { + title: '비용 추적', + filamentCost: '필라멘트 비용', + energy: '에너지', + totalCost: '총 비용', + total: '합계', + includesBom: 'BOM 포함', + budget: '예산', + remaining: '남은 예산' + }, + subProjects: { + title: '하위 프로젝트 ({{count}})' + }, + notes: { + title: '메모', + noEditPermission: '메모 편집 권한이 없습니다', + placeholder: '이 프로젝트에 대한 메모 추가...', + empty: '아직 메모가 없습니다. 편집을 클릭하여 메모를 추가하세요.' + }, + files: { + title: '파일', + linkFolders: '파일 관리자에서 폴더 연결', + forQuickAccess: '빠른 접근을 위해 이 프로젝트에 연결합니다.', + fileCount: '{{count}}개 파일', + empty: '연결된 폴더가 없습니다. 파일 관리자로 이동하여 폴더를 이 프로젝트에 연결하세요.', + noFiles: '이 폴더에 파일이 없습니다.', + print: '지금 인쇄', + addToQueue: '대기열에 추가' + }, + bom: { + title: '부품 목록', + acquired: '{{total}}개 중 {{completed}}개 확보', + showAll: '전체 표시', + hideDone: '완료된 것 숨기기', + addPart: '부품 추가', + noAddPermission: '부품 추가 권한이 없습니다', + partNamePlaceholder: '부품 이름 (예: M3x8 나사)', + partName: '부품 이름', + qty: '수량', + price: '가격 ({{currency}})', + sourcingUrlPlaceholder: '구매 URL (선택사항)', + remarksPlaceholder: '비고 (선택사항)', + deletePart: '부품 삭제', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까?', + noUpdatePermission: '부품 업데이트 권한이 없습니다', + noEditPermission: '부품 편집 권한이 없습니다', + noDeletePermission: '부품 삭제 권한이 없습니다', + totalCost: '총 비용:', + empty: '부품 목록에 부품이 없습니다. 하드웨어, 전자 부품 또는 기타 구성품을 추가하여 조달이 필요한 것을 추적하세요.' + }, + timeline: { + title: '활동 타임라인', + empty: '아직 활동이 없습니다.' + }, + template: { + saveAsTemplate: '템플릿으로 저장', + noCreatePermission: '템플릿 생성 권한이 없습니다' + }, + queue: { + title: '대기열', + viewAll: '전체 보기', + printing: '{{count}}개 인쇄 중', + queued: '{{count}}개 대기 중' + }, + prints: { + title: '인쇄물 ({{count}})' + }, + toast: { + projectUpdated: '프로젝트 업데이트됨', + partAdded: '부품 추가됨', + partRemoved: '부품 제거됨', + exportFailed: '내보내기 실패', + projectExported: '프로젝트 내보냄', + templateCreated: '템플릿 생성됨' + } + }, + system: { + title: '시스템 정보', + version: '버전', + uptime: '가동 시간', + cpuUsage: 'CPU 사용량', + memoryUsage: '메모리 사용량', + diskUsage: '디스크 사용량', + networkInfo: '네트워크 정보', + logs: '로그', + debugMode: '디버그 모드', + enableDebug: '디버그 로깅 활성화', + disableDebug: '디버그 로깅 비활성화', + downloadLogs: '로그 다운로드', + clearLogs: '로그 초기화', + dockerInfo: 'Docker 정보', + containerName: '컨테이너 이름', + imageName: '이미지 이름', + platform: '플랫폼', + architecture: '아키텍처' + }, + library: { + title: '필라멘트 라이브러리', + addFilament: '필라멘트 추가', + editFilament: '필라멘트 편집', + deleteFilament: '필라멘트 삭제', + vendor: '제조사', + material: '재료', + color: '색상', + kFactor: 'K 계수', + temperature: '온도', + noFilaments: '라이브러리에 필라멘트 없음', + deleteConfirm: '이 필라멘트를 삭제하시겠습니까?', + importFromPrinter: '프린터에서 가져오기', + exportToFile: '파일로 내보내기' + }, + slice: { + title: '모델 슬라이싱', + action: '슬라이싱', + slicing: '슬라이싱 중…', + printer: '프린터 프로필', + process: '프로세스 프로필', + filament: '필라멘트 프로필', + filamentSlot: '필라멘트 {{index}} ({{type}})', + selectPreset: '— 프리셋 선택 —', + loadingPresets: '프리셋 불러오는 중…', + analyzingPlateFilaments: '플레이트 필라멘트 분석 중…', + analyzingPlateFilamentsHint: '이 플레이트가 사용하는 AMS 슬롯을 확인하기 위해 미리보기 슬라이싱을 실행합니다. 캐시 후에는 재오픈이 즉각적입니다.', + previewToast: '{{name}} 분석 중 — {{elapsed}}', + previewWithProgress: '{{name}} 분석 중 — {{stage}} ({{percent}}%) — {{elapsed}}', + notUsedByPlate: '— 이 플레이트에서 사용되지 않음', + noPresetsForSlot: '사용 가능한 프리셋 없음', + presetsLoadFailed: '프리셋 불러오기 실패. 먼저 설정 → 프로필에서 가져오세요.', + refreshPresets: '새로 고침', + refreshPresetsTitle: '프리셋 새로 고침 — 최신 클라우드 및 번들 목록 가져오기 (Bambu Studio 또는 Bambu Handy에서 프리셋 삭제 후 사용)', + allPresetsRequired: '모든 프리셋을 선택해야 합니다', + enqueuing: '슬라이싱 작업 제출 중…', + queued: '대기 중…', + failed: '슬라이싱 실패. 슬라이서 사이드카 로그를 확인하세요.', + startedToast: '백그라운드에서 {{name}} 슬라이싱 중…', + queuedToast: '대기 중: {{name}} — {{elapsed}}', + runningToast: '{{name}} 슬라이싱 중 — {{elapsed}}', + runningWithProgress: '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', + completedToast: '{{name}} 슬라이싱 완료', + failedToast: '{{name}} 슬라이싱 실패: {{detail}}', + tier: { + local: '가져온 것', + cloud: '클라우드', + standard: '표준' + }, + cloud: { + notAuthenticated: '클라우드 프리셋을 보려면 Bambu 클라우드에 로그인하세요 (설정 → 프로필 → 클라우드).', + expired: 'Bambu 클라우드 세션이 만료되었습니다 — 다시 로그인하여 클라우드 프리셋을 새로고침하세요.', + unreachable: '현재 Bambu 클라우드에 연결할 수 없습니다. 로컬 및 표준 프리셋은 계속 작동합니다.' + }, + actionAll: '{{count}}개 플레이트 모두 슬라이싱', + actionAllTitle: '모든 플레이트를 단일 다중 플레이트 출력으로 슬라이싱합니다 (단일 아카이브). 필라멘트 선택은 프로젝트가 정의하는 모든 슬롯을 포함합니다.', + allPlatesToggle: '{{count}}개 플레이트 모두 슬라이싱', + otherPrinters: '다른 프린터', + bundle: '슬라이서 번들', + bundleNone: '— 없음 (개별로 프리셋 선택) —', + bundleAllRequired: '번들 프로세스 및 모든 필라멘트 슬롯을 선택해야 합니다', + runningWithProgressMultiPlate: '플레이트 {{plateIndex}}/{{plateCount}} • {{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', + failedTitle: '슬라이싱 실패', + bedType: { + label: '빌드 플레이트', + auto: '자동 (프로세스 프리셋 사용)', + coolPlate: '쿨 플레이트', + coolPlateSuperTack: '쿨 플레이트 슈퍼택', + engineering: '엔지니어링 플레이트', + highTemp: '고온 플레이트', + texturedPEI: '텍스처 PEI 플레이트', + smoothPEI: '매끄러운 PEI 플레이트' + } + }, + spoolman: { + title: 'Spoolman 통합', + enabled: 'Spoolman 활성화됨', + url: 'Spoolman URL', + connected: '연결됨', + disconnected: '연결되지 않음', + testConnection: '연결 테스트', + sync: '동기화', + syncing: '동기화 중...', + lastSync: '마지막 동기화', + linkToSpoolman: 'Spoolman에 연결', + openInSpoolman: 'Spoolman에서 열기', + unlinkSpool: '스풀 연결 해제', + unlinkConfirmTitle: '스풀 할당 해제?', + unlinkConfirmMessage: '이 슬롯에서 스풀을 제거합니다. 스풀 데이터 자체는 변경되지 않습니다.', + selectSpool: '스풀 선택', + noUnlinkedSpools: '할당되지 않은 스풀 없음', + linkSuccess: '스풀이 성공적으로 할당되었습니다', + linkFailed: '스풀 할당 실패', + unlinkSuccess: '스풀이 성공적으로 할당 해제되었습니다', + unlinkFailed: '스풀 할당 해제 실패', + linkedSpool: '할당된 스풀', + spoolId: '스풀 ID', + fillSourceLabel: '(Spoolman)', + weight: '무게', + remaining: '남은 양', + disableWeightSync: 'AMS 예상 무게 동기화 비활성화', + disableWeightSyncDesc: 'AMS 추정치에서 남은 용량을 업데이트하지 않습니다. AMS 백분율 기반 추정 대신 Spoolman의 사용량 추적을 선호하는 경우 사용하세요. 새 스풀은 여전히 AMS 추정치를 초기 무게로 사용합니다.', + reportPartialUsage: '실패한 인쇄물에 대한 부분 사용량 보고', + reportPartialUsageDesc: '인쇄가 실패하거나 취소될 때 레이어 진행률을 기반으로 해당 시점까지 사용된 예상 필라멘트를 보고합니다.' + }, + inventory: { + title: '스풀 재고', + spoolmanMixedContentTitle: 'HTTPS에서 Spoolman을 불러올 수 없음 — 브라우저가 혼합 콘텐츠를 차단함', + spoolmanMixedContentBody: 'Bambuddy가 HTTPS로 서비스되고 있지만 Spoolman URL은 여전히 HTTP입니다. 브라우저는 보안상 혼합 콘텐츠를 차단하므로 내장된 Spoolman UI가 렌더링되지 않습니다. 이 기능이 작동하려면 Spoolman이 HTTPS로 접근 가능해야 합니다.', + spoolmanMixedContentFixReverseProxy: 'Spoolman을 Bambuddy와 같은 리버스 프록시(Traefik / Nginx / Caddy) 뒤에 HTTPS로 배치한 다음 설정에서 Spoolman URL을 새 HTTPS 주소로 업데이트하세요.', + spoolmanMixedContentFixOpenNewTab: '임시 방편으로 HTTP로 새 브라우저 탭에서 Spoolman을 여세요 — 혼합 콘텐츠 규칙은 내장 프레임에만 적용되므로 독립 탭은 여전히 작동합니다.', + spoolmanOpenInNewTab: '새 탭에서 Spoolman 열기', + labels: { + title: '스풀 라벨 인쇄', + selectedCount: '{{count}}개 선택됨', + pickSpools: '라벨을 인쇄할 스풀 선택:', + searchPlaceholder: '이름, 브랜드 또는 #ID 검색', + filterByMaterial: '재료:', + allMaterials: '전체', + selectVisible: '보이는 모든 항목 선택 ({{count}})', + deselectVisible: '보이는 항목 선택 해제', + clearAll: '모두 초기화', + noSpoolsToShow: '표시할 스풀이 없습니다. 필터를 조정하고 다시 시도하세요.', + noMatches: '현재 검색 또는 필터와 일치하는 스풀이 없습니다.', + printOne: '이 스풀의 라벨 인쇄', + printLabels: '라벨 인쇄…', + bulkTitle: '현재 표시된 {{count}}개에서 라벨을 인쇄할 스풀 선택', + noSpoolsTitle: '라벨을 붙일 스풀 없음', + error: '라벨을 생성할 수 없습니다: {{msg}}', + templates: { + box40x30: { + label: '박스 라벨 (40 × 30 mm)', + hint: '페이지당 단일 라벨; 일반 DK/Brother 롤 크기, 필라멘트 가방 및 보관함 라벨에 적합.' + }, + box: { + label: '박스 라벨 (62 × 29 mm)', + hint: '페이지당 단일 라벨; Brother PT/QL 및 Dymo 소형 라벨에 맞는 크기.' + }, + averyL7160: { + label: 'Avery L7160 — A4 시트 (38.1 × 63.5 mm × 21)', + hint: 'EU 시트; A4 페이지당 21개 라벨.' + }, + avery5160: { + label: 'Avery 5160 — US Letter 시트 (25.4 × 66.7 mm × 30)', + hint: 'US 시트; Letter 페이지당 30개 라벨.' + }, + amsHolderSmall: { + label: 'AMS 홀더 — 소형 (74 × 33 mm)', + hint: '페이지당 단일 레이블; MakerWorld 모델 752566 (AMS 필라멘트 레이블 홀더)의 인쇄 가능 레이블과 일치합니다.' + }, + amsHolderLarge: { + label: 'AMS 홀더 — 대형 (75 × 55 mm)', + hint: '페이지당 단일 레이블; AMS 필라멘트 레이블 홀더의 카드스톡 삽입 변형에 맞습니다. 스와치, 브랜드, 재질, ID, QR 코드에 충분한 공간이 있습니다.' + } + }, + sortBy: { + label: '정렬:', + id: 'ID 순', + color: '색상 순' + } + }, + addSpool: '스풀 추가', + editSpool: '스풀 편집', + copySpool: '스풀 복사', + material: '재료', + selectMaterial: '재료 선택...', + subtype: '하위 유형', + brand: '브랜드', + searchBrand: '브랜드 검색...', + useCustomBrand: '\"{{brand}}\" 사용', + useCustomMaterial: '사용자 지정 재료 사용: {{material}}', + colorName: '색상 이름', + colorNamePlaceholder: '제이드 화이트, 파이어 레드...', + color: '색상', + hexColor: '16진수 색상', + pickColor: '사용자 지정 색상 선택', + labelWeight: '라벨 무게', + coreWeight: '빈 스풀 무게', + searchSpoolWeight: '스풀 무게 검색...', + weightUsed: '사용됨', + currentWeight: '남은 무게', + measuredWeight: '측정된 무게', + spoolName: '스풀', + costPerKg: 'kg당 비용', + storageLocation: '보관 위치', + storageLocationPlaceholder: '예: 선반 A, 서랍 1', + openInInventory: '재고에서 열기', + measuredWeightError: '측정된 무게는 {{min}}g과 {{max}}g 사이여야 합니다.', + slicerFilament: '슬라이서 필라멘트', + slicerFilamentName: '슬라이서 프리셋 이름', + slicerPreset: '슬라이서 프리셋', + searchPresets: '필라멘트 프리셋 검색...', + selectedPreset: '선택됨', + noPresetsFound: '프리셋을 찾을 수 없음', + tempOverrides: '온도 재정의', + note: '메모', + notePlaceholder: '이 스풀에 대한 추가 메모...', + category: '카테고리', + categoryPlaceholder: '예: 생산, 프로토타입, 고객 A', + categoryNone: '미분류', + lowStockThresholdOverride: '재고 부족 임계값 (이 스풀)', + lowStockThresholdOverrideHelp: '전역 임계값({{global}}%)을 사용하려면 비워두세요.', + clearRfid: 'RFID 태그 초기화', + rfidCleared: 'RFID 태그가 초기화되었습니다', + archive: '보관', + restore: '복원', + noSpools: '아직 스풀이 없습니다. 첫 번째 스풀을 추가하여 시작하세요.', + noAvailableSpools: '사용 가능한 스풀이 없습니다. 재고에 스풀을 추가하거나 먼저 다른 슬롯에서 해제하세요.', + kProfiles: 'K-프로필', + addKProfile: 'K-프로필 추가', + assignSpool: '스풀 할당', + unassignSpool: '할당 해제', + assignSuccess: '스풀 할당 및 AMS 슬롯 구성됨', + assignFailed: '스풀 할당 실패', + selectSpool: '이 슬롯에 할당할 스풀 선택', + assigned: '할당됨', + assigning: '할당 중...', + searchSpools: '스풀 검색...', + showAllSpools: '모든 스풀 표시', + spoolmanSpools: 'Spoolman 스풀', + allMaterials: '모든 재료', + filterByBrand: '브랜드로 필터...', + showArchived: '보관된 항목 표시', + quickAdd: '빠른 추가 (재고)', + quantity: '수량', + stock: '재고', + configured: '구성됨', + spoolsCreated: '{{count}}개 스풀 생성됨', + spoolsPartiallyCreated: '{{total}}개 중 {{created}}개 스풀 생성됨 (일부 실패)', + spoolCreated: '스풀 생성됨', + spoolUpdated: '스풀 업데이트됨', + spoolDeleted: '스풀 삭제됨', + deepLinkSpoolNotFound: '스풀을 찾을 수 없음', + deepLinkFetchFailed: '스풀을 불러올 수 없음 — 다시 시도하세요', + spoolArchived: '스풀 보관됨', + spoolRestored: '스풀 복원됨', + kProfileSaveFailed: 'K-프로필 설정을 저장할 수 없습니다', + syncWeightSpoolNotFound: '스풀을 찾을 수 없음 — 삭제되었을 수 있습니다', + syncWeightSpoolmanUnreachable: 'Spoolman에 연결할 수 없음 — 나중에 다시 시도하세요', + syncWeightFailed: '무게 동기화 실패', + spoolmanUnreachable: 'Spoolman에 연결할 수 없습니다 — 나중에 다시 시도하세요', + deleteSpoolNotFound: '스풀을 찾을 수 없음 — 이미 삭제되었을 수 있습니다', + deleteFailed: '스풀 삭제 실패', + archiveSpoolNotFound: '스풀을 찾을 수 없음 — 이미 삭제되었을 수 있습니다', + archiveFailed: '스풀 보관 실패', + restoreSpoolNotFound: '스풀을 찾을 수 없음 — 이미 삭제되었을 수 있습니다', + restoreFailed: '스풀 복원 실패', + saveFailed: '변경 사항 저장 실패', + tagClearFailed: '태그 초기화 실패', + deleteConfirm: '이 스풀을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + archiveConfirm: '이 스풀을 보관하시겠습니까?', + advancedSettings: '고급 설정', + filamentInfoTab: '필라멘트 정보', + paProfileTab: 'PA 프로필', + filamentInfo: '필라멘트', + additional: '추가', + loadingPresets: '클라우드 프리셋 불러오는 중...', + cloudConnected: '클라우드 연결됨', + cloudNotConnected: '클라우드 연결되지 않음 (기본값 사용)', + recentColors: '최근', + searchColors: '색상 검색...', + searchResults: '검색 결과', + allColors: '모든 색상', + commonColors: '일반 색상', + showLess: '간략히 보기', + showAll: '모두 보기', + noColorsFound: '검색과 일치하는 색상 없음', + noResults: '일치하는 항목 없음', + extraColorsLabel: '추가 색상', + extraColorsPlaceholder: 'EC984C,#6CD4BC,A66EB9,D87694', + extraColorsHint: '2~8개의 16진수 색상값을 쉼표로 구분하여 붙여넣으세요. 그라데이션으로 렌더링됩니다.', + extraColorsInvalid: '유효하지 않은 16진수 무시됨: {{tokens}}', + colorEffectLabel: '효과', + colorEffect: { + none: '없음', + sparkle: '스파클', + wood: '우드', + marble: '마블', + glow: '글로우', + matte: '매트', + silk: '실크', + galaxy: '갤럭시', + rainbow: '레인보우', + metal: '메탈', + translucent: '반투명', + gradient: '그라데이션', + dualColor: '듀얼 컬러', + triColor: '트리 컬러', + multicolor: '멀티컬러' + }, + selectMaterialFirst: '먼저 필라멘트 정보 탭에서 재료를 선택해 주세요.', + noPrintersConfigured: '구성된 프린터 없음. PA 프로필을 사용하려면 프린터를 추가하세요.', + matchingFilter: '일치', + anyBrand: '모든 브랜드', + anyVariant: '모든 변형', + autoSelect: '자동 선택', + matches: '일치', + match: '일치', + noMatches: '일치 없음', + connected: '연결됨', + offline: '오프라인', + printerOffline: '프린터가 오프라인입니다. 연결하여 보정 프로필을 확인하세요.', + noKProfilesMatch: '선택한 필라멘트와 일치하는 K-프로필이 없습니다.', + leftNozzle: '왼쪽 노즐', + rightNozzle: '오른쪽 노즐', + profilesSelected: '보정 프로필 선택됨', + totalInventory: '총 재고', + totalConsumed: '총 소비량', + byMaterial: '재료별', + inPrinter: '프린터 내', + lowStock: '재고 부족', + sinceTracking: '추적 시작 이후', + loadedInAms: 'AMS/외부에 장착됨', + remaining: '남은 양', + weightCheck: '무게 확인', + lastWeighed: '마지막 계량', + neverWeighed: '계량 기록 없음', + search: '스풀 검색...', + showing: '표시 중', + to: '~', + of: '/', + show: '표시', + spools: '스풀', + spool: '스풀', + page: '페이지', + noSpoolsMatch: '결과를 찾을 수 없음', + noSpoolsMatchDesc: '검색 또는 필터를 조정하여 원하는 항목을 찾아보세요.', + active: '활성', + archived: '보관됨', + all: '전체', + used: '사용됨', + new: '새것', + clearFilters: '필터 초기화', + table: '테이블', + cards: '카드', + net: '순', + groupSimilar: '그룹화', + groupedSpools: '동일한 스풀 {{count}}개', + groupedRows: '행', + columns: '열', + configureColumns: '열 구성', + configureColumnsDesc: '드래그하여 열 순서를 변경하거나 화살표를 사용하세요. 눈 아이콘으로 표시 여부를 전환합니다.', + visible: '표시됨', + reset: '초기화', + cancel: '취소', + applyChanges: '변경 사항 적용', + moveUp: '위로 이동', + moveDown: '아래로 이동', + hideColumn: '열 숨기기', + showColumn: '열 표시', + linkToSpool: '스풀에 연결', + tagLinked: '태그가 스풀에 연결됨', + tagLinkFailed: '태그 연결 실패', + tagAlreadyLinked: '태그가 이미 다른 스풀에 연결됨', + unknownTag: '알 수 없는 RFID 태그 감지됨', + usageHistory: '사용 기록', + noUsageHistory: '사용 기록 없음', + printName: '인쇄 이름', + weightConsumed: '소비 무게', + clearHistory: '초기화', + historyCleared: '사용 기록 초기화됨', + fillSourceLabel: '(재고)', + lowStockThresholdError: '임계값은 0.1에서 99.9 사이여야 합니다', + assignMismatchTitle: '재료 불일치', + assignMismatchMessage: '선택한 스풀 재료 \"{{spoolMaterial}}\"이(가) {{location}}의 트레이 재료 \"{{trayMaterial}}\"과(와) 일치하지 않습니다. 그래도 할당하시겠습니까?', + assignMismatchConfirm: '그래도 할당', + assignPartialMismatchMessage: '스풀 재료 \"{{spoolMaterial}}\"이(가) {{location}}의 \"{{trayMaterial}}\"과(와) 유사하지만 정확히 일치하지 않습니다. 계속하시겠습니까?', + assignProfileMismatchMessage: '스풀 프로필 \"{{spoolProfile}}\"이(가) {{location}}의 트레이 프로필 \"{{trayProfile}}\"과(와) 일치하지 않습니다. 계속하시겠습니까?', + assignReconfigureNote: 'AMS 슬롯이 스풀의 프로필을 사용하도록 재구성됩니다.', + spoolmanFilamentCatalog: 'Spoolman 필라멘트 카탈로그', + pickFromSpoolmanCatalog: 'Spoolman 카탈로그에서 선택…', + spoolmanFilamentSelected: 'Spoolman 카탈로그에서 필라멘트 선택됨', + spoolmanFilamentUnlinked: '필라멘트 카탈로그 연결 해제됨', + noSpoolmanFilaments: 'Spoolman 카탈로그에서 필라멘트를 찾을 수 없음', + spoolmanFilamentColorSwatch: '필라멘트 색상', + spoolWeightManagedBySpoolman: '빈 스풀 무게는 Spoolman에서 필라멘트 유형별로 관리됩니다', + spoolmanCatalogLoadFailed: 'Spoolman 필라멘트 카탈로그 불러오기 실패', + subtitle: '스풀 관리', + storageLocationNone: '위치 미설정', + resetUsage: '사용량을 0으로 초기화', + resetUsageTooltip: '이 스풀의 소비된 그램 카운터를 0으로 초기화합니다', + resetUsageConfirm: '이 스풀의 소비된 그램 카운터를 0으로 초기화하시겠습니까? 이후 인쇄는 처음부터 추적됩니다. 스풀 자체, 잔여 무게 계산 및 설정은 변경되지 않습니다.', + resetAllUsage: '모든 스풀 사용량 초기화', + resetAllUsageTooltip: '모든 스풀의 소비된 그램 카운터를 0으로 초기화합니다', + resetAllUsageConfirm: '{{count}}개 스풀(아카이브 포함)의 소비된 그램 카운터를 모두 0으로 초기화하시겠습니까? 이는 \"총 소비량\" 통계를 지워 이후 인쇄가 처음부터 추적되도록 합니다. 스풀과 잔여 무게는 변경되지 않습니다.', + usageReset: '스풀 사용량이 0으로 초기화되었습니다', + allUsageReset: '{{count}}개 스풀 초기화됨', + resetUsageFailed: '스풀 사용량 초기화 실패' + }, + timelapse: { + title: '타임랩스', + create: '타임랩스 만들기', + download: '다운로드', + delete: '삭제', + preview: '미리보기', + frameRate: '프레임 속도', + quality: '품질', + processing: '처리 중...', + noTimelapses: '사용 가능한 타임랩스 없음' + }, + ams: { + title: 'AMS', + slot: '슬롯', + empty: '비어 있음', + emptySlot: '빈 슬롯', + unknown: '알 수 없음', + humidity: '습도', + temperature: '온도', + filamentType: '필라멘트 유형', + filamentColor: '색상', + remaining: '남은 양', + history: 'AMS 기록', + noHistory: '기록 없음', + configureSlot: '슬롯 구성', + externalSpool: '외부 스풀', + profile: '프로필', + kFactor: 'K 계수', + fill: '채우기', + configure: '구성', + used: '사용됨', + remainingUnit: '남음', + slotEmpty: '비어 있음', + emptySlotReset: '필라멘트가 할당되지 않음' + }, + printModal: { + title: '인쇄 시작', + selectPrinter: '프린터 선택', + selectPlate: '플레이트 선택', + filamentMapping: '필라멘트 매핑', + totalCost: '총 비용:', + slotRemainingShort: ' - {{grams}}g 남음', + printSettings: '인쇄 설정', + bedLeveling: '베드 레벨링', + flowCalibration: '유량 보정', + vibrationCalibration: '진동 보정', + layerInspection: '첫 번째 레이어 검사', + timelapse: '타임랩스', + startPrint: '인쇄 시작', + addToQueue: '대기열에 추가', + cancel: '취소', + noPrintersAvailable: '사용 가능한 프린터 없음', + printerBusy: '프린터가 사용 중입니다', + printerOffline: '프린터가 오프라인입니다', + sameTypeDifferentColor: '같은 유형, 다른 색상', + filamentTypeNotLoaded: '필라멘트 유형이 장착되지 않음', + openCalendar: '달력 열기', + leftNozzle: 'L', + rightNozzle: 'R', + leftNozzleTooltip: '왼쪽 노즐', + rightNozzleTooltip: '오른쪽 노즐', + filamentOverride: '필라멘트 재정의', + filamentOverrideHint: '선택적으로 모델 기반 할당을 위해 필라멘트를 재정의합니다. 스케줄러는 원래 3MF 값 대신 선택한 필라멘트와 일치시킵니다.', + originalFilament: '원래', + overrideWith: '재정의', + resetToOriginal: '원래대로 초기화', + insufficientFilamentTitle: '필라멘트 부족', + insufficientFilamentMessage: '일부 할당된 스풀에 이 인쇄에 필요한 것보다 적은 필라멘트가 남아 있습니다:', + insufficientFilamentLine: '{{printer}} - {{slot}}: {{required}}g 필요, {{remaining}}g 남음', + printAnyway: '그래도 인쇄', + forceColorMatch: '색상 일치 강제', + staggerPrinterStarts: '프린터 시작 분산', + staggerGroupSize: '그룹 크기', + staggerInterval: '간격 (분)', + staggerPreview: '{{printers}}대 프린터 → {{size}}대씩 {{groups}}개 그룹, 매 {{interval}}분마다 시작', + staggerLastGroup: '마지막 그룹: {{count}}', + staggerTotal: '합계: {{minutes}}분', + staggerToPrinters: '{{count}}대 프린터에 분산', + gcodeInjection: '자동 인쇄 G-code 삽입' + }, + backup: { + includesEncryptionKey: '로컬 백업에는 MFA 암호화 키 파일(DATA_DIR/.mfa_encryption_key)이 포함되어 백업 ZIP이 자체 완결됩니다. ZIP 파일을 민감하게 취급하세요 — 파일을 가진 누구나 내부에 저장된 OIDC 클라이언트 비밀과 TOTP 비밀을 복호화할 수 있습니다.', + title: '백업 및 복원', + createBackup: '백업 만들기', + restoreBackup: '백업 복원', + restoreDescription: '백업 파일에서 모든 데이터 교체', + downloadBackup: '백업 다운로드', + uploadBackup: '백업 업로드', + lastBackup: '마지막 백업', + autoBackup: '자동 백업', + backupNow: '지금 백업', + restoreWarning: '경고: 백업을 복원하면 현재 모든 데이터를 덮어씁니다.', + includeArchives: '아카이브 포함', + includeSettings: '설정 포함', + includeProfiles: '프로필 포함', + backupSuccess: '백업이 성공적으로 생성되었습니다', + restoreSuccess: '백업이 성공적으로 복원되었습니다', + backupFailed: '백업 실패', + restoreFailed: '복원 실패', + restoreNote: '복원 중 가상 프린터가 중지됩니다', + githubBackup: 'Git 백업', + enabled: '활성화됨', + cloudLoginRequired: 'Bambu 클라우드 로그인 필요. GitHub 백업을 활성화하려면 프로필 → 클라우드 프로필에서 로그인하세요.', + cloudLoginRequiredShort: '클라우드 로그인 필요', + githubDescription: '백업 및 버전 기록을 위해 비공개 GitHub 저장소에 프로필을 자동으로 동기화합니다.', + repositoryUrl: '저장소 URL', + repoUrlPlaceholderGitHub: 'https://github.com/username/repo-name', + repoUrlPlaceholderGitea: 'https://gitea.example.com/username/repo-name', + repoUrlPlaceholderForgejo: 'https://forgejo.example.com/username/repo-name', + repoUrlPlaceholderGitLab: 'https://gitlab.com/username/repo-name', + allowInsecureHttp: '비보안 HTTP 허용', + allowInsecureHttpHint: 'TLS가 없는 개인 네트워크의 자체 호스팅 인스턴스에 활성화', + personalAccessToken: '개인 액세스 토큰', + tokenSaved: '(저장됨)', + enterNewToken: '업데이트하려면 새 토큰 입력', + tokenHint: '콘텐츠 읽기/쓰기 권한이 있는 세분화된 토큰', + branch: '브랜치', + provider: 'Git 제공자', + providerGitHub: 'GitHub', + providerGitLab: 'GitLab', + providerGitea: 'Gitea', + providerForgejo: 'Forgejo', + manualOnly: '수동만', + hourly: '매시간', + daily: '매일', + weekly: '매주', + includeInBackup: '백업에 포함', + kProfiles: 'K-프로필', + kProfilesDescription: '연결된 프린터의 압력 전진 보정', + noPrintersConnected: '연결된 프린터 없음', + printersConnected: '{{total}}개 중 {{connected}}개 연결됨', + cloudProfiles: '클라우드 프로필', + cloudProfilesDescription: 'Bambu 클라우드의 필라멘트, 프린터 및 프로세스 프리셋', + appSettings: '앱 설정', + appSettingsDescription: 'Bambuddy 구성 (전체 데이터베이스)', + spoolInventory: '스풀 재고', + spoolInventoryDescription: '필라멘트 스풀, 사용 기록 및 비용 추적', + printArchives: '인쇄 아카이브', + printArchivesDescription: '인쇄 기록 메타데이터 (gcode/3MF 파일 제외)', + lastBackupAt: '마지막 백업:', + noBackupsYet: '아직 백업 없음', + next: '다음:', + startingBackup: '백업 시작 중...', + test: '테스트', + enableBackup: '백업 활성화', + testConnection: '연결 테스트', + enterRepoUrl: '저장소 URL 입력', + enterRepoAndToken: '저장소 URL 및 액세스 토큰 입력', + repoRequired: '저장소 URL이 필요합니다', + tokenRequired: '액세스 토큰이 필요합니다', + githubBackupEnabled: 'GitHub 백업 활성화됨', + tokenUpdated: '토큰 업데이트됨', + settingsSaved: '설정 저장됨', + failedToSave: '저장 실패: {{message}}', + backupCompleteFiles: '백업 완료 - {{count}}개 파일 업데이트됨', + backupSkippedNoChanges: '변경 사항 없어 백업 건너뜀', + backupFailed2: '백업 실패: {{message}}', + clearedLogs: '{{count}}개 로그 초기화됨', + failedToClearLogs: '로그 초기화 실패: {{message}}', + history: '기록', + clear: '초기화', + date: '날짜', + status: '상태', + commit: '커밋', + localBackup: '로컬 백업', + localBackupDescription: '데이터베이스, 아카이브, 업로드 및 모든 파일을 포함한 Bambuddy 데이터의 전체 백업을 만듭니다.', + downloadBackupLabel: '백업 다운로드', + completeBackupZip: '전체 백업: 데이터베이스 + 모든 파일 (ZIP)', + download: '다운로드', + preparingBackup: '백업 준비 중...', + creatingArchive: '백업 아카이브 생성 중... 대용량 아카이브의 경우 시간이 걸릴 수 있습니다.', + downloadingFile: '백업 파일 다운로드 중...', + backupDownloaded: '백업이 성공적으로 다운로드되었습니다', + failedToCreateBackup: '백업 생성 실패: {{message}}', + restore: '복원', + restoreReplacesAll: '복원은 모든 데이터를 교체합니다.', + restoreReplacesAllDetail: '현재 데이터베이스와 파일이 완전히 교체됩니다. 복원 후 재시작이 필요합니다.', + restoreConfirmTitle: '백업 복원', + restoreConfirmMessage: '\"{{filename}}\"에서 복원하시겠습니까? 현재 데이터베이스와 모든 파일이 완전히 교체됩니다. 복원 후 애플리케이션을 재시작해야 합니다.', + restoreConfirmButton: '백업 복원', + uploadingFile: '백업 파일 업로드 중...', + backupRestoredRestart: '백업 복원됨. Bambuddy를 재시작하세요.', + failedToRestore: '백업 복원 실패. 파일 형식을 확인하세요.', + reloadNow: '지금 새로고침', + creatingBackup: '백업 만드는 중', + restoringBackup: '백업 복원 중', + preparing: '준비 중...', + processing: '처리 중...', + doNotClosePage: '이 페이지를 닫거나 다른 곳으로 이동하지 마세요. 대용량 백업의 경우 몇 분이 걸릴 수 있습니다.', + restoring: '복원 중...', + restoreComplete: '복원 완료', + restoreFailed2: '복원 실패', + importSettings: '백업 파일에서 설정 가져오기', + pleaseWaitRestoring: '데이터가 복원되는 동안 기다려 주세요', + selectBackupFile: '백업 파일 클릭하여 선택 (.json 또는 .zip)', + duplicateHandling: '중복 처리 방법:', + matchPrinters: '프린터', + matchPrintersBy: '일련번호로 일치', + matchSmartPlugs: '스마트 플러그', + matchSmartPlugsBy: 'IP 주소로 일치', + matchNotificationProviders: '알림 제공자', + matchNotificationProvidersBy: '이름으로 일치', + matchFilaments: '필라멘트', + matchFilamentsBy: '이름 + 유형 + 브랜드로 일치', + matchArchives: '아카이브', + matchArchivesBy: '콘텐츠 해시로 일치 (항상 건너뜀)', + matchPendingUploads: '대기 중인 업로드', + matchPendingUploadsBy: '파일 이름으로 일치', + matchSettingsTemplates: '설정 및 템플릿', + matchSettingsTemplatesBy: '항상 덮어씀', + replaceExisting: '기존 데이터 교체', + keepExisting: '기존 데이터 유지', + overwriteDescription: '백업 데이터로 이미 존재하는 항목 덮어쓰기', + keepDescription: '아직 존재하지 않는 항목만 복원', + overwriteCaution: '주의:', + overwriteWarning: '덮어쓰기는 현재 구성을 백업 데이터로 교체합니다. 보안상 프린터 액세스 코드는 절대 덮어쓰지 않습니다.', + cancel: '취소', + processingBackup: '백업 파일 처리 중...', + itemsRestored: '복원된 항목', + itemsSkipped: '건너뛴 항목', + restored: '복원됨', + skippedAlreadyExist: '건너뜀 (이미 존재)', + filesCategory: '파일 (3MF, 썸네일 등)', + andMore: '...및 {{count}}개 더', + newApiKeysGenerated: '새 API 키 생성됨', + keysShownOnce: '이 키는 한 번만 표시됩니다. 지금 복사하세요!', + copy: '복사', + noDataFound: '백업 파일에서 복원할 데이터를 찾을 수 없습니다.', + close: '닫기', + scheduledBackup: '예약 백업', + scheduledBackupDescription: '일정에 따라 백업 스냅샷을 자동으로 생성합니다. 출력 디렉토리를 NAS 또는 외부 저장소에 마운트할 수 있습니다.', + frequency: '주기', + backupTime: '시간', + retention: '보존', + retentionDescription: '유지할 백업 수', + outputPath: '출력 경로', + outputPathPlaceholder: '기본값: {{path}}', + outputPathDescription: '기본 위치를 사용하려면 비워두세요', + runNow: '지금 실행', + backupFiles: '백업 파일', + noScheduledBackups: '아직 백업 없음', + deleteBackup: '삭제', + deleteBackupConfirm: '이 백업 파일을 삭제하시겠습니까?', + backupRunning: '백업 진행 중...', + scheduledBackupComplete: '백업이 성공적으로 완료되었습니다', + scheduledBackupFailed: '백업 실패', + nextBackup: '다음 백업', + backupSize: '크기', + utc: 'UTC', + defaultPathLabel: '기본값:', + categories: { + settings: '설정', + notification_providers: '알림 제공자', + notification_templates: '알림 템플릿', + smart_plugs: '스마트 플러그', + printers: '프린터', + filaments: '필라멘트', + maintenance_types: '유지 관리 유형', + archives: '아카이브', + projects: '프로젝트', + pending_uploads: '대기 중인 업로드', + external_links: '외부 링크', + api_keys: 'API 키' + }, + repoIsPrivate: '저장소가 비공개입니다 — 안전하게 백업할 수 있습니다.', + repoIsPublicWarning: '저장소가 공개입니다. Bambuddy 백업에는 MQTT 자격증명, Home Assistant 토큰, Prometheus 토큰, Bambu Cloud 이메일, K-프로파일을 통한 프린터 액세스 코드가 포함됩니다. 공급자 설정에서 저장소를 비공개로 변경할 때까지 저장이 차단됩니다.', + repoVisibilityUnknown: '저장소 공개 여부를 확인할 수 없습니다. Bambuddy는 비공개로 확인된 저장소에만 백업하며, 저장이 차단됩니다.' + }, + tags: { + title: '태그', + addTag: '태그 추가', + editTag: '태그 편집', + deleteTag: '태그 삭제', + tagName: '태그 이름', + tagColor: '태그 색상', + noTags: '태그 없음', + deleteConfirm: '이 태그를 삭제하시겠습니까?', + manageTags: '태그 관리' + }, + uploadModal: { + title: '3MF 파일 업로드', + dragDrop: '.3mf 파일을 여기에 드래그 앤 드롭', + or: '또는', + browseFiles: '파일 탐색', + extractionInfo: '프린터 모델은 3MF 파일 메타데이터에서 자동으로 추출됩니다.', + uploaded: '업로드됨', + failed: '실패', + uploading: '업로드 중...', + upload: '업로드', + uploadFailed: '업로드 실패' + }, + editArchive: { + title: '아카이브 편집', + name: '이름', + namePlaceholder: '인쇄 이름', + printer: '프린터', + noPrinter: '프린터 없음', + project: '프로젝트', + noProject: '프로젝트 없음', + itemsPrinted: '인쇄된 항목', + itemsPrintedHelp: '이 인쇄 작업에서 생산된 항목 수', + notes: '메모', + notesPlaceholder: '이 인쇄에 대한 메모 추가...', + externalLink: '외부 링크', + externalLinkPlaceholder: 'https://printables.com/model/...', + externalLinkHelp: 'Printables, Thingiverse 또는 다른 출처 링크', + tags: '태그', + tagsPlaceholder: '태그 추가...', + addMoreTags: '더 많은 태그 추가...', + matchingTags: '\"{{query}}\"와 일치', + existingTags: '기존 태그', + clickToAdd: '(클릭하여 추가)', + status: '상태', + failureReason: '실패 원인', + selectReason: '원인 선택...', + photos: '인쇄 결과 사진', + photosHelp: '+를 클릭하여 인쇄 결과 사진 추가', + printResult: '인쇄 결과', + saving: '저장 중...', + failureReasons: { + adhesionFailure: '접착 실패', + spaghettiDetached: '스파게티 / 분리', + layerShift: '레이어 시프트', + cloggedNozzle: '노즐 막힘', + filamentRunout: '필라멘트 소진', + warping: '휨', + stringing: '스트링', + underExtrusion: '압출 부족', + powerFailure: '전원 실패', + userCancelled: '사용자 취소', + other: '기타' + }, + statuses: { + completed: '완료됨', + failed: '실패', + aborted: '취소됨', + printing: '인쇄 중' + } + }, + kProfiles: { + title: 'K-프로필', + noPrintersConfigured: '구성된 프린터 없음', + addPrinterInSettings: 'K-프로필을 관리하려면 설정에서 프린터를 추가하세요', + noActivePrinters: '활성 프린터 없음', + enablePrinterConnection: 'K-프로필을 보려면 프린터 연결을 활성화하세요', + loadingProfiles: 'K-프로필 불러오는 중...', + printerOffline: '프린터 오프라인', + printerOfflineDesc: '선택한 프린터가 연결되지 않았습니다. 켜서 K-프로필을 확인하세요.', + noMatchingProfiles: '일치하는 프로필 없음', + noMatchingProfilesDesc: '검색 기준과 일치하는 프로필이 없습니다', + noKProfiles: 'K-프로필 없음', + noKProfilesDesc: '{{diameter}}mm 노즐에 대한 압력 전진 프로필이 없습니다', + createFirstProfile: '첫 번째 프로필 만들기', + printer: '프린터', + nozzle: '노즐', + refresh: '새로고침', + addProfile: '프로필 추가', + export: '내보내기', + import: '가져오기', + select: '선택', + selectAll: '모두 선택', + delete: '삭제', + searchPlaceholder: '이름 또는 필라멘트로 검색...', + allExtruders: '모든 압출기', + leftOnly: '왼쪽만', + rightOnly: '오른쪽만', + allFlow: '모든 유량', + hfOnly: 'HF만', + sOnly: 'S만', + sortName: '정렬: 이름', + sortKValue: '정렬: K값', + sortFilament: '정렬: 필라멘트', + leftExtruder: '왼쪽 압출기', + rightExtruder: '오른쪽 압출기', + modal: { + addTitle: 'K-프로필 추가', + editTitle: 'K-프로필 편집', + profileName: '프로필 이름', + profileNamePlaceholder: '내 PLA 프로필', + kValue: 'K값', + kValuePlaceholder: '0.020', + kValueHelp: '일반 범위: PLA 0.01~0.06, PETG 0.02~0.10', + filament: '필라멘트', + selectFilament: '필라멘트 선택...', + noFilamentsHelp: '필라멘트를 찾을 수 없습니다. 먼저 Bambu Studio에서 K-프로필을 만드세요.', + flowType: '유량 유형', + highFlow: '고유량', + standard: '표준', + nozzleSize: '노즐 크기', + extruder: '압출기', + extruders: '압출기', + left: '왼쪽', + right: '오른쪽', + notes: '메모 (로컬 저장)', + notesPlaceholder: '이 프로필에 대한 메모 추가...', + notesHelp: '메모는 프린터가 아닌 Bambuddy에 저장됩니다', + syncing: '프린터와 동기화 중...', + savingExtruder: '압출기 {{current}}/{{total}}에 저장 중...', + pleaseWait: '기다려 주세요' + }, + deleteConfirm: { + title: '프로필 삭제', + cannotUndo: '이 작업은 취소할 수 없습니다', + message: '프린터에서 \"{{name}}\"을(를) 삭제하시겠습니까?' + }, + bulkDelete: { + title: '프로필 삭제', + cannotUndo: '이 작업은 취소할 수 없습니다', + message: '프린터에서 선택한 {{count}}개 프로필을 삭제하시겠습니까?' + }, + toast: { + profileSaved: 'K-프로필 저장됨', + profilesSaved: '{{count}}개 압출기에 K-프로필 저장됨', + selectAtLeastOneExtruder: '적어도 하나의 압출기를 선택해 주세요', + profileDeleted: 'K-프로필 삭제됨', + profilesDeleted: '{{count}}개 프로필 삭제됨', + exportedProfiles: '{{count}}개 프로필 내보냄', + importedProfiles: '{{total}}개 중 {{count}}개 프로필 가져옴', + noProfilesToExport: '내보낼 프로필 없음', + invalidFileFormat: '유효하지 않은 파일 형식', + failedToParseImport: '가져오기 파일 파싱 실패', + failedToSaveBatch: 'K-프로필 저장 실패', + noteSaved: '메모 저장됨', + failedToSaveNote: '메모 저장 실패' + }, + permission: { + noRead: '프로필 새로고침 권한이 없습니다', + noCreate: '프로필 추가 권한이 없습니다', + noUpdate: 'K-프로필 업데이트 권한이 없습니다', + noDelete: 'K-프로필 삭제 권한이 없습니다', + noExport: '프로필 내보내기 권한이 없습니다', + noImport: '프로필 가져오기 권한이 없습니다' + } + }, + virtualPrinter: { + title: '가상 프린터', + running: '실행 중', + stopped: '중지됨', + description: { + default: 'Bambu Studio 및 OrcaSlicer에 표시되는 가상 프린터를 활성화합니다. 이 프린터로 전송된 파일은 인쇄 없이 바로 아카이브됩니다.', + proxy: '실제 프린터로 슬라이서 트래픽을 릴레이하는 프록시를 활성화하여 모든 네트워크에서 원격 인쇄가 가능합니다.' + }, + enable: { + title: '가상 프린터 활성화', + visibleInSlicer: '슬라이서 검색에서 \"Bambuddy\"로 표시됨', + proxyingTo: '{{name}}으로 프록시 중', + notActive: '활성화되지 않음' + }, + model: { + title: '프린터 모델', + description: '에뮬레이션할 프린터 모델을 선택하세요.', + restartWarning: '모델 변경 시 가상 프린터가 재시작됩니다' + }, + accessCode: { + title: '액세스 코드', + isSet: '액세스 코드가 설정됨', + notSet: '액세스 코드가 설정되지 않음 - 활성화하려면 필요', + placeholder: '8자리 코드 입력', + placeholderChange: '변경하려면 새 코드 입력', + hint: '정확히 8자여야 합니다. 슬라이서가 인증하는 데 사용됩니다.', + charCount: '({{count}}/8)' + }, + targetPrinter: { + title: '대상 프린터', + configured: '프록시 대상 구성됨', + notConfigured: '대상 프린터가 선택되지 않음 - 프록시 모드에 필요', + placeholder: '프린터 선택...', + hint: '슬라이서 트래픽을 프록시할 프린터를 선택하세요. 프린터는 LAN 모드여야 합니다.', + noPrinters: '구성된 프린터 없음. 프록시 모드를 사용하려면 먼저 프린터를 추가하세요.' + }, + remoteInterface: { + title: '네트워크 인터페이스 재정의', + configured: '인터페이스 재정의 활성', + optional: '선택사항 - 자동 감지된 IP가 잘못된 경우 사용 (예: 여러 NIC, Docker, VPN)', + placeholder: '자동 감지 (기본값)...', + hint: 'SSDP를 통해 광고되고 TLS 인증서에 사용되는 IP 주소를 재정의합니다. Bambuddy에 여러 네트워크 인터페이스가 있을 때 유용합니다.' + }, + mode: { + title: '모드', + archive: '아카이브', + archiveDesc: '파일 즉시 아카이브', + review: '검토', + reviewDesc: '아카이브 전 검토', + queue: '대기열', + queueDesc: '아카이브 후 대기열 추가', + proxy: '프록시', + proxyDesc: '실제 프린터로 릴레이' + }, + autoDispatch: { + title: '자동 발송', + description: '대기열에 추가될 때 자동으로 인쇄를 시작합니다. 꺼져 있으면 수동 발송을 기다립니다.' + }, + queueForceColorMatch: { + title: '색상 일치 강제', + description: '정확한 필라멘트 유형과 색상이 장착되지 않은 프린터에는 발송을 거부합니다. 기본적으로 꺼져 있음 — 이 옵션 없이는 대기열이 모델 전용 매칭을 사용하여 잘못된 색상이 장착된 프린터를 선택할 수 있습니다.' + }, + tailscaleDisabled: { + title: 'Tailscale 통합', + description: '이 가상 프린터가 Tailscale을 통해 노출되도록 표시하려면 활성화하세요. 슬라이서에 붙여넣을 IP를 알 수 있도록 호스트의 Tailscale 주소를 표시합니다. CA 가져오기 단계는 변경되지 않음 — 이 토글은 인증서에 영향을 미치지 않습니다.' + }, + setupRequired: { + title: '설정 필요', + description: '가상 프린터 기능이 작동하려면 추가 시스템 구성이 필요합니다. 여기에는 포트 포워딩, 방화벽 규칙 및 플랫폼별 설정이 포함됩니다.', + readGuide: '활성화 전에 설정 가이드를 읽으세요' + }, + archiveNameSource: { + title: '아카이브 이름 출처', + description: '가상 프린터를 통해 파일이 도착할 때 새 아카이브의 이름 지정 방법을 선택합니다. \"메타데이터\"는 3MF의 슬라이서 내장 제목을 사용합니다(기본값). \"파일 이름\"은 Bambu Studio가 FTP를 통해 전송한 파일 이름을 사용합니다.', + metadata: '메타데이터', + filename: '파일 이름' + }, + howItWorks: { + title: '작동 방식', + step1: '같은 LAN에서 가상 프린터는 검색을 통해 슬라이서(Bambu Studio / OrcaSlicer)에 자동으로 나타납니다. 다른 네트워크에서는 IP 주소와 액세스 코드로 수동으로 추가하세요.', + step2: '아카이브, 검토, 대기열 모드에서 슬라이서의 \"전송\" 버튼을 사용하여 3MF 파일을 Bambuddy에 업로드하세요. 슬라이서는 \"인쇄 성공\"을 표시하지만 파일은 저장되고 인쇄되지 않습니다.', + step3: '프록시 모드에서 가상 프린터는 모든 트래픽을 실제 프린터로 릴레이합니다 — 직접 연결된 것처럼 즉시 인쇄가 시작됩니다.' + }, + status: { + title: '상태 세부 정보', + printerName: '프린터 이름', + model: '모델', + serialNumber: '일련 번호', + mode: '모드', + pendingFiles: '대기 중인 파일', + targetPrinter: '대상 프린터', + ftpPort: 'FTP 포트', + mqttPort: 'MQTT 포트', + ftpConnections: 'FTP 연결', + mqttConnections: 'MQTT 연결' + }, + toast: { + updated: '가상 프린터 설정 업데이트됨', + failedToUpdate: '설정 업데이트 실패', + copyFailed: '복사 실패 — 텍스트를 수동으로 선택하여 복사해 보세요', + accessCodeRequired: '먼저 액세스 코드를 설정해 주세요', + targetPrinterRequired: '먼저 대상 프린터를 선택해 주세요', + bindIpRequired: '먼저 바인드 IP를 설정해 주세요', + accessCodeEmpty: '액세스 코드는 비워둘 수 없습니다', + accessCodeLength: '액세스 코드는 정확히 8자여야 합니다', + created: '가상 프린터 생성됨', + failedToCreate: '가상 프린터 생성 실패', + deleted: '가상 프린터 삭제됨', + failedToDelete: '가상 프린터 삭제 실패' + }, + list: { + title: '가상 프린터', + add: '추가', + addFirst: '가상 프린터 추가', + empty: '구성된 가상 프린터 없음. 하나를 추가하여 시작하세요.' + }, + bindIp: { + title: '바인드 인터페이스', + placeholder: '인터페이스 선택...', + hint: '이 가상 프린터가 바인딩할 네트워크 인터페이스. 프린터당 고유해야 합니다.' + }, + proxy: { + accessCodeHint: '프록시 모드에서는 슬라이서에서 대상 프린터의 액세스 코드를 사용하세요. 연결은 실제 프린터로 투명하게 전달됩니다.' + }, + addDialog: { + title: '가상 프린터 추가', + name: '이름', + hint: '생성 후 액세스 코드, 대상 프린터 및 기타 설정을 구성할 수 있습니다.', + create: '생성' + }, + deleteConfirm: { + title: '가상 프린터 삭제', + message: '\"{{name}}\"을(를) 삭제하시겠습니까? 이 프린터의 모든 서비스가 중지됩니다.' + }, + caCert: { + title: '슬라이서 인증서', + description: '가상 프린터는 Bambuddy CA가 서명한 TLS 인증서를 사용합니다. 이 CA 인증서를 슬라이서의 신뢰 저장소에 한 번만 가져오면 연결을 수락합니다 — 명령줄에서 복사할 필요가 없습니다.', + copy: '복사', + copied: '복사됨', + download: '다운로드', + fingerprint: 'SHA-256' + } + }, + modelViewer: { + openInSlicer: '슬라이서에서 열기', + tabs: { + model: '3D 모델', + gcode: 'G-code 미리보기' + }, + notAvailable: '사용 불가', + notSliced: '슬라이싱되지 않음', + plates: '플레이트', + allPlates: '모든 플레이트', + plateNumber: '플레이트 {{number}}', + plateCount: '플레이트 {{count}}개', + plateCount_other: '플레이트 {{count}}개', + objectCount: '개체 {{count}}개', + objectCount_other: '개체 {{count}}개', + filamentCount: '필라멘트 {{count}}개', + filamentCount_other: '필라멘트 {{count}}개', + eta: '예상 {{minutes}}분', + noPreview: '이 파일에 대한 미리보기를 사용할 수 없습니다', + pagination: { + pageOf: '{{total}}페이지 중 {{current}}', + prev: '이전', + next: '다음' + }, + errors: { + failedToLoad: '파일 불러오기 실패', + noMeshes: '3MF 파일에서 메쉬를 찾을 수 없음', + unsupportedFormat: '지원되지 않는 파일 형식' + } + }, + maintenanceDescriptions: { + lubricateCarbonRods: '부드러운 움직임을 위해 카본 로드에 윤활유 도포', + lubricateRails: '부드러운 움직임을 위해 선형 레일에 윤활유 도포', + cleanNozzle: '막힘 방지를 위해 핫엔드와 노즐 청소', + checkBelts: '정확한 인쇄를 위해 벨트 장력 확인', + cleanBuildPlate: '접착력 향상을 위해 빌드 플레이트 청소', + checkExtruder: '마모 여부 확인을 위해 압출기 기어 점검', + checkCooling: '냉각 팬이 제대로 작동하는지 확인', + generalInspection: '전반적인 프린터 점검', + cleanCarbonRods: '마찰 감소를 위해 카본 로드 청소', + lubricateSteelRods: '부드러운 움직임을 위해 스틸 로드에 윤활유 도포', + cleanSteelRods: '마찰 감소를 위해 스틸 로드 청소', + cleanLinearRails: '먼지와 이물질 제거를 위해 선형 레일 닦기', + checkPtfeTube: '마모 또는 손상 여부 확인을 위해 PTFE 튜브 점검', + replaceHepaFilter: '공기 품질을 위해 HEPA 필터 교체', + replaceCarbonFilter: '활성탄 필터 교체', + lubricateLeftNozzleRail: '왼쪽 노즐 레일 윤활 (H2 시리즈)' + }, + smartPlugs: { + offline: '오프라인', + admin: '관리자', + openPlugAdminPage: '플러그 관리 페이지 열기', + deleteSmartPlug: '스마트 플러그 삭제', + turnOnSmartPlug: '스마트 플러그 켜기', + turnOffSmartPlug: '스마트 플러그 끄기', + turnOn: '켜기', + turnOff: '끄기', + addSmartPlug: { + scanningNetwork: '네트워크 스캔 중...', + chooseEntity: '엔티티 선택...', + connectionFailed: '연결 실패', + searchEntities: '엔티티 검색...', + searchPowerSensors: '전력 센서 검색...', + searchEnergySensors: '에너지 센서 검색...', + placeholders: { + plugName: '거실 플러그', + mqttStateOnValue: 'ON, true, 1', + mqttSameAsPower: '전력 토픽과 같거나 다름' + } + }, + linkedTo: '연결됨:', + monitorOnly: '모니터만', + alerts: '알림', + scheduleOn: '켜기 {{time}}', + scheduleOff: '끄기 {{time}}', + on: '켜짐', + off: '꺼짐', + power: '전력', + kwhToday: '오늘 kWh', + settings: '설정', + automationSettings: '자동화 설정', + showInSwitchbar: '스위치바에 표시', + quickAccessSidebar: '사이드바에서 빠른 접근', + enabled: '활성화됨', + enableAutomation: '이 플러그의 자동화 활성화', + autoOn: '자동 켜기', + autoOnDescription: '인쇄 시작 시 켜기', + autoOff: '자동 끄기', + autoOffDescription: '인쇄 완료 시 끄기 (1회)', + autoOffPersistent: '계속 활성화', + autoOffPersistentDescription: '1회성 대신 인쇄 사이에 활성화 유지', + turnOffDelayMode: '끄기 지연 모드', + time: '시간', + temp: '온도', + delayMinutes: '지연 (분)', + tempThreshold: '온도 임계값 (°C)', + tempThresholdDescription: '노즐이 이 온도 이하로 냉각될 때 끄기', + edit: '편집', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + turnOnConfirm: '\"{{name}}\"을(를) 켜시겠습니까?', + turnOffConfirm: '\"{{name}}\"을(를) 끄시겠습니까? 연결된 장치의 전원이 차단됩니다.', + failedToTurn: '\"{{name}}\" {{action}} 실패', + unknown: '알 수 없음', + addTitle: '스마트 플러그 추가', + editTitle: '스마트 플러그 편집', + stopScanning: '스캔 중지', + discoverTasmota: 'Tasmota 장치 검색', + foundDevices: '{{count}}개 장치 발견 - 클릭하여 선택:', + noDevicesFound: '네트워크에서 Tasmota 장치를 찾을 수 없음', + haNotConfigured: 'Home Assistant가 구성되지 않았습니다.', + haSettingsPath: '설정 → 네트워크 → Home Assistant', + selectEntity: '엔티티 선택 *', + ipAddress: 'IP 주소 *', + nameLabel: '이름 *', + username: '사용자 이름', + password: '비밀번호', + authHint: 'Tasmota 장치에 인증이 필요하지 않으면 비워두세요', + linkToPrinter: '프린터에 연결', + noPrinter: '프린터 없음 (수동 제어만)', + linkingDescription: '연결하면 인쇄 시작/완료 시 자동 켜기/끄기가 활성화됩니다', + powerAlerts: '전력 알림', + alertAbove: '초과 시 알림 (W)', + alertBelow: '미만 시 알림 (W)', + alertDescription: '전력 소비가 이 임계값을 초과할 때 알림 받기. 해당 방향을 비활성화하려면 비워두세요.', + dailySchedule: '일일 스케줄', + turnOnAt: '켜기 시각', + turnOffAt: '끄기 시각', + scheduleDescription: '매일 이 시간에 자동으로 켜기/끄기. 해당 동작을 건너뛰려면 비워두세요.', + showOnPrinterCard: '프린터 카드에 표시', + displayOnPrinterCard: '프린터 카드에 버튼 표시', + connectedResult: '연결됨!', + deviceLabel: '장치: {{name}} - ', + stateLabel: '상태: {{state}}', + test: '테스트', + delete: '삭제', + save: '저장', + add: '추가', + cancel: '취소', + failedToStartScan: '스캔 시작 실패', + nameRequired: '이름이 필요합니다', + entityRequired: 'Home Assistant 플러그에는 엔티티가 필요합니다', + mqttTopicRequired: '전력, 에너지 또는 상태 모니터링을 위한 MQTT 토픽이 하나 이상 구성되어야 합니다', + loadingEntities: '엔티티 불러오는 중...', + loading: '불러오는 중...', + failedToLoadEntities: '엔티티 불러오기 실패: {{error}}', + noEntitiesMatching: '\"{{search}}\"과 일치하는 엔티티를 찾을 수 없음', + noEntitiesAvailable: '사용 가능한 엔티티 없음', + searchingEntities: '모든 엔티티 검색 중 ({{count}}개 발견)', + showingEntities: 'switch, light, input_boolean 표시 중 ({{count}}개 사용 가능)', + energyMonitoringOptional: '에너지 모니터링 (선택사항)', + energyMonitoringHint: '전력/에너지 데이터를 제공하는 센서를 검색하여 선택하세요.', + powerSensorW: '전력 센서 (W)', + energyTodayKwh: '오늘 에너지 (kWh)', + totalEnergyKwh: '총 에너지 (kWh)', + noMatchingSensors: '일치하는 센서 없음', + none: '없음', + mqttNotConfigured: 'MQTT 브로커가 구성되지 않았습니다.', + mqttSettingsPath: '설정 → 네트워크 → MQTT 게시', + mqttNotConfiguredSuffix: '(게시를 활성화할 필요는 없고 브로커 세부 정보만 입력하면 됩니다).', + mqttMonitorOnlyDescription: 'MQTT 플러그는 MQTT 구독을 통해 전력/에너지 데이터를 받습니다. 켜기/끄기 제어는 불가능 — MQTT 브로커나 홈 자동화 시스템을 사용하세요.', + powerMonitoring: '전력 모니터링', + energyMonitoring: '에너지 모니터링', + stateMonitoring: '상태 모니터링', + optional: '선택사항', + topic: '토픽', + jsonPath: 'JSON 경로', + multiplier: '배수', + onValue: 'ON 값', + mqttPowerHint: 'JSON 경로는 JSON 페이로드에서 값을 추출합니다 (예: \"power_l1\"). 토픽이 원시 숫자 값을 게시하면 비워두세요.\nmW→W에는 배수 0.001, kW→W에는 1000을 사용하세요.', + mqttEnergyHint: 'JSON 경로는 JSON 페이로드에서 값을 추출합니다. 원시 값에는 비워두세요.\nWh→kWh에는 배수 0.001, MWh→kWh에는 1000을 사용하세요.', + mqttStateHint: 'JSON 경로는 JSON 페이로드에서 값을 추출합니다. 원시 값에는 비워두세요.\nON 값: \"ON\"을 의미하는 정확한 문자열. 자동 감지(ON, true, 1)를 위해 비워두세요.', + restControl: '제어', + restOnUrl: '켜기 URL', + restOffUrl: '끄기 URL', + restOnBody: 'ON 요청 본문', + restOffBody: 'OFF 요청 본문', + restMethod: 'HTTP 방법', + restHeaders: '사용자 지정 헤더 (JSON)', + restStatusUrl: '상태 URL', + restStatusPath: '상태 JSON 경로', + restStatusOnValue: 'ON 값', + restPowerUrl: '전력 URL', + restPowerPath: '전력 JSON 경로', + restPowerMultiplier: '전력 배수', + restEnergyUrl: '에너지 URL', + restEnergyPath: '에너지 JSON 경로', + restEnergyMultiplier: '에너지 배수', + restUrlRequired: 'REST 플러그에는 URL(ON 또는 OFF) 중 하나 이상이 필요합니다', + restHeadersHint: '예: {\"Authorization\": \"Bearer your-token\"}', + restBodyHint: '예: ON, {\"state\": \"on\"}', + restStatusHint: '현재 상태를 폴링할 URL', + restPathHint: '예: state 또는 data.power.status', + restPowerUrlHint: '전력 데이터의 별도 URL (비어 있으면 상태 URL 사용)', + restEnergyUrlHint: '에너지 데이터의 별도 URL (비어 있으면 상태 URL 사용)', + restEnergyHint: '각 값은 자체 URL을 사용하거나 상태 URL로 대체할 수 있습니다. 단위 변환에 배수를 사용하세요 (예: Wh→kWh에 0.001).', + testConnection: '연결 테스트', + connectionSuccess: '연결 성공', + noSwitchesInSwitchbar: '스위치바에 스위치 없음', + enableSwitchbarHint: '설정 > 스마트 플러그에서 \"스위치바에 표시\"를 활성화하세요', + autoOffAfterDrying: '건조 후 자동 끄기', + autoOffAfterDryingDescription: 'AMS 건조가 완료되면 끄기', + delayAfterDryingMinutes: '건조 후 지연 (분)' + }, + notifications: { + providerTypes: { + callmebot: 'CallMeBot/WhatsApp', + ntfy: 'ntfy', + pushover: 'Pushover', + telegram: 'Telegram', + email: '이메일', + discord: 'Discord', + webhook: 'Webhook', + homeassistant: 'Home Assistant' + }, + providerDescriptions: { + email: 'SMTP 이메일 알림', + telegram: 'Telegram 봇을 통한 알림', + discord: 'Webhook을 통해 Discord 채널로 전송', + ntfy: '무료, 자체 호스팅 가능한 푸시 알림', + pushover: '간단하고 신뢰할 수 있는 푸시 알림', + callmebot: 'CallMeBot을 통한 무료 WhatsApp 알림', + webhook: '모든 URL에 일반 HTTP POST', + homeassistant: 'Home Assistant 대시보드의 지속적인 알림' + }, + lastSuccess: '마지막: {{date}}', + error: '오류', + printer: '프린터:', + allPrinters: '모든 프린터', + sendTestNotification: '테스트 알림 전송', + eventSettings: '이벤트 설정', + enabled: '활성화됨', + sendFromProvider: '이 제공자에서 알림 전송', + printEvents: '인쇄 이벤트', + printerStatus: '프린터 상태', + amsAlarms: 'AMS 알람', + amsHtAlarms: 'AMS-HT 알람', + printQueue: '인쇄 대기열', + start: '시작', + plateCheck: '플레이트 확인', + complete: '완료', + failed: '실패', + stopped: '중지됨', + progress: '진행률', + offline: '오프라인', + lowFilament: '필라멘트 부족', + maintenance: '유지 관리', + amsHumidity: 'AMS 습도', + amsTemp: 'AMS 온도', + amsHtHumidity: 'AMS-HT 습도', + amsHtTemp: 'AMS-HT 온도', + bedCooled: '베드 냉각됨', + firstLayer: '첫 번째 레이어', + quiet: '방해 금지', + digest: '요약 {{time}}', + printStarted: '인쇄 시작됨', + plateNotEmpty: '플레이트 비어 있지 않음', + plateNotEmptyDescription: '인쇄 전 개체 감지됨', + printCompleted: '인쇄 완료됨', + bedCooledLabel: '베드 냉각됨', + bedCooledDescription: '인쇄 후 베드가 임계값 이하로 냉각됨', + firstLayerCompleteLabel: '첫 번째 레이어 완료', + firstLayerCompleteDescription: '첫 번째 레이어 완료 시 스냅샷과 함께 알림', + missingSpoolAssignmentLabel: '스풀 할당 누락', + missingSpoolAssignmentDescription: '인쇄 시작 시 필요한 트레이에 할당된 스풀이 없을 때 알림', + printFailed: '인쇄 실패', + printStopped: '인쇄 중지됨', + progressMilestones: '진행률 이정표', + progressMilestonesDescription: '25%, 50%, 75%에서 알림', + printerOffline: '프린터 오프라인', + printerError: '프린터 오류', + lowFilamentLabel: '필라멘트 부족', + maintenanceDue: '유지 관리 필요', + maintenanceDueDescription: '유지 관리가 필요할 때 알림', + amsHumidityHigh: 'AMS 습도 높음', + amsHumidityHighDescription: '일반 AMS 습도가 임계값 초과', + amsTemperatureHigh: 'AMS 온도 높음', + amsTemperatureHighDescription: '일반 AMS 온도가 임계값 초과', + amsHtHumidityHigh: 'AMS-HT 습도 높음', + amsHtHumidityHighDescription: 'AMS-HT 습도가 임계값 초과', + amsHtTemperatureHigh: 'AMS-HT 온도 높음', + amsHtTemperatureHighDescription: 'AMS-HT 온도가 임계값 초과', + inventoryAlerts: '재고 알림', + stockReorderAlert: '재주문 알림', + stockReorderAlertDescription: 'SKU가 재주문 시점에 도달함', + stockBreakAlert: '재고 소진 알림', + stockBreakAlertDescription: '보충 전에 재고가 소진될 것임', + jobAdded: '작업 추가됨', + jobAddedDescription: '대기열에 작업 추가됨', + jobAssigned: '작업 할당됨', + jobAssignedDescription: '모델 기반 작업이 프린터에 할당됨', + jobStarted: '작업 시작됨', + jobStartedDescription: '대기열 작업 인쇄 시작됨', + jobWaiting: '작업 대기 중', + jobWaitingDescription: '필라멘트 또는 프린터를 기다리는 작업', + jobSkipped: '작업 건너뜀', + jobSkippedDescription: '작업 건너뜀 (이전 실패)', + jobFailed: '작업 실패', + jobFailedDescription: '작업 시작 실패', + queueComplete: '대기열 완료', + queueCompleteDescription: '모든 대기열 작업 완료', + quietHours: '방해 금지 시간', + noNotificationsDuring: '이 시간 동안 알림 없음', + editProviderToChangeQuietHours: '방해 금지 시간을 변경하려면 제공자를 편집하세요', + dailyDigest: '일일 요약', + batchNotifications: '알림을 하나의 일일 요약으로 묶기', + sendAt: '{{time}}에 전송', + editProviderToChangeDigestTime: '요약 시간을 변경하려면 제공자를 편집하세요', + edit: '편집', + deleteProvider: '알림 제공자 삭제', + deleteConfirm: '\"{{name}}\"을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.', + delete: '삭제', + addTitle: '알림 제공자 추가', + editTitle: '알림 제공자 편집', + nameLabel: '이름 *', + namePlaceholder: '내 알림', + providerTypeLabel: '제공자 유형 *', + configuration: '구성', + testConfiguration: '구성 테스트', + printerFilter: '프린터 필터', + onlyFromPrinter: '이 프린터의 이벤트에 대한 알림만 전송', + quietHoursDnd: '방해 금지 시간', + quietStart: '시작', + quietEnd: '종료', + dailyDigestLabel: '일일 요약', + sendDigestAt: '요약 전송 시각', + digestCollected: '이벤트가 수집되어 이 시간에 하나의 요약으로 전송됩니다', + notificationEvents: '알림 이벤트', + progressPercent: '(25%, 50%, 75%)', + bedCooledAfterPrint: '(인쇄 완료 후)', + eventPriority: { + sectionTitle: 'ntfy 우선순위', + helpNtfy: '각 활성화된 이벤트에 대한 우선순위를 선택하세요. ntfy는 이를 사용하여 알림을 에스컬레이션합니다(소리, 가시성, 푸시 동작). 여기서 설정되지 않은 수준은 ntfy 서버 기본값을 사용합니다.', + min: '최소', + low: '낮음', + default: '기본값', + high: '높음', + urgent: '긴급' + }, + cancel: '취소', + save: '저장', + add: '추가', + nameRequired: '이름이 필요합니다', + fieldRequired: '{{field}}이(가) 필요합니다', + phoneNumber: '전화번호', + apiKey: 'API 키', + serverUrl: '서버 URL', + topic: '토픽', + authToken: '인증 토큰', + userKey: '사용자 키', + appToken: '앱 토큰', + priority: '우선순위', + botToken: '봇 토큰', + chatId: '채팅 ID', + smtpServer: 'SMTP 서버', + smtpPort: 'SMTP 포트', + security: '보안', + authentication: '인증', + username: '사용자 이름', + password: '비밀번호', + fromEmail: '발신 이메일', + toEmail: '수신 이메일', + webhookUrl: 'Webhook URL', + payloadFormat: '페이로드 형식', + authorization: '인증', + titleFieldName: '제목 필드 이름', + messageFieldName: '메시지 필드 이름', + editTemplate: '템플릿 편집: {{name}}', + titleLabel: '제목', + bodyLabel: '본문', + titlePlaceholder: '알림 제목...', + bodyPlaceholder: '알림 본문...', + availableVariables: '사용 가능한 변수', + clickToInsert: '클릭하여 본문의 커서 위치에 삽입', + livePreview: '실시간 미리보기', + hide: '숨기기', + show: '표시', + loadingPreview: '미리보기 불러오는 중...', + enterTemplateContent: '미리보기를 보려면 템플릿 내용을 입력하세요', + titlePreview: '제목:', + bodyPreview: '본문:', + resetToDefault: '기본값으로 초기화', + titleRequired: '제목이 필요합니다', + bodyRequired: '본문이 필요합니다', + notificationLog: '알림 로그', + showFailedOnly: '실패만', + last24Hours: '최근 24시간', + last7Days: '최근 7일', + last30Days: '최근 30일', + last90Days: '최근 90일', + justNow: '방금', + noFailedNotifications: '실패한 알림 없음', + noNotificationsLogged: '기록된 알림 없음', + unknownProvider: '알 수 없는 제공자', + logTitle: '제목', + logMessage: '메시지', + logError: '오류', + logProvider: '제공자: {{type}}', + logTime: '시간: {{time}}', + refresh: '새로고침', + clearOld: '오래된 것 삭제', + statsSummary: '최근 {{days}}일:', + statsNotifications: '알림', + statsSent: '{{count}}개 전송됨', + statsFailed: '{{count}}개 실패', + eventTypes: { + print_start: '인쇄 시작됨', + print_complete: '인쇄 완료', + print_failed: '인쇄 실패', + print_stopped: '인쇄 중지됨', + print_progress: '진행률', + printer_offline: '프린터 오프라인', + printer_error: '프린터 오류', + filament_low: '필라멘트 부족', + maintenance_due: '유지 관리 필요', + test: '테스트' + }, + userEmail: { + title: '알림', + emailNotifications: '이메일 알림', + emailNotificationsDesc: '내 인쇄 작업에 대한 이메일 알림을 받습니다. 이메일은 고급 인증에서 구성된 시스템 SMTP 설정을 사용하여 전송됩니다.', + sendingTo: '알림이 전송될 주소', + noEmailWarning: '계정에 이메일 주소가 없습니다. 관리자에게 연락하여 추가하세요.', + printJobNotifications: '인쇄 작업 알림', + printJobNotificationsDesc: '내가 제출한 인쇄 작업에 대해 이메일 알림을 트리거할 이벤트를 선택하세요.', + printJobStarts: '인쇄 작업 시작', + printJobStartsDesc: '인쇄 작업이 시작될 때 알림 받기.', + printJobFinishes: '인쇄 작업 완료', + printJobFinishesDesc: '인쇄 작업이 성공적으로 완료될 때 알림 받기.', + printErrors: '인쇄 오류', + printErrorsDesc: '인쇄 작업이 실패하거나 오류가 발생할 때 알림 받기.', + printJobStops: '인쇄 작업 중지', + printJobStopsDesc: '인쇄 작업이 취소되거나 중지될 때 알림 받기.', + saveSuccess: '알림 환경 설정이 저장되었습니다.', + saveError: '알림 환경 설정 저장 실패.' + } + }, + richTextEditor: { + bold: '굵게', + italic: '기울임', + underline: '밑줄', + bulletList: '글머리 기호 목록', + numberedList: '번호 목록', + alignLeft: '왼쪽 정렬', + alignCenter: '가운데 정렬', + alignRight: '오른쪽 정렬', + addLink: '링크 추가', + removeLink: '링크 제거' + }, + externalLinks: { + noLinksConfigured: '구성된 외부 링크 없음', + deleteLink: '링크 삭제', + removeCustomIcon: '사용자 지정 아이콘 제거', + openInNewTab: '새 탭에서 열기', + placeholders: { + linkName: '내 링크' + } + }, + keyboardShortcuts: { + title: '키보드 단축키', + navigation: '탐색', + archivesSection: '아카이브', + kProfilesSection: 'K-프로필', + generalSection: '일반', + shortcuts: { + goToPrinters: '프린터로 이동', + goToArchives: '아카이브로 이동', + goToQueue: '대기열로 이동', + goToStats: '통계로 이동', + goToProfiles: '클라우드 프로필로 이동', + goToSettings: '설정으로 이동', + focusSearch: '검색 포커스', + openUploadModal: '업로드 모달 열기', + clearSelection: '선택 초기화 / 입력 포커스 해제', + contextMenu: '카드 컨텍스트 메뉴', + refreshProfiles: '프로필 새로고침', + newProfile: '새 프로필', + exitSelectionMode: '선택 모드 종료', + showHelp: '이 도움말 표시' + }, + footer: 'Esc를 누르거나 외부를 클릭하여 닫기' + }, + notificationLog: { + title: '알림 로그', + events: { + printStarted: '인쇄 시작됨', + printComplete: '인쇄 완료', + printFailed: '인쇄 실패', + printStopped: '인쇄 중지됨', + progress: '진행률', + printerOffline: '프린터 오프라인', + printerError: '프린터 오류', + lowFilament: '필라멘트 부족', + maintenanceDue: '유지 관리 필요', + test: '테스트' + }, + timeAgo: { + justNow: '방금', + minutesAgo: '{{minutes}}분 전', + hoursAgo: '{{hours}}시간 전' + } + }, + restoreBackup: { + title: '백업 복원', + restoring: '복원 중...', + restoreComplete: '복원 완료', + restoreFailed: '복원 실패', + importSettings: '백업 파일에서 설정 가져오기', + pleaseWait: '데이터가 복원되는 동안 기다려 주세요', + clickToSelect: '백업 파일 클릭하여 선택 (.json 또는 .zip)', + howDuplicateHandling: '중복 처리 방법:', + categories: { + printers: '프린터', + smartPlugs: '스마트 플러그', + notificationProviders: '알림 제공자', + filaments: '필라멘트', + archives: '아카이브', + pendingUploads: '대기 중인 업로드', + settingsTemplates: '설정 및 템플릿' + }, + matchingInfo: { + printers: '일련번호로 일치', + smartPlugs: 'IP 주소로 일치', + notificationProviders: '이름으로 일치', + filaments: '이름 + 유형 + 브랜드로 일치', + archives: '콘텐츠 해시로 일치', + pendingUploads: '파일 이름으로 일치', + settingsTemplates: '항상 덮어씀' + }, + replaceExisting: '기존 데이터 교체', + keepExisting: '기존 데이터 유지', + replaceDescription: '백업 데이터로 이미 존재하는 항목 덮어쓰기', + keepDescription: '아직 존재하지 않는 항목만 복원', + caution: '주의:', + cautionText: '덮어쓰기는 현재 구성을 백업 데이터로 교체합니다. 보안상 프린터 액세스 코드는 절대 덮어쓰지 않습니다.', + itemsRestored: '복원된 항목', + itemsSkipped: '건너뛴 항목', + restored: '복원됨', + skipped: '건너뜀 (이미 존재)', + filesLabel: '파일 (3MF, 썸네일 등)', + newApiKeysGenerated: '새 API 키 생성됨', + newApiKeysWarning: '이 키는 한 번만 표시됩니다. 지금 복사하세요!', + processingBackup: '백업 파일 처리 중...', + noDataFound: '백업 파일에서 복원할 데이터를 찾을 수 없습니다.', + failedToRestore: '백업 복원 실패. 파일 형식을 확인하세요.' + }, + backupExport: { + title: '백업 내보내기', + selectData: '포함할 데이터 선택', + selectAll: '모두 선택', + selectNone: '선택 없음', + categoryDescriptions: { + settings: '언어, 테마, 업데이트 환경 설정', + notifications: 'ntfy, Pushover, Discord 등', + templates: '사용자 지정 메시지 템플릿', + smartPlugs: 'Tasmota 플러그 구성', + externalLinks: '외부 서비스에 대한 사이드바 링크', + printers: '프린터 정보 (액세스 코드 제외)', + plateDetection: '빈 플레이트 기준 이미지', + filaments: '필라멘트 유형 및 비용', + maintenance: '사용자 지정 유지 관리 일정', + archives: '모든 인쇄 데이터 + 파일 (3MF, 썸네일, 사진)', + projects: '프로젝트, BOM 항목 및 첨부 파일', + pendingUploads: '검토 대기 중인 가상 프린터 업로드', + apiKeys: 'Webhook API 키 (가져오기 시 새 키 생성)' + }, + requiresPrinters: '프린터 선택 필요', + zipFileWarning: 'ZIP 파일이 생성됩니다.', + zipFileDescription: '모든 3MF 파일, 썸네일, 타임랩스 및 사진을 포함합니다. 시간이 걸리고 파일이 커질 수 있습니다.', + includeAccessCodes: '액세스 코드 포함', + includeAccessCodesDescription: '다른 기기로 전송하는 경우', + includeAccessCodesWarning: '액세스 코드가 평문으로 포함됩니다. 이 백업 파일을 안전하게 보관하세요!', + categoriesSelected: '{{selectedCount}}개 카테고리 선택됨' + }, + pendingUploads: { + placeholders: { + notes: '이 인쇄에 대한 메모 추가...' + }, + discardUpload: '업로드 삭제', + archiveAllUploads: '모든 업로드 아카이브', + discardAllUploads: '모든 업로드 삭제', + archive: '아카이브', + timeAgo: { + justNow: '방금', + minutesAgo: '{{minutes}}분 전', + hoursAgo: '{{hours}}시간 전', + daysAgo: '{{days}}일 전' + } + }, + apiBrowser: { + placeholders: { + requestBody: 'JSON 요청 본문...', + searchEndpoints: '엔드포인트 검색...' + } + }, + configureAmsSlot: { + title: 'AMS 슬롯 구성', + slotConfigured: '슬롯 구성됨!', + configuringSlot: '슬롯 구성 중:', + slotLabel: '{{ams}} 슬롯 {{slot}}', + searchPresets: '프리셋 검색...', + colorPlaceholder: '색상 이름 또는 16진수 (예: brown, FF8800)', + clearCustomColor: '사용자 지정 색상 초기화', + noCloudPresets: '클라우드 프리셋 없음. Bambu 클라우드에 로그인하여 동기화하세요.', + noPresetsAvailable: '사용 가능한 프리셋 없음. Bambu 클라우드에 로그인하거나 로컬 프로필을 가져오세요.', + noMatchingPresets: '일치하는 프리셋을 찾을 수 없습니다.', + custom: '사용자 지정', + builtin: '기본 제공', + settingsSentToPrinter: '설정이 프린터로 전송됨', + filamentProfile: '필라멘트 프로필', + kProfileLabel: 'K 프로필 (압력 전진)', + filteringFor: '필터링 중: {{material}}', + noKProfile: 'K 프로필 없음 (기본값 0.020 사용)', + noMatchingKProfiles: '일치하는 K 프로필을 찾을 수 없습니다. 기본값 K=0.020이 사용됩니다.', + selectFilamentFirst: '먼저 필라멘트 프로필을 선택하세요', + kFromCalibration: 'K={{value}} (프린터 보정에서)', + customColorLabel: '사용자 지정 색상 (선택사항)', + presetColors: '{{name}} 색상:', + showLessColors: '색상 간략히 보기', + showMoreColors: '더 많은 색상 보기', + clear: '초기화', + hexLabel: '16진수: #{{hex}}', + resetting: '초기화 중...', + resetSlot: '슬롯 초기화', + cancel: '취소', + configuring: '구성 중...', + configureSlot: '슬롯 구성' + }, + githubBackup: { + title: 'Git 백업', + history: '기록', + downloadBackup: '백업 다운로드', + restoreBackup: '백업 복원', + noBackupsYet: '아직 백업 없음' + }, + emailSettings: { + placeholders: { + fromName: 'Bambuddy' + } + }, + tagManagement: { + searchTags: '태그 검색...', + renameTag: '태그 이름 바꾸기', + deleteTag: '태그 삭제' + }, + notificationTemplates: { + placeholders: { + title: '알림 제목...', + body: '알림 본문...' + } + }, + batchTag: { + placeholders: { + newTag: '새 태그 입력...' + } + }, + photoGallery: { + deletePhoto: '사진 삭제' + }, + filamentHoverCard: { + copySpoolUuid: '스풀 UUID 복사' + }, + kProfilesView: { + hasNote: '메모 있음', + copyProfile: '프로필 복사' + }, + layout: { + openMenu: '메뉴 열기', + noPermissionSystemInfo: '시스템 정보를 볼 권한이 없습니다' + }, + dashboard: { + dragToReorder: '드래그하여 순서 변경', + hideWidget: '위젯 숨기기' + }, + notificationProviderCard: { + deleteNotificationProvider: '알림 제공자 삭제' + }, + fileManagerModal: { + closeFileManager: '파일 관리자 닫기', + sortFiles: '파일 정렬', + goToParentFolder: '상위 폴더로 이동', + threeView: '3D 보기' + }, + embeddedCameraViewer: { + refreshStream: '스트림 새로고침', + close: '닫기', + zoomOut: '축소', + resetZoom: '배율 초기화', + zoomIn: '확대', + dragToResize: '드래그하여 크기 조정' + }, + timelapseViewer: { + skipBack5s: '5초 뒤로', + skipForward5s: '5초 앞으로' + }, + notificationProviders: { + descriptions: { + email: 'SMTP 이메일 알림', + telegram: 'Telegram 봇을 통한 알림', + discord: 'Webhook을 통해 Discord 채널로 전송', + ntfy: '무료, 자체 호스팅 가능한 푸시 알림', + pushover: '간단하고 신뢰할 수 있는 푸시 알림', + callmebot: 'CallMeBot을 통한 무료 WhatsApp 알림', + webhook: '모든 URL에 일반 HTTP POST' + } + }, + logViewer: { + searchPlaceholder: '메시지 또는 로거 이름 검색...', + noLogEntries: '로그 항목을 찾을 수 없음' + }, + switchbarPopover: { + noSwitchesInSwitchbar: '스위치바에 스위치 없음' + }, + projectPageModal: { + placeholders: { + title: '제목', + designer: '디자이너', + license: '라이선스', + description: '설명 입력...', + profileTitle: '프로필 제목', + profileDescription: '프로필 설명...' + } + }, + SpoolmanSettings: {}, + time: { + unknown: '-', + waiting: '대기 중', + justNow: '방금', + now: '지금', + minsAgo: '{{count}}분 전', + inMins: '{{count}}분 후', + hoursAgo: '{{count}}시간 전', + inHours: '{{count}}시간 후', + daysAgo: '{{count}}일 전', + inDays: '{{count}}일 후' + }, + spoolbuddy: { + nav: { + dashboard: '대시보드', + ams: 'AMS', + inventory: '재고', + writeTag: '태그 쓰기', + settings: '설정' + }, + status: { + nfcReady: 'NFC 준비됨', + nfcOff: 'NFC 꺼짐', + offline: '오프라인', + online: '온라인', + noPrinters: '프린터 없음', + deviceOffline: '장치 오프라인', + waitingConnection: '장치 연결 대기 중...', + systemReady: '시스템 준비됨', + status: '상태' + }, + dashboard: { + readyToScan: '스캔 준비됨', + idleMessage: '스풀을 저울에 올려 식별하세요', + nfcHint: 'NFC 태그가 자동으로 읽힙니다', + device: '장치', + syncWeight: '무게 동기화', + weightSynced: '동기화됨!', + unknownTag: '알 수 없는 태그', + newTag: '새 태그 감지됨', + onScale: '저울 위', + linkSpool: '스풀에 연결', + linkTagTitle: '태그를 스풀에 연결', + linkTag: '태그 연결', + selectSpool: '이 태그를 연결할 스풀 선택:', + noUntagged: '태그 없는 스풀을 찾을 수 없음', + tagDetected: '태그 감지됨', + noTag: '태그 없음', + tagId: '태그', + grossWeight: '총 무게', + spoolSize: '스풀 크기', + close: '닫기', + currentSpool: '현재 스풀', + plateReady: '플레이트 준비됨: {{name}}', + plateReadyLabel: '초기화할 플레이트', + plateClearAction: '초기화', + plateClearedToast: '플레이트가 초기화됨으로 표시됨', + plateClearFailed: '플레이트를 초기화됨으로 표시할 수 없음' + }, + modal: { + spoolDetected: '스풀 감지됨', + assignToAms: 'AMS에 할당', + syncWeight: '무게 동기화', + weightSynced: '동기화됨!', + syncing: '동기화 중...', + newTagDetected: '새 태그 감지됨', + addToInventory: '재고에 추가', + assignToAmsTitle: 'AMS에 할당', + selectSlot: '슬롯 선택', + assign: '할당', + assigning: '할당 중...', + assignSuccess: '할당됨!', + assignPendingInsert: '할당됨. 스풀을 삽입하면 슬롯이 구성됩니다.', + assignError: '스풀 할당 실패. 다시 시도하세요.', + noPrinterSelected: '프린터 선택...', + noAmsDetected: '이 프린터에서 AMS가 감지되지 않음', + slot: '슬롯' + }, + weight: { + noReading: '읽기 없음', + stable: '안정됨', + measuring: '측정 중...', + tare: '영점 조정', + calibrate: '보정' + }, + spool: { + remaining: '남은 양', + material: '재료', + brand: '브랜드', + color: '색상', + coreWeight: '코어', + labelWeight: '라벨', + scaleWeight: '저울', + netWeight: '순 무게', + lastUsed: '마지막 사용' + }, + ams: { + noData: 'AMS가 감지되지 않음', + connectAms: '필라멘트 슬롯을 보려면 AMS를 연결하세요', + noPrinter: '선택된 프린터 없음', + selectPrinter: '상단 표시줄에서 프린터를 선택하세요', + printerDisconnected: '프린터 연결 끊김', + humidity: '습도', + level: '레벨', + active: '활성', + slot: '슬롯', + empty: '비어 있음' + }, + inventory: { + search: '스풀 검색...', + empty: '재고에 스풀 없음', + noResults: '일치하는 스풀 없음', + spools: '스풀', + addSpool: '스풀 추가' + }, + settings: { + tabDevice: '장치', + tabDisplay: '화면', + tabScale: '저울', + tabUpdates: '업데이트', + nfcReader: 'NFC 리더', + type: '유형', + connection: '연결', + notConnected: 'N/A', + deviceInfo: '장치 정보', + hostname: '호스트', + uptime: '가동 시간', + systemConfig: '백엔드 및 인증', + backendUrl: 'Bambuddy 백엔드 URL', + apiToken: 'API 토큰', + apiTokenPlaceholder: 'API 토큰 입력', + saveConfig: '구성 저장', + systemQueued: '구성 대기 중.', + nfcDiagnostic: 'NFC 진단', + scaleDiagnostic: '저울 진단', + readTagDiagnostic: '태그 읽기 진단', + testNfc: '리더 테스트', + testScale: '정확도 테스트', + testReadTag: '태그 읽기', + systemFieldsRequired: '백엔드 URL이 필요합니다.', + brightness: '밝기', + saved: '저장됨', + noBacklight: 'DSI 백라이트가 감지되지 않음. 밝기 제어는 DSI 디스플레이가 필요합니다.', + screenBlank: '화면 꺼짐 대기 시간', + screenBlankDesc: '비활성 후 화면이 꺼집니다. 터치하여 깨우세요.', + displayNote: '밝기는 소프트웨어 필터로 적용됩니다.', + scaleCalibration: '저울 보정', + currentWeight: '현재 무게', + tareOffset: '영점', + calFactor: '계수', + knownWeight: '알려진 무게', + calStep1: '저울에서 모든 물건을 제거하고 영점 설정을 누르세요.', + calStep2: '저울에 알려진 무게를 올리세요.', + setZero: '영점 설정', + calibrateNow: '보정', + calibrated: '보정됨', + tareSet: '영점 조정 명령 전송됨. 장치 대기 중...', + tareComplete: '영점 조정 완료!', + tareTimedOut: '영점 조정 시간 초과 — SpoolBuddy 데몬이 실행 중인가요?', + tareFailed: '영점 조정 명령 전송 실패', + zeroSet: '영점이 설정됨. 저울에 알려진 무게를 올리세요.', + calibrationDone: '보정 완료!', + calibrationFailed: '보정 실패', + lastCalibrated: '마지막 보정', + stable: '안정됨', + settling: '안정화 중...', + firmware: '펌웨어', + scale: '저울', + noDevice: 'SpoolBuddy 장치를 찾을 수 없음', + daemonVersion: '데몬 버전', + currentVersion: '현재', + versionPending: '데몬 대기 중...', + checking: '확인 중...', + checkUpdates: '업데이트 확인', + updateAvailable: '업데이트 사용 가능', + updateInstructions: 'SSH를 통해 업데이트: SpoolBuddy 설치 스크립트를 실행하여 업그레이드하세요.', + upToDate: '최신 버전', + includeBeta: '베타 버전 포함' + }, + writeTag: { + tabExisting: '기존 스풀', + tabNew: '새 스풀', + tabReplace: '태그 교체', + searchPlaceholder: '재료, 색상, 브랜드로 검색...', + noUntaggedSpools: '태그 없는 스풀 없음', + noTaggedSpools: '태그 있는 스풀 없음', + selectSpool: '스풀을 선택한 후 빈 NTAG를 리더에 올려놓으세요', + placeTag: 'NTAG를 리더에 올려놓으세요', + tagReady: '태그 감지됨 — 쓰기 준비됨', + writeTag: '태그 쓰기', + replaceTag: '태그 교체', + writing: '태그 쓰는 중...', + waiting: 'SpoolBuddy 대기 중...', + writeSuccess: '태그 성공적으로 쓰여짐!', + writeFailed: '쓰기 실패', + queueFailed: '쓰기 명령 대기 실패', + tryAgain: '다시 시도', + cancel: '취소', + replaceWarning: '이전 태그가 연결 해제됩니다. 새 태그가 교체합니다.', + deviceOffline: 'SpoolBuddy가 오프라인입니다', + material: '재료', + colorName: '색상 이름', + color: '색상', + brand: '브랜드', + weight: '무게 (g)', + createSpool: '스풀 생성', + creating: '생성 중...', + spoolCreated: '스풀 생성됨! 쓰기 준비됨.', + createFailed: '스풀 생성 실패', + incompleteDataWarning: '불완전한 Spoolman 데이터로 태그 쓰여짐' + }, + quickMenu: { + printerPower: '프린터 전원', + systemControls: '시스템', + restartDaemon: '데몬 재시작', + restartBrowser: '브라우저 재시작', + reboot: '재부팅', + shutdown: '종료', + swipeToClose: '아래로 스와이프하여 닫기', + confirmTitle: '확인', + confirmShutdown: 'SpoolBuddy를 종료하시겠습니까? 다시 켜려면 물리적 접근이 필요합니다.', + confirmReboot: 'SpoolBuddy를 재부팅하시겠습니까?', + confirmRestartDaemon: 'SpoolBuddy 데몬을 재시작하시겠습니까? NFC와 저울이 일시적으로 사용 불가능합니다.', + confirmRestartBrowser: '키오스크 브라우저를 재시작하시겠습니까? 화면이 잠시 꺼집니다.', + confirm: '확인', + confirmPlugOn: '{{name}}을(를) 켜시겠습니까?', + confirmPlugOff: '{{name}}을(를) 끄시겠습니까?', + turnOn: '켜기', + turnOff: '끄기' + } + }, + bugReport: { + title: '버그 신고', + description: '설명', + descriptionPlaceholder: '무엇이 잘못되었나요? 문제를 설명해 주세요...', + email: '이메일 (선택사항)', + emailPlaceholder: 'your@email.com', + emailPrivacy: '제공하면 이메일이 GitHub 이슈의 접힌 섹션에 포함되어 관리자가 후속 조치를 취할 수 있습니다.', + screenshot: '스크린샷', + uploadOrPaste: '이미지 업로드, 붙여넣기 또는 드래그', + dataCollectedSummary: '보고서에 포함되는 데이터는?', + dataIncluded: '포함됨:', + dataIncludedList: '앱 버전, OS, 아키텍처, Python 버전, 데이터베이스 통계(개수만), 프린터 모델, 노즐 개수, 펌웨어 버전, 연결 상태, 통합 상태(Spoolman, MQTT, HA), 비민감 설정, 네트워크 인터페이스 수, Docker 세부 정보, 의존성 버전.', + dataNeverIncluded: '절대 포함되지 않음:', + dataNeverIncludedList: '프린터 이름, 일련 번호, 액세스 코드, 비밀번호, IP 주소, 이메일 주소, API 키, 토큰, Webhook URL, 호스트 이름 또는 사용자 이름.', + submit: '제출', + startLogging: '디버그 로깅 시작', + stepEnableLogging: '디버그 로깅 활성화됨', + stepReproduce: '이제 문제를 재현하세요', + stepStopLogging: '중지 후 보고서 제출', + stopAndSubmit: '중지 후 제출', + maxDuration: '{{minutes}}분 후 자동 중지', + stoppingLogs: '로그 수집 및 제출 중...', + submitting: '버그 보고서 제출 중...', + submitSuccess: '버그 보고서가 성공적으로 제출되었습니다!', + submitFailed: '버그 보고서 제출 실패', + thankYou: '감사합니다!', + submitted: '버그 보고서가 제출되었습니다.', + viewIssue: '이슈 보기', + unexpectedError: '예상치 못한 오류가 발생했습니다', + submittingStepConnection: '프린터 연결 확인 실행 중', + submittingStepVirtualPrinters: '가상 프린터 설정 확인 실행 중', + submittingStepLogScan: '알려진 문제가 있는지 최근 로그 스캔 중', + submittingStepSubmit: 'GitHub에 보고서 제출 중', + diagnosticChecking: '프린터 연결 확인 중...', + diagnosticHealthy: '연결 확인 통과 — 프린터에서 문제가 발견되지 않았습니다.', + diagnosticSummary: '{{total}}개 프린터 중 {{problems}}개에서 연결 문제가 있습니다', + diagnosticIntro: '하나 이상의 프린터에 연결 문제가 있어 현재 문제의 원인일 수 있습니다. 아래에서 프린터를 펼쳐 수정 방법을 확인하세요 — 해결하면 버그 보고서 없이 문제가 해결될 수 있습니다. 아래에서 보고서를 제출할 수도 있습니다.', + logHealthSummary: '로그에서 알려진 문제가 발견되었습니다', + logHealthIntro: '최근 로그가 알려진 문제와 일치합니다. 아래 수정 방법을 확인하세요 — 해결하면 버그 보고서 없이 문제가 해결될 수 있습니다. 아래에서 보고서를 제출할 수도 있습니다.' + }, + failureDetection: { + title: 'AI 실패 감지', + description: '자체 호스팅 Obico ML API로 인쇄를 모니터링하고 감지된 실패에 자동으로 조치합니다.', + mlUrl: 'Obico ML API URL', + mlUrlHint: '자체 호스팅 Obico ml_api 컨테이너의 기본 URL (예: http://192.168.1.10:3333).', + test: '테스트', + testSuccess: 'ML API에 도달 가능하며 정상입니다.', + testFailed: 'ML API에 도달할 수 없습니다.', + sensitivity: '민감도', + sensitivityLow: '낮음 (오탐 적음)', + sensitivityMedium: '중간 (균형)', + sensitivityHigh: '높음 (조기 감지, 오탐 많음)', + sensitivityHint: '경고 및 실패를 트리거하는 신뢰도 임계값을 조정합니다.', + action: '감지된 실패에 대한 조치', + actionNotify: '알림만', + actionPause: '인쇄 일시 중지', + actionPauseOff: '일시 중지 후 전원 끄기', + pollInterval: '폴링 간격 (초)', + pollIntervalHint: '인쇄 중 각 프린터를 확인하는 빈도. 최소 5초, 최대 120초.', + externalUrlMissing: '외부 URL이 설정되지 않았습니다.', + externalUrlHint: 'ML API가 URL을 통해 카메라 스냅샷을 가져옵니다. ML API 컨테이너가 Bambuddy에 도달할 수 있도록 일반 설정에서 외부 URL을 설정하세요.', + perPrinterTitle: '모니터링되는 프린터', + perPrinterHint: '감지 서비스가 감시할 프린터를 선택하세요.', + monitorAll: '연결된 모든 프린터 모니터링', + statusTitle: '상태', + serviceRunning: '서비스 실행 중', + thresholds: '낮음 / 높음 임계값', + activePrinters: '활성 인쇄물', + noActivePrints: '현재 실행 중인 인쇄물 없음.', + historyTitle: '최근 감지', + noHistory: '아직 감지 없음.' + }, + makerworld: { + title: 'MakerWorld', + description: 'MakerWorld 모델 URL을 붙여넣어 Bambu Handy 앱을 떠나지 않고 Bambuddy에서 직접 가져오고 인쇄하세요.', + pasteUrlHeader: 'MakerWorld에서 가져오기', + pasteUrlPlaceholder: 'https://makerworld.com/en/models/… 또는 MakerWorld 링크 붙여넣기', + resolveButton: '확인', + signInRequiredTitle: '다운로드하려면 Bambu 클라우드 로그인 필요', + signInRequiredBody: '익명으로 모델 세부 정보를 탐색할 수 있지만 MakerWorld는 3MF 파일을 다운로드하려면 Bambu 클라우드 계정이 필요합니다.', + openCloudSettings: '클라우드 설정 열기', + untitledModel: '제목 없는 모델', + byCreator: '{{name}} 제작', + downloadsCount: '{{count}}회 다운로드', + licensePrefix: '라이선스', + alreadyImported: '이미 라이브러리에 있음', + openOnMakerworld: 'MakerWorld에서 열기', + alreadyInLibrary: '이 모델이 이미 라이브러리에 있습니다 — 파일 관리자 → MakerWorld에서 찾으세요', + importSuccess: '{{filename}} 가져옴 — 파일 관리자 → MakerWorld에 저장됨', + platesHeader: '플레이트 ({{count}})', + plateDefaultName: '플레이트 {{n}}', + materialCount: '{{count}}개 필라멘트', + amsRequired: 'AMS 필요', + slicedFor: '{{printer}}용으로 슬라이싱됨', + alsoCompatible: '호환 가능으로도 표시됨: {{printers}}', + importToLibrary: '저장', + sliceIn: '{{slicer}}에서 저장 및 슬라이싱', + disclaimer: 'MakerWorld 통합은 커뮤니티가 문서화한 API 엔드포인트를 사용합니다. Bambuddy는 MakerWorld 또는 Bambu Lab과 제휴하거나 이들의 승인을 받지 않았습니다.', + lastImportSuccess: '라이브러리에 가져옴', + lastImportAlreadyInLibrary: '이미 라이브러리에 있음', + viewInLibrary: '파일 관리자에서 보기', + openInBambuStudio: 'Bambu Studio에서 열기', + openInOrcaSlicer: 'OrcaSlicer에서 열기', + importTo: '파일 관리자로 가져오기', + recentImportsHeader: '최근 가져오기', + phaseResolving: '확인 중', + phaseDownloading: '다운로드 중', + folderAuto: 'MakerWorld (기본값)', + importAll: '모두 가져오기', + importAllProgress: '{{total}}개 중 {{current}}개 가져오는 중', + openGallery: '이미지 갤러리 열기', + galleryPrev: '이전 이미지', + galleryNext: '다음 이미지', + deleteImport: '라이브러리에서 제거', + importDeleting: '제거 중…', + importDeleted: '라이브러리에서 제거됨', + confirmDelete: '라이브러리에서 {{filename}}을(를) 제거하시겠습니까? 로컬 파일이 삭제되지만 MakerWorld에서 다시 가져올 수 있습니다.', + errors: { + resolveFailed: 'MakerWorld URL을 확인할 수 없습니다.', + downloadFailed: '다운로드 실패. 다시 시도하세요.', + deleteFailed: '라이브러리에서 파일을 제거할 수 없습니다.' + } + }, + gcodeViewer: { + back: '뒤로', + backToArchives: '인쇄 아카이브로 돌아가기', + backToFiles: '파일 관리자로 돌아가기' + }, + libraryTrash: { + title: '휴지통', + headerButton: '휴지통', + headerTooltip: '휴지통으로 이동된 파일 보기', + backToFiles: '파일 관리자로 돌아가기', + subtitleAdmin: '삭제된 파일은 {{days}}일 동안 여기에 보관된 후 자동 삭제됩니다. 이 보기는 모든 사용자의 휴지통 파일을 표시합니다.', + subtitleUser: '삭제된 파일은 {{days}}일 동안 여기에 보관된 후 자동 삭제됩니다.', + loading: '휴지통 불러오는 중…', + loadError: '휴지통을 불러올 수 없습니다.', + empty: '휴지통이 비어 있습니다.', + summary: '{{count}}개 파일 · {{size}}', + emptyTrash: '휴지통 비우기', + restore: '복원', + purgeNow: '지금 삭제', + autoPurgeIn: '{{when}} 후 자동 삭제', + days: '일', + retentionLabel: '자동 삭제 기간', + selectAll: '모두 선택', + selectOne: '{{filename}} 선택', + selectionCount: '{{count}}개 선택됨', + bulkRestore: '선택 항목 복원', + bulkPurge: '선택 항목 삭제', + col: { + filename: '파일', + folder: '폴더', + size: '크기', + deleted: '휴지통 이동일', + autoPurge: '자동 삭제일', + owner: '소유자', + actions: '작업' + }, + confirm: { + purgeTitle: '영구 삭제?', + purgeBody: '{{filename}}이(가) 디스크에서 삭제되며 복원할 수 없습니다.', + emptyTitle: '휴지통을 비우시겠습니까?', + emptyBody: '{{count}}개의 모든 파일이 디스크에서 삭제됩니다. 이 작업은 취소할 수 없습니다.', + bulkPurgeTitle: '선택한 파일을 영구 삭제하시겠습니까?', + bulkPurgeBody: '선택한 {{count}}개 파일이 디스크에서 삭제되며 복원할 수 없습니다.', + cta: '영구 삭제' + }, + toast: { + restored: '파일이 복원되었습니다.', + restoreFailed: '파일을 복원할 수 없습니다.', + purged: '파일이 영구 삭제되었습니다.', + purgeFailed: '파일을 삭제할 수 없습니다.', + emptied: '휴지통에서 {{count}}개 파일이 삭제되었습니다.', + emptyFailed: '휴지통을 비울 수 없습니다.', + retentionSaved: '자동 삭제가 {{days}}일로 설정되었습니다.', + retentionFailed: '보존 설정을 저장할 수 없습니다.', + bulkRestored: '{{count}}개 파일이 복원되었습니다.', + bulkPurged: '{{count}}개 파일이 삭제되었습니다.' + } + }, + libraryPurge: { + title: '오래된 파일 삭제', + headerButton: '오래된 파일 삭제', + headerTooltip: '오래된 파일을 휴지통으로 일괄 이동', + description: '라이브러리에서 오래된 파일을 한 번에 정리합니다. 인쇄 기록이 있는 파일은 마지막 인쇄 날짜 기준으로, 한 번도 인쇄되지 않은 파일은 업로드 날짜 기준으로 계산됩니다.', + ageLabel: '다음보다 오래된 파일 이동', + days: '일', + includeNeverPrinted: '한 번도 인쇄되지 않은 파일 포함', + effectsTitle: '삭제 클릭 시 일어나는 일', + effect1: '일치하는 파일이 휴지통으로 이동됩니다 — 디스크에서 아직 삭제되지 않습니다.', + effect2: '보존 기간이 만료되기 전까지 언제든 휴지통에서 복원할 수 있습니다.', + effect3: '보존 기간 후 휴지통 청소기가 디스크에서 영구적으로 제거합니다.', + effect4: '외부(연결된) 폴더의 파일은 건너뜁니다 — Bambuddy는 자신이 소유하지 않은 바이트는 절대 삭제하지 않습니다.', + previewLoading: '일치하는 파일 수 확인 중…', + previewFailed: '삭제 미리보기를 불러올 수 없습니다.', + previewSummary: '{{count}}개 파일 · {{size}}이(가) 휴지통으로 이동됩니다', + andMore: '…및 {{count}}개 더', + warning: '휴지통 파일은 보존 기간이 만료될 때까지 저장 공간을 차지합니다. 즉시 디스크를 확보하려면 나중에 휴지통을 비우세요.', + confirmCta: '{{count}}개를 휴지통으로 이동', + purging: '휴지통으로 이동 중…', + toast: { + success: '{{count}}개 파일을 휴지통으로 이동했습니다.', + failed: '파일을 삭제할 수 없습니다.' + } + }, + libraryAutoPurge: { + enableLabel: '오래된 파일 자동 삭제', + enableDescription: '매일 한 번 관리자 삭제를 실행합니다. 파일이 먼저 휴지통으로 이동됩니다 — 즉시 삭제되지 않습니다.', + ageLabel: '다음보다 오래된 파일 자동 삭제', + ageDescription: '최소 7일, 최대 10년. 수동 삭제 버튼과 같은 날짜 규칙을 사용합니다.', + days: '일', + includeNeverPrinted: '한 번도 인쇄되지 않은 파일 포함', + saveFailed: '자동 삭제 설정을 저장할 수 없습니다.' + }, + archivePurge: { + headerButton: '오래된 것 삭제', + headerTooltip: '오래된 아카이브 일괄 삭제', + title: '오래된 아카이브 삭제', + description: '오래된 인쇄 기록을 정리합니다. 각 아카이브는 가장 최근 인쇄 완료 시점 기준으로 계산됩니다 — 아카이브를 다시 인쇄하면 날짜가 새로고침되므로 활성 작업은 절대 삭제되지 않습니다.', + ageLabel: '다음 기간 동안 인쇄되지 않은 아카이브 삭제', + days: '일', + effectsTitle: '삭제 클릭 시 일어나는 일', + effect1: '일치하는 각 아카이브가 데이터베이스에서 영구적으로 제거됩니다.', + effect2: '3MF, 썸네일, 타임랩스, 소스 3MF, F3D 디자인 파일 및 사진 폴더가 모두 디스크에서 삭제됩니다.', + effect3: '아카이브에 대한 휴지통이 없습니다 — 삭제는 즉각적이며 취소할 수 없습니다.', + effect4: '아카이브를 다시 인쇄하면 날짜 카운터가 초기화되므로 여전히 사용하는 아카이브는 안전합니다.', + previewLoading: '일치하는 아카이브 수 확인 중…', + previewFailed: '삭제 미리보기를 불러올 수 없습니다.', + previewSummary: '{{count}}개 아카이브 · {{size}}이(가) 삭제됩니다', + andMore: '…및 {{count}}개 더', + warning: '영구적입니다. 계속하기 전에 보관하고 싶은 것을 다운로드하거나 즐겨찾기에 추가하세요.', + confirmCta: '{{count}}개 아카이브 삭제', + purging: '삭제 중…', + toast: { + success: '{{count}}개 아카이브가 삭제되었습니다.', + failed: '아카이브를 삭제할 수 없습니다.' + }, + purgeStatsLabel: '통계에서도 제거', + purgeStatsHint: '일치하는 아카이브를 빠른 통계(필라멘트, 시간, 비용, 에너지)에서 삭제합니다. 이 옵션 없이는 빠른 통계는 모든 기여를 유지하고 파일만 디스크에서 제거됩니다.' + }, + archiveAutoPurge: { + enableLabel: '오래된 아카이브 자동 삭제', + enableDescription: '매일 한 번, 임계값 내에 인쇄되지 않은 아카이브를 영구적으로 삭제합니다. 아카이브를 다시 인쇄하면 카운터가 초기화됩니다. 휴지통 없음 — 삭제는 즉각적입니다.', + ageLabel: '다음 기간 동안 인쇄되지 않은 아카이브 자동 삭제', + ageDescription: '최소 7일, 최대 10년. 가장 최근 인쇄 완료 시점 기준 — 아카이브를 다시 인쇄하면 날짜가 새로고침됩니다. 아카이브, 3MF, 썸네일, 타임랩스 및 사진을 삭제합니다.', + days: '일', + runNow: '지금 아카이브 삭제', + saveFailed: '자동 삭제 설정을 저장할 수 없습니다.', + purgeStatsLabel: '통계에서도 제거', + purgeStatsDescription: '활성화되면 일일 정리 작업도 각 삭제된 아카이브를 빠른 통계(필라멘트, 시간, 비용, 에너지)에서 제거합니다. 기본값 비활성화 — 빠른 통계는 기여를 유지하고 파일만 디스크에서 제거됩니다.' + }, + cameraTokens: { + title: '카메라 API 토큰', + navTitle: '카메라 API 토큰', + description: 'Home Assistant, Frigate, 키오스크 또는 안정적인 URL이 필요한 다른 도구에 카메라 스트림을 내장하기 위한 장기 토큰. 각 토큰은 카메라 스트림 전용이며 언제든지 취소할 수 있습니다.', + loading: '불러오는 중…', + confirmRevoke: { + title: '이 토큰을 취소하시겠습니까?', + body: '\"{{name}}\"을(를) 사용하는 모든 장치가 즉시 접근을 잃습니다. 이 작업은 취소할 수 없습니다.', + cancel: '취소', + confirm: '취소' + }, + create: { + title: '새 토큰 만들기', + nameLabel: '토큰 이름', + namePlaceholder: '예: Home Assistant', + daysLabel: '만료까지 일 수', + submit: '만들기', + hint: '최대 수명은 365일입니다. 토큰 값은 생성 시 한 번만 표시됩니다 — 지금 복사하세요.' + }, + created: { + title: '토큰 생성됨 — 지금 복사하세요', + warning: '이 토큰은 이 번만 볼 수 있습니다. 이 대화상자를 닫으면 다시는 볼 수 없습니다.', + copy: '복사', + dismiss: '저장했습니다' + }, + list: { + myTitle: '내 토큰', + allTitle: '모든 사용자 (관리자 보기)', + empty: '아직 토큰 없음.', + name: '이름', + owner: '소유자', + prefix: '접두사', + created: '생성일', + expires: '만료일', + lastUsed: '마지막 사용', + revoke: '취소', + expired: '만료됨' + }, + toast: { + created: '토큰 생성됨', + createFailed: '토큰 생성 실패', + revoked: '토큰 취소됨', + revokeFailed: '토큰 취소 실패', + loadFailed: '토큰 불러오기 실패', + copied: '클립보드에 복사됨', + copyFailed: '복사 실패 — 수동으로 선택하여 복사하세요' + } + }, + forecast: { + title: '예측', + noSpools: '활성 스풀을 찾을 수 없습니다. 예측 데이터를 보려면 재고에 스풀을 추가하세요.', + noUsageData: '사용 데이터를 사용할 수 없습니다 — 재고 타임라인을 예측할 수 없습니다.', + sku: 'SKU', + material: '재료', + stock: '재고', + dailyRate: '소비율', + daysLeft: '남은 일수', + emptyBy: '소진 예정일', + reorderBy: '재주문 기한', + actions: '작업', + trend: '추세', + estimated: '추정', + noData: '데이터 없음', + timeframe: '기간', + chartTitle: '예상 재고 — 상위 5개 재료', + dashedLinesROP: '점선 = 재주문 시점', + stockLevel: '재고 수준', + reorderPoint: '재주문 시점', + safetyMargin: '안전 마진', + trendLegend: '추세 (기록 기반, 95% 서비스 수준)', + estimatedLegend: '추정 (무게 변화)', + noDataLegend: '데이터 없음', + ropLabel: 'ROP', + ssLabel: 'SS', + safetyStockLegend: '안전 재고', + stockArrivalLegend: '재고 입고', + stockoutLegend: '재고 소진', + alertCount_one: '{{count}}개 알림', + alertCount_other: '{{count}}개 알림', + order: '주문', + save: '저장', + cancel: '취소', + settingsSaved: '설정 저장됨', + failedSaveSettings: '설정 저장 실패', + globalLeadTimeSaved: '전역 리드 타임 저장됨', + globalLeadTime: '전역 리드 타임', + globalLeadTimeHint: '전역 리드 타임 하한값 — 모든 SKU의 재주문 시점 계산에 사용됨', + skuLeadTimeOverride: 'SKU 리드 타임 재정의', + skuLeadTimeHint: '0 = 전역 리드 타임 사용. 이 SKU에 대해 재정의하려면 >0으로 설정.', + safetyMarginLabel: '안전 마진', + effectiveLeadTime: '유효 리드 타임', + effectiveLeadTimeHint: 'max(전역 {{global}}일, SKU {{sku}}일)', + reorderPointHint: 'd̄ × LT + 안전 마진 — 재고가 이 수준에 도달하면 주문', + safetyMarginHint: '통계적 안전 재고 (z=1.65 × σ × √LT) + 사용자 정의 버퍼', + safetyMarginHintDays: '통계적 안전 재고 위에 추가되는 버퍼.{{approx}}', + safetyMarginHintDaysApprox: ' ≈ 현재 소비율로 {{g}}g.', + safetyMarginHintG: '통계적 안전 재고 위에 추가되는 고정 무게 버퍼.{{approx}}', + safetyMarginHintGApprox: ' ≈ 현재 소비율로 {{days}}일.', + individualSpools: '개별 스풀', + labelWeight: '라벨', + spoolCount_one: '스풀 {{count}}개', + spoolCount_other: '스풀 {{count}}개', + stockBreakRisk: '재고 소진 위험', + stockBreakDetail: '{{days}}일 남음, 리드 타임 {{lt}}일.', + stockBreakBefore: '보충 전 재고 소진', + reorderNow: '지금 재주문', + reorderTriggerPassed: '트리거 날짜 {{date}}가 지났습니다.', + shoppingList: '쇼핑 목록', + shoppingListItems_one: '({{count}}개 항목)', + shoppingListItems_other: '({{count}}개 항목)', + shoppingListEmpty: '쇼핑 목록이 비어 있습니다. 항목을 추가하려면 행의 장바구니 아이콘을 클릭하세요.', + addToCart: '쇼핑 목록에 추가', + alertsSnoozed: '이 SKU의 알림 음소거', + alertsEnabled: '이 SKU의 알림 음소거 해제', + addedToCart: '쇼핑 목록에 추가됨', + failedAddItem: '항목 추가 실패', + listView: '목록', + logisticsView: '물류', + qty: '수량', + weight: '무게', + leadTime: '리드 타임', + expectedRestock: '예상 재입고', + status: '상태', + note: '메모', + pending: '대기 중', + purchased: '구매됨', + received: '수령됨', + markPurchased: '구매됨으로 표시', + markReceived: '수령됨으로 표시 — 재고에 스풀 추가', + resetToPending: '대기 중으로 초기화', + remove: '제거', + clearAll: '모두 초기화', + downloadCsv: 'CSV', + addToCartTitle: '쇼핑 목록에 추가', + byQuantity: '수량 기준', + byDuration: '기간 기준', + numberOfSpools: '스풀 수', + lastHowManyDays: '몇 일 동안 지속되어야 합니까?', + noUsageQty: '사용 데이터 없음 — 수량을 1로 설정합니다.', + noteOptional: '메모 (선택사항)', + notePlaceholder: '예: 프로젝트 X용, 긴급…', + addNSpools_one: '스풀 {{count}}개 추가', + addNSpools_other: '스풀 {{count}}개 추가', + onArrival: '입고 시', + stockBreakIn: '{{days}}일 후 재고 소진.', + stockRunsOutBefore: '{{lt}}일 리드 타임이 경과하기 전에 재고가 소진됩니다.', + atRate: '{{rate}}g/일 소비율로', + moreSpools_one: '스풀 {{count}}개 더', + moreSpools_other: '스풀 {{count}}개 더', + bridgeGap: '격차를 메우기 위해 필요합니다.', + noReadAccess: '재고 예측을 볼 권한이 없습니다.', + noWriteAccess: '예측 설정을 수정할 권한이 없습니다.' + }, + diagnostic: { + modalTitle: '연결 진단 — {{name}}', + running: '진단 실행 중...', + runFailed: '진단 실행 실패: {{error}}', + retry: '다시 실행', + runButton: '진단 실행', + sectionTitle: '연결 진단', + sectionDescription: '프린터가 연결되지 않거나 인쇄되지 않는 이유를 확인합니다 — 포트 연결 가능 여부, LAN 개발자 모드, Docker 네트워크 모드, 자격증명.', + noPrinters: '구성된 프린터가 없습니다.', + overall: { + ok: '문제가 발견되지 않았습니다 — 프린터 연결이 정상입니다.', + warnings: '프린터가 작동하지만 일부 항목에 주의가 필요합니다.', + problems: '프린터가 연결되지 않거나 인쇄되지 않는 원인이 되는 문제가 발견되었습니다.' + }, + check: { + port_mqtt: { + title: '제어 포트 (MQTT 8883)', + pass: '연결 가능 — 프린터가 제어 연결을 수락하고 있습니다.', + fail: '포트 8883에 연결할 수 없습니다. 프린터가 꺼져 있거나, IP 주소가 다르거나, 방화벽이 차단하고 있습니다. 프린터 IP를 확인하고 포트 8883이 차단되지 않았는지 확인하세요.' + }, + port_ftps: { + title: '파일 전송 포트 (FTPS 990)', + pass: '연결 가능 — 인쇄 파일 전송이 작동합니다.', + warn: '포트 990에 연결할 수 없습니다. 모니터링은 작동할 수 있지만 프린터로 파일 전송에 실패합니다. 포트 990이 차단되지 않았는지 확인하세요.' + }, + port_rtsps: { + title: '카메라 포트 (RTSPS 322)', + pass: '연결 가능 — 카메라 스트림이 작동합니다.', + warn: '포트 322에 연결할 수 없습니다. 라이브 카메라 보기가 작동하지 않습니다. 인쇄에는 영향을 주지 않습니다.' + }, + network_mode: { + title: 'Docker 네트워크 모드', + pass: '호스트 네트워크 모드로 실행 중입니다.', + warn: 'Bambuddy가 Docker 브리지 네트워킹으로 실행 중입니다. 프린터 검색과 가상 프린터에는 호스트 네트워크 모드가 필요합니다 — \"network_mode: host\"로 컨테이너를 재생성하세요.', + skip: 'Docker에서 실행 중이 아닙니다 — 해당 없음.' + }, + subnet: { + title: '네트워크 서브넷', + pass: '프린터와 Bambuddy가 같은 서브넷에 있습니다.', + warn: '프린터({{printer_ip}})와 Bambuddy({{host_ip}})가 다른 서브넷에 있습니다. 서브넷 간 라우팅이 구성되어 있지 않으면 서로 연결하지 못할 수 있습니다.', + skip: '서브넷을 확인할 수 없어 건너뜁니다.' + }, + mqtt_auth: { + title: '프린터 자격증명', + pass: '프린터가 연결을 수락했습니다.', + fail: '프린터에 연결됐지만 연결을 거부했습니다. 액세스 코드 또는 시리얼 번호가 잘못됐을 가능성이 높습니다. 개발자 모드를 토글할 때마다 액세스 코드가 변경됩니다 — 프린터 화면에서 다시 복사하세요.', + skip: '확인하지 않음 — 프린터에 연결할 수 없었습니다.' + }, + developer_mode: { + title: 'LAN 개발자 모드', + pass: '개발자 모드가 활성화되어 있습니다.', + fail: '프린터에서 개발자 모드가 꺼져 있습니다. 프린터의 LAN 설정에서 활성화하고 확인을 누르세요. 이 없으면 인쇄가 시작되지 않습니다.', + skip: '확인할 수 없음 — 프린터에 연결되어 있어야 합니다.' + } + } + }, + systemHealth: { + sectionTitle: '시스템 상태', + sectionDescription: '최근 로그에서 지원 티켓이 되기 전에 직접 해결할 수 있는 알려진 문제를 스캔합니다.', + rescan: '다시 스캔', + clean: '최근 {{times}}개 로그 항목에서 알려진 문제가 발견되지 않았습니다.', + logUnavailable: '파일 로깅이 비활성화되어 로그를 스캔할 수 없습니다. 이 확인을 사용하려면 파일 로깅을 활성화하세요.', + learnMore: '수정 방법', + fixLabel: '수정:', + occurrences: '{{times}}회 발견 — 마지막: {{lastSeen}}', + category: { + layer8: '직접 해결 가능', + environment: '환경', + bug: '버그 보고 바람' + }, + signature: { + "ftp-auth-rejected": { + name: '프린터가 액세스 코드를 거부함', + cause: '프린터가 파일 전송 로그인을 거부했습니다. 액세스 코드가 잘못됐거나 개발자 모드를 토글한 후 변경됐습니다.', + fix: '프린터 화면(LAN 설정)에서 액세스 코드를 다시 복사하여 Bambuddy의 프린터 설정에서 업데이트하세요.' + }, + "ftp-connection-timeout": { + name: '파일 전송 연결 시간 초과', + cause: 'Bambuddy가 프린터의 파일 전송 포트(FTPS 990)에 연결할 수 없었습니다. 포트가 차단됐거나 프린터가 꺼져 있거나 다른 서브넷에 있습니다.', + fix: 'Bambuddy와 프린터 사이에서 포트 990을 차단하는 것이 없는지 확인하고, 같은 네트워크에 있는지 확인하세요.' + }, + "ftp-ssl-error": { + name: '보안 파일 전송 핸드셰이크 실패', + cause: '프린터의 파일 전송 서버와의 TLS 핸드셰이크가 실패했습니다. 주로 방화벽이나 오래된 프린터 펌웨어가 원인입니다.', + fix: '프린터 펌웨어를 업데이트하고 방화벽이나 프록시가 포트 990에서 연결을 가로채지 않는지 확인하세요.' + }, + "mqtt-connection-flapping": { + name: '프린터 연결이 계속 끊김', + cause: '제어 연결(MQTT 8883)이 반복적으로 끊어지고 다시 연결됩니다 — 주로 불안정한 네트워크 경로나 부분적으로 차단된 포트가 원인입니다.', + fix: '프린터의 Wi-Fi 신호를 확인하고, 유선 연결을 권장하며, 포트 8883이 안정적으로 연결 가능한지 확인하세요.' + }, + "camera-connection-refused": { + name: '카메라 스트림 연결 불가', + cause: '포트 RTSPS 322에서 라이브 카메라에 연결할 수 없었습니다. 포트가 차단됐거나 프린터에서 카메라 또는 LAN 라이브뷰가 꺼져 있습니다.', + fix: '프린터에서 카메라와 LAN 라이브뷰를 활성화하고 포트 322가 차단되지 않았는지 확인하세요. 인쇄에는 영향을 주지 않습니다.' + }, + "database-locked": { + name: '데이터베이스 쓰기 경합', + cause: 'SQLite 데이터베이스에 부하 시 \"database is locked\" 오류가 발생합니다 — 여러 프린터를 동시에 실행할 때 흔한 문제입니다.', + fix: 'Bambuddy를 외부 PostgreSQL 데이터베이스로 전환하세요. 설명서의 PostgreSQL 가이드를 참고하세요.' + } + } + }, + vpDiagnostic: { + title: '설정 확인 — {{name}}', + runButton: '설정 확인 실행', + running: '설정 확인 실행 중...', + runFailed: '설정 확인을 실행할 수 없습니다: {{error}}', + retry: '다시 실행', + overall: { + ok: '모든 확인이 통과됐습니다 — 이 가상 프린터가 올바르게 설정되었습니다.', + warnings: '가상 프린터가 작동하지만 일부 항목에 주의가 필요합니다.', + problems: '슬라이서가 이 가상 프린터를 인식하거나 사용할 수 없는 원인이 되는 문제가 발견되었습니다.' + }, + check: { + enabled: { + title: '가상 프린터 활성화', + fail: '이 가상 프린터가 꺼져 있습니다. 검색 가능하게 하려면 켜세요.' + }, + running: { + title: '서비스 실행 중', + fail: '가상 프린터가 활성화됐지만 서비스가 실행 중이 아닙니다. Bambuddy 로그를 확인하세요 — 바인드 IP 충돌이나 권한 오류가 보통 원인입니다.' + }, + bind_interface: { + title: '바인드 네트워크 인터페이스', + fail: '바인드 인터페이스가 설정되지 않았거나 이 호스트에 더 이상 존재하지 않습니다. 바인드 인터페이스 드롭다운에서 현재 인터페이스를 선택하세요.' + }, + access_code: { + title: '액세스 코드 설정됨', + fail: '액세스 코드가 설정되지 않았습니다. 슬라이서에는 여기에 설정한 것과 동일한 8자리 액세스 코드가 필요합니다.' + }, + target_printer: { + title: '대상 프린터', + fail: '대상 프린터가 선택되지 않았습니다. 프록시 모드에는 실제 프린터가 필요합니다.', + warn: '대상 프린터가 현재 오프라인입니다 — 재연결되면 프록시가 재개됩니다.' + }, + port_ftps: { + title: '파일 업로드 서비스 (포트 {{port}})', + fail: '바인드 IP의 포트 {{port}}에서 수신 중인 서비스가 없어 슬라이서가 파일을 업로드할 수 없습니다. 이 인터페이스의 포트 충돌이 일반적인 원인입니다.' + }, + port_mqtt: { + title: '제어 서비스 (포트 {{port}})', + fail: '바인드 IP의 포트 {{port}}에서 수신 중인 서비스가 없어 슬라이서가 연결하거나 상태를 표시할 수 없습니다.' + }, + port_bind: { + title: '검색 서비스 (포트 {{port}})', + fail: '바인드 IP의 포트 {{port}}에서 수신 중인 서비스가 없어 슬라이서의 검색 핸드셰이크가 실패합니다.' + }, + certificate: { + title: 'TLS 인증서', + pass: '인증서가 준비됐습니다. Bambuddy CA 인증서(위)가 슬라이서의 신뢰 저장소에 가져와져 있는지 확인하세요.', + fail: '이 가상 프린터의 TLS 인증서가 없습니다. Bambuddy 데이터 디렉터리가 쓰기 가능한지 확인하세요.' + } + } + } +}; +