"""Local CLI language; physical Linux consoles use ASCII without changing locale/fonts."""
import builtins
import json
import os

import field_profiles as profiles

MESSAGES = {
    'AI 연결용 login ID [Enter=기존 유지]: ':'AI login ID [Enter=keep current]: ',
    'AI 연결용 비밀번호 [Enter=기존 유지, 화면에 표시 안 됨]: ':'AI password [hidden; Enter=keep current]: ',
    '비밀번호 다시 입력: ':'Confirm password: ',
    '기존 CA·주소로 로그인 1회를 실행하려면 LOGIN 입력: ':'One login with ACTIVE CA/address: type LOGIN [Enter=cancel]: ',
    '원격 결과는 미확정으로 남기고 기존 파일을 유지하려면 CANCEL 입력: ':'Preserve original files and unknown remote outcome: type CANCEL [Enter=cancel]: ',
    'Web 화면 계정이 아닌 AI 연결용 계정이어야 합니다. 성공 시 이전 AI token이 폐기됩니다.':'Use an AI connection account, not a Web UI account. Success revokes previous AI token.',
    'AI 인증정보 숨김 입력·로그인1회·WSS 확인. Web 관리자 계정과 구분하세요.':'AI credentials, one login, WSS status. Not a Web administrator account.',
    'ct auth 명령의 sudo 경로를 사용하세요.':'Use sudo through ct auth.',
    '취소; 변경 없음':'Cancelled; no change',
    '; 비밀값은 출력하지 않습니다. ct auth status로 확인하세요.':'; secrets hidden. Check ct auth status.',
    '; 기존 인증정보 보존, 재시도 없음':'; original credentials preserved, no retry',
    '비밀번호 확인 불일치; 변경 없음':'Password confirmation differs; no change',
    'ct auth resume으로 진행 중인 인증 작업부터 확인하세요.':'Inspect pending authentication via ct auth resume first.',
    '확정된 새 세션이 없습니다. Web 결과를 확인하고 로그인 반복을 피하세요.':'No confirmed new session. Check Web outcome; avoid repeated login.',
    '카메라를 모두 Stop한 뒤 실행하세요. 자동 Stop하지 않습니다.':'Stop all cameras first. No automatic camera Stop.',
    'Sidecar 정상 종료 미확인; 로그인하지 않습니다.':'Sidecar stop unconfirmed; no login.',
    'AI_LOGIN_PASS; WSS_NOT_CONFIRMED. 재로그인하지 말고 Web 연결 상태를 확인하세요.':'AI_LOGIN_PASS; WSS_NOT_CONFIRMED. Check Web connection, do not log in again.',
    'AI_LOGIN_PASS; SESSION_SAVED. ct start 후 WSS를 확인하세요. 자동 Start하지 않았습니다.':'AI_LOGIN_PASS; SESSION_SAVED. Check WSS after ct start. No automatic Start.',
    '발급된 세션 또는 적용 단계는 취소할 수 없습니다. ct auth resume으로 확인하세요.':'Issued session/apply phase cannot be cancelled. Inspect ct auth resume.',
    'si 대화형 터미널에서 실행하세요. 비밀번호를 인자로 받지 않습니다.':'Use an interactive si terminal. No password arguments.',
    '로그인 결과 미확정. Sidecar 정지 유지, 자동 재시도 없음; ct auth status로 확인':'Login outcome unknown. Sidecar remains stopped; no retry. Check ct auth status.',
    'Contextra 현장 관리 / field maintenance (0 Exit)':'Contextra field maintenance (0 Exit)',
    '1 상태/status  2 환경선택/profile  3 설정/edit  4 계정저장/credentials  5 CA 파일':'1 Status  2 Select profile  3 Edit profile  4 Credentials  5 CA file',
    '6 NIC 상태  7 NIC 적용  8 앱준비/prepare  9 명시적 연결/connect  10 앱적용/apply':'6 NIC status  7 Apply NIC  8 Prepare app  9 Connect explicitly  10 Apply app',
    '11 서비스 Start  12 정상 Stop  13 긴급/emergency  14 진단/diagnose':'11 Start services  12 Stop services  13 Emergency import  14 Diagnose',
    '15 적용재개/resume  16 설정복구/restore  17 파일경로/paths  18 파일편집/nano':'15 Resume apply  16 Restore config  17 File paths  18 Edit file (nano)',
    '19 기록반출/export  20 Python APP 패치  21 LLM chat  22 LLM API':'19 Export record  20 Python APP patch  21 LLM chat  22 LLM API',
    '23 사용자 확인기록  24 수동메모  25 주 Web 선택':'23 Record acceptance  24 Add note  25 Select control Web',
    '번호 [Enter=메뉴 유지]: ':'Number [Enter=keep menu]: ',
    '실행하려면 YES 입력: ':'Type YES to execute [Enter=cancel]: ',
    '메뉴는 계속 사용할 수 있습니다. 상태1 / 경로17 / 복구16':'Menu remains available: status=1 / paths=17 / restore=16',
    '현재 작업을 중단했습니다. 진행 중 적용은 상태/재개로 확인하세요.':'Cancelled this action. Inspect status/resume for an interrupted apply.',
    '완료. 카메라는 자동 Start하지 않습니다.':'Done. Cameras are NOT automatically started.',
    '일부 컨테이너가 실행 중입니다. 자동 강제 회수하지 않습니다.':'Some containers remain. No automatic force cleanup.',
    'LLM을 먼저 종료하세요. 자동 종료하지 않습니다.':'Stop the LLM first. It is not stopped automatically.',
    'Python 변경을 오프라인 APP image로 적용하려면 APPLY 입력: ':'Type APPLY for offline Python APP image [Enter=cancel]: ',
    'ct auth는 현재 실행 설정의 인증용입니다. 선택 프로필 계정 저장은 ct profile credentials, 새 Web 연결은 ct config connect.':'ct auth uses ACTIVE runtime settings. Profile credentials: ct profile credentials. New Web: ct config connect.',
    '조회 실패. 다른 상태 확인은 계속합니다.':'Query failed; other checks continue.',
    '편집 전에 ct stop을 실행하세요.':'Run ct stop before editing.',
    '해당 작업 중단:':'Action stopped:', '중단:':'Stopped:',
    '화면에만 표시합니다. 외부 전달 전 비밀정보를 확인하세요.':'Display only. Review secrets before sharing logs.',
    ' / -=비우기':' / -=clear', '; Enter=현재값 유지':'; Enter=keep current',
    '미설정':'unset', '환경:':'Environment:', '환경 이름':'Environment label', '환경 설명':'Environment label',
    '스인 내부망':'Office LAN', '폐쇄 현장망':'Closed-site LAN',
    '일반 설정(si 편집):':'Editable profile (si):', '계정 파일(소유자 전용, 값 출력 없음):':'Credentials (owner-only; values hidden):',
    '선택 Web의 공개 CA:':'Selected Web public CA:',
    'NIC 실행 설정(root): /etc/netplan/*.yaml':'NIC runtime files (root): /etc/netplan/*.yaml',
    '앱 실행 site(root):':'Runtime site (root):', '앱 실행 Compose(root):':'Runtime Compose (root):',
    '기존 env 입력(root, 내용은 출력하지 않음):':'Existing env inputs (root; contents hidden):',
    '설정 편집: ct profile edit / ct profile file':'Edit source: ct profile edit / ct profile file',
    'NIC 적용: ct net apply / 앱 준비: ct config prepare / 명시적 연결: ct config connect':'NIC: ct net apply / app: ct config prepare / explicit login: ct config connect',
    '기존 파일 변경 가져오기: ct emergency / 계정 저장: ct profile credentials / CA: ct ca':'Import runtime edits: ct emergency / credentials: ct profile credentials / CA: ct ca',
    '실행 설정 조회 실패. 프로필 편집은 계속 사용할 수 있습니다.':'Runtime lookup failed. Profile editing remains available.',
    '유선 NIC':'Wired NIC', '주소 방식 dhcp/static':'Address mode dhcp/static',
    '고정 IPv4/prefix (DHCP에서는 비워도 됨)':'Static IPv4/prefix (may be empty with DHCP)',
    'DNS 쉼표 목록':'DNS comma-separated list', 'AI Redis 공개 포트':'AI Redis exposed port',
    'AI control/WSS 포트':'AI control/WSS port', '미디어 접근 허용 CIDR':'Media access CIDR',
    'Redis 허용 Web IPv4 쉼표 목록':'Allowed Redis clients (IPv4 comma-separated)',
    '선택 Web IPv4':'Selected Web IPv4', 'Event 전체 URL':'Full Event URL',
    'Web이 발급/기대하는 AI server ID':'Web-issued AI server ID',
    'SSH1023 유지. 다른 SSH 포트는 NIC 변경에 섞어 자동 적용하지 않습니다.':'SSH1023 is preserved. NIC changes do not change the SSH listener.',
    '로그인 경로는 기존 계약 /api/v1/auth/login 입니다. 다른 Web 후보·미디어 목록은 ct profile file에서 편집합니다.':'Login path: /api/v1/auth/login. Other Web/media entries: ct profile file.',
    '저장 완료. 아직 NIC/Runtime/로그인은 변경하지 않았습니다.':'Saved only. NIC, runtime and login unchanged.',
    'AI 연결용 login ID':'AI login ID',
    '비밀번호 [Enter=기존 유지, 숨김 입력]: ':'Password [hidden; Enter=keep current]: ',
    '새 비밀번호 확인: ':'Confirm new password: ', '비밀번호 확인 불일치':'Password confirmation differs',
    '유효한 비밀번호가 필요합니다.':'A valid password is required.', '계정 저장:':'Credentials saved:',
    '로그인 요청은 하지 않았습니다. 다음: ct config prepare/connect':'No login sent. Next: ct config prepare/connect',
    '선택 환경:':'Selected environment:', '선택 Web 설정:':'Selected Web:',
    '프로필 포트: control/WSS':'Profile ports: control/WSS', 'Redis 허용 주소:':'Allowed Redis clients:',
    '실제 NIC IPv4:':'Actual NIC IPv4:', '실제 NIC 조회 실패: ip -4 -br addr':'NIC lookup failed: ip -4 -br addr',
    '앱 설정 AI 주소:':'App-configured AI address:', '앱 실행 설정:':'Active app settings:',
    '주소 불일치: 아직 새 환경을 앱에 적용하지 않았습니다. 다음: ct config prepare/connect/apply':'Address differs: app still uses old settings. Next: ct config prepare/connect/apply',
    '실행 설정 지문:':'Runtime fingerprint:', '일치':'match', '수동 변경 감지 - ct emergency':'manual changes detected - ct emergency',
    'Runtime 설정 오류. ct 도구는 사용 가능합니다. ct emergency 또는 ct config restore로 확인하세요.':'Runtime configuration error. ct is available: ct emergency / ct config restore.',
    '계정 등록:':'Credentials present:', 'CA 준비:':'CA present:', '진행 중:':'Pending:',
    '마지막 발급 결과:':'Last enrollment result:', '미측정 (ct diagnose로 TCP만 확인)':'Not probed (ct diagnose checks TCP only)',
    'TCP 연결됨; TLS/로그인/WSS는 별도 확인':'TCP connected; TLS/login/WSS require separate checks',
    'TCP 연결 실패; 상대 전원/주소/포트 확인':'TCP failed; check peer power/address/port',
    '주 연결':'control Web', '보조 후보':'alternative candidate', '미디어:':'Media:',
    '참고용; 실제 입력은 Web rtspUrl':'Reference only; actual input uses Web rtspUrl',
    ' / TCP 연결됨':' / TCP connected', ' / TCP 연결 실패 (다른 입력은 차단하지 않음)':' / TCP failed (other inputs not blocked)',
    '현재 실행 Sidecar:':'Running Sidecar:', 'Sidecar 상태 미확인. 로그인 요청은 하지 않았습니다.':'Sidecar state unconfirmed. No login sent.',
    '프로필 조회 오류:':'Profile lookup failed:', 'ct profile list / ct profile file로 수정하세요.':'Repair using ct profile list / ct profile file.',
    '프로필 번호 / Enter=취소: ':'Profile number / Enter=cancel: ', '번호 오류':'Invalid number',
    '선택만 변경했습니다. NIC/서비스/로그인 변경 없음.':'Selection changed only. NIC/services/login unchanged.',
    '새 프로필 이름(영문)':'New profile name (ASCII)', '이미 있는 프로필입니다.':'Profile already exists.',
    '일반 설정만 복사했습니다. 계정/CA는 새로 등록합니다.':'Only general settings copied. Set credentials and CA separately.',
    '편집 경로:':'Edit path:', '문법 검사 완료. 적용은 ct config prepare/connect 또는 ct net apply.':'Syntax checked. Apply via ct config prepare/connect or ct net apply.',
    '주 연결 Web 번호: ':'Control Web number: ', '주 Web 선택만 저장했습니다. 계정/CA는 Web별로 별도입니다.':'Web selection saved only. Credentials and CA are separate per Web.',
    '선택 중인 프로필은 삭제하지 않습니다.':'Cannot archive the selected profile.',
    '프로필을 보존 archive로 이동하려면 DELETE 입력: ':'Type DELETE to archive the profile [Enter=cancel]: ',
    '같은 archive가 있습니다.':'Archive already exists.', '계정/CA 원본은 보존했습니다.':'Credentials and CA preserved.',
    '선택 프로필을 새 준비본으로 만듭니다. 아직 로그인/기존 설정 적용은 하지 않습니다.':'Prepare a new stage from this profile. No login or active setting change.',
    'PREPARE 입력: ':'Type PREPARE [Enter=cancel]: ',
    '선택 프로필의 계정으로 로그인/인증서 요청1회. 기존 token이 폐기될 수 있습니다.':'One login/enrollment with selected credentials. Previous token may be revoked.',
    '카메라/서비스가 실행 중이면 먼저 ct stop이 필요합니다. 성공 후에도 자동 Start하지 않습니다.':'Run ct stop first if services are active. No automatic Start after success.',
    '이전 요청 결과 미확정. 원격 처리 확인 후 ct config retry를 명시적으로 사용하세요.':'Previous outcome unconfirmed. Check remote outcome before explicit ct config retry.',
    '이전 원격 결과를 확인했고 새 요청을 승인하려면 RETRY 입력: ':'After checking remote outcome, type RETRY [Enter=cancel]: ',
    '명시적 연결 요청을 하려면 CONNECT 입력: ':'Type CONNECT for one explicit request [Enter=cancel]: ',
    '발급 확인. 로컬 설정 적용: ct config apply':'Certificate verified. Local apply: ct config apply',
    '검증된 준비본을 적용하고 서비스 정지 상태로 유지하려면 APPLY 입력: ':'Type APPLY to apply verified stage, services remain stopped [Enter=cancel]: ',
    '로컬 설정만 이전 기준으로 복구하려면 RESTORE 입력: ':'Type RESTORE for local configuration only [Enter=cancel]: ',
    '적용 중입니다. resume/restore를 사용하세요.':'Apply in progress. Use resume/restore.',
    '원격 요청 이력이 있습니다. 발급/처리 상태 확인 후 resume/retry하세요.':'Remote request exists. Check outcome before resume/retry.',
    '미발급 준비본을 보존하고 선택 해제하려면 CANCEL 입력: ':'Type CANCEL to preserve/deselect unissued stage [Enter=cancel]: ',
    '기존 Runtime 유지. 준비본은 보존했습니다.':'Active runtime unchanged. Stage preserved.',
    '비밀정보 없는 수동 작업 메모: ':'Manual note (no secrets): ', '사용자 확인 결과: ':'User-observed result: ',
    '실제로 확인한 항목만 적으세요. 예: 로그인/WSS/Redis/카메라1 Start-Stop. 미확인은 제외.':'Record only observed login/WSS/Redis/camera results; omit unchecked items.',
    '사용자 관측으로 기록했습니다. 자동 검증 성공으로 대체하지 않습니다.':'Recorded as user observation, not automated PASS.',
    '메모 포함 비밀정보가 없는지 검토했다면 EXPORT 입력: ':'Review notes for secrets, then type EXPORT [Enter=cancel]: ',
    'USB 반출 파일:':'USB export file:', 'SHA 불일치 일반 설정 가져오기. image/코드/디스크/인증 검증은 끄지 않습니다.':'Import supported config drift. Image/code/disk/auth guards remain enabled.',
    '1 실행 Compose  2 기존 env/overlay 재해석값  3 site AI 주소  Enter=취소':'1 Active Compose  2 Rendered env/overlay  3 Site AI address  Enter=cancel',
    '원본 선택: ':'Choose source: ', '프로필 값과 충돌하면 위 가져온 값으로 바뀝니다. 서비스/로그인은 아직 변경하지 않습니다.':'Imported values replace conflicting profile values. No service/login changes yet.',
    '프로필에 수용하려면 IMPORT 입력: ':'Type IMPORT to accept into profile [Enter=cancel]: ',
    '수용 완료. 계정/CA는 별도로 확인하고 ct config prepare/connect/apply로 이어갑니다.':'Imported. Check credentials/CA, then ct config prepare/connect/apply.',
    '다른 ct 설정 작업이 진행 중입니다. 해당 터미널에서 완료/취소 후 재개하세요.':'Another ct configuration action holds the lock. Finish/cancel it first.',
    '폴더:':'Folder:', ' 0=상위 / q=취소':' 0=parent / q=cancel', '번호: ':'Number: ',
    '1 기본 반입 폴더  2 마운트된 USB  3 경로 입력  4 번호형 탐색  Enter=1':'1 Inbox  2 USB (mount if needed)  3 Direct path  4 Number picker  Enter=1',
    '선택: ':'Choice: ', '파일 또는 폴더 절대 경로: ':'Absolute file/folder path: ',
    '폴더 항목이 너무 많습니다. 더 좁은 경로를 입력하세요.':'Too many folder entries; select a narrower directory.',
    '선택 파일:':'Selected file:', '파일 SHA256:':'File SHA256:',
    '별도로 전달받은 인증서 fingerprint와 대조하세요. private key는 반입하지 않습니다.':'Compare with independently supplied CA fingerprint. Do not import private keys.',
    '이 CA를 선택 Web의 신뢰 기준으로 복사하려면 TRUST 입력: ':'Type TRUST to copy this public CA for selected Web [Enter=cancel]: ',
    '복사 완료:':'Copied:', '위 fingerprint를 Web 담당자가 별도 전달한 값과 대조하세요. 설치나 trust 변경은 하지 않았습니다.':'Compare fingerprint independently with the Web operator. Trust has not changed.',
    '방식:':'Mode:', '저장 주소:':'Configured address:', '(DHCP 자동)':'(DHCP)', '주소:':'Address:', '프로필:':'Profile:',
    '현장 전환은 물리 콘솔 권장. netplan 적용은 ct net apply, 복구는 ct net restore.':'Use physical console for network transitions: ct net apply / ct net restore.',
    'SSH가 끊길 수 있습니다. 물리 콘솔에서 권장합니다. Web/앱 설정은 별도 적용입니다.':'SSH may disconnect. Use physical console. Web/app settings are applied separately.',
    '이 NIC 설정을 적용하려면 NET 입력: ':'Type NET to apply NIC [Enter=cancel]: ',
    '이전 NIC 설정으로 복구하려면 RESTORE 입력: ':'Type RESTORE for prior NIC settings [Enter=cancel]: ',
    '명시적 로그인/CSR 요청을1회 수행합니다. 결과가 불명확하면 자동 반복하지 않습니다.':'Sending one explicit login/CSR request. Unknown outcomes are NOT automatically retried.',
    '프로필 준비 완료. 아직 로그인/Runtime 적용하지 않았습니다. 다음: ct config connect':'Profile prepared, not logged in/applied. Next: ct config connect',
    '설정 반영 완료·재부팅 유지. 서비스/카메라 자동 Start 없음. 다음: ct start':'Configuration persisted. Services/cameras NOT started. Next: ct start',
    '진행 중 준비가 있습니다. ct config status/resume/cancel을 사용하세요.':'Pending stage exists: ct config status/resume/cancel.',
    '준비 후 프로필/계정/CA가 변경됐습니다. 미발급이면 cancel 후 다시 prepare하세요.':'Profile/credentials/CA changed after prepare. If unissued, cancel and prepare again.',
    '준비 이후 파일 변경: ':'Prepared file changed: ', '준비본의 기준이 변경됐습니다. 원격 요청을 하지 않습니다.':'Prepared baseline changed; no remote request.',
    'root 여유15GiB 필요':'Root needs 15GiB free', '설정 오류':'Configuration error',
    '설정 파일이 없거나 너무 큽니다: ':'Config file missing/too large: ', '설정 항목 오류: ':'Invalid configuration fields: ',
    '계정 파일은 root 또는 si 소유600이어야 합니다.':'Credentials must be owned by root/si with mode600.',
    '계정 파일 비밀번호 형식 오류':'Invalid credential password format',
    '절대 경로만 허용하며 symlink는 사용하지 않습니다.':'Absolute non-symlink path required.',
}

KOREAN_MESSAGES = {
    'Local prepared version:':'로컬 마지막 준비 버전:',
    'Local successful version:':'로컬 마지막 발급 성공 버전:',
    'Editable source: network/webs/ports/redis_allow/media in the profile. Format version stays 1.':'직접 편집: 프로필의 network/webs/포트/redis_allow/media. 파일 형식 version은 1을 유지합니다.',
    'Connection revision: webs[].connection_version or ct config version NUMBER; then prepare.':'연결 버전: webs[].connection_version 또는 ct config version 번호로 지정 후 prepare합니다.',
    'Runtime site/Compose/env: supported imports only via ct emergency; do not edit active hashes or prepared files.':'실행 site/Compose/env: 지원 변경만 ct emergency로 수용합니다. active 지문/준비본은 직접 고치지 않습니다.',
    'Credentials and CA: use ct profile credentials / ct ca; never publish private files.':'계정/CA: ct profile credentials / ct ca를 사용하고 비공개 파일은 공유하지 않습니다.',
    'Web certificate signing is not configured. Ask the Web operator to configure its existing CA certificate/key paths and reload the application.':'Web 인증서 발급 설정이 없습니다. Web 담당자에게 기존 CA 인증서/서명키 경로 설정과 앱 반영을 요청하세요.',
    'Web certificate signing failed. Ask the Web operator to check CA/key validity, matching and file permissions.':'Web 인증서 서명 실패입니다. Web 담당자에게 CA/키 유효성·일치·읽기 권한 확인을 요청하세요.',
    'Preserve this stage and session. Do not cancel, change the connection version or create a new CA. Retry once after the Web fix.':'준비본과 세션을 보존하세요. cancel·버전 변경·새 CA 생성을 하지 말고 Web 조치 후 한 번 재시도하세요.',
    '26 Connection version  27 CPU/RAM resources  28 Language  29 ARP status':'26 연결 설정 버전  27 CPU/RAM 진단  28 언어  29 ARP 상태',
    '32 Data clean  33 DB reset  34 Camera reset  35 Redis clean  36 Storage policy':'32 저장자료 정리  33 DB 기록 초기화  34 카메라 초기화  35 Redis 정리  36 보관 설정',
    '30 VSCode safety status (settings only; no automatic restart)':'30 VSCode 안전 설정 상태 (자동 재시작 없음)',
    '31 USB status (ct usb mount / ct usb unmount)':'31 USB 상태 (ct usb mount / ct usb unmount)',
    'Prepared connectionConfigVersion:':'준비한 연결 설정 버전:',
    'Sending connectionConfigVersion:':'실제 요청에 보낼 연결 설정 버전:',
    'Web current version: UNKNOWN (no remote query or login).':'Web 현재 버전: 미확인 (원격 조회·로그인 하지 않음).',
    'Web current version: UNKNOWN':'Web 현재 버전: 미확인',
    'connection_version override:':'직접 지정한 연결 버전:',
    'Profile version=1 is its file format. It is NOT connection_version.':'프로필 version=1은 파일 형식입니다. 연결 설정 번호가 아닙니다.',
    'Set: ct config version NUMBER | auto (no login)':'지정: ct config version 번호 | auto (로그인 요청 없음)',
    'Saved locally. No remote request. Next: ct config prepare':'로컬 저장 완료. 원격 요청 없음. 다음: ct config prepare',
    'Connection revision rejected. Not a password error. Web current version is unknown.':'연결 설정 버전이 거절됐습니다. 비밀번호 오류가 아닙니다. Web 최신 번호는 미확인입니다.',
    'Preserve failed stage: ct config cancel; ct config version NUMBER; ct config prepare':'실패 준비본 보존: ct config cancel → ct config version 번호 → ct config prepare',
    'Check the account for LOGIN, or the token for CERTIFICATE. Do not increase versions for 401.':'LOGIN이면 계정, CERTIFICATE이면 token을 확인하세요. 401을 번호 증가로 해결하지 않습니다.',
    'Check peer address, route and CA. The outcome may be unknown; do not automatically retry.':'상대 주소·경로·CA를 확인하세요. 원격 처리 결과가 불명확하므로 자동 재시도하지 않습니다.',
    'Inspect the recorded phase before ct config retry. Certificate success is not WSS acceptance.':'기록된 단계를 확인한 뒤 ct config retry를 사용하세요. 인증서 성공과 WSS 연결은 별도입니다.',
    'USB number (Enter=cancel): ':'USB 번호 (Enter=취소): ',
    'USB unmount number [Enter=cancel]: ':'마운트 해제할 USB 번호 [Enter=취소]: ',
    'Mount this USB read-only? Type MOUNT (Enter=cancel): ':'이 USB를 읽기 전용 마운트하려면 MOUNT (Enter=취소): ',
    'No eligible USB filesystem. OS/data/LVM/swap disks are excluded. No format operation.':'대상 USB가 없습니다. OS/데이터/LVM/swap 디스크는 제외합니다. 포맷하지 않습니다.',
    'No eligible mounted USB. Protected disks are not selectable.':'해제 가능한 USB가 없습니다. 보호 디스크는 선택할 수 없습니다.',
    'Close files/terminals using this USB. Busy mounts remain mounted; no force/lazy option.':'USB를 사용하는 파일·터미널을 닫으세요. 사용 중이면 그대로 두며 강제/지연 해제하지 않습니다.',
    'Save editor files and stop extension tasks first. Extensions reload; shell/SSH are not targeted.':'편집 파일을 저장하고 확장 작업을 멈추세요. 확장만 다시 로드하며 터미널/SSH는 대상이 아닙니다.',
    'Next:':'다음:', 'Phase:':'단계:', 'attempts:':'기록된 시도:',
}


def language():
    value=os.environ.get('CONTEXTRA_CLI_LANG')
    if value not in ('en','ko','auto'):
        try:value=profiles.read_json(profiles.STATE/'language.json').get('language','auto')
        except (OSError,ValueError):value='auto'
    if value in ('en','ko'):return value
    try:tty=os.ttyname(0)
    except OSError:tty=''
    return 'ko' if tty.startswith('/dev/pts/') or os.environ.get('SSH_CONNECTION') else 'en'


def text(value):
    value=str(value)
    if language()!='en':
        for english,korean in sorted(KOREAN_MESSAGES.items(),key=lambda x:-len(x[0])):
            value=value.replace(english,korean)
        return value
    for korean,english in sorted(MESSAGES.items(),key=lambda x:-len(x[0])):
        value=value.replace(korean,english)
    return value.encode('ascii','backslashreplace').decode('ascii')


def print(*args, **kwargs):
    builtins.print(*(text(a) for a in args),**kwargs)


def input(prompt=''):
    return builtins.input(text(prompt))


def configure(args):
    print('CLI language:',language(),' / en=ASCII / ko=Korean / auto=physical console English, SSH Korean')
    value=args[0] if len(args)==1 else input('en / ko / auto [Enter=keep current]: ').strip() if not args else ''
    if not value:return
    if value not in ('en','ko','auto'):raise ValueError('ct lang en | ko | auto')
    profiles.atomic(profiles.STATE/'language.json',{'language':value})
    print('Saved:',value,'No OS locale/font changes. Setting path:',profiles.STATE/'language.json')
