diff --git a/lib/data/game_translations_ko.dart b/lib/data/game_translations_ko.dart index 03decae..42fe777 100644 --- a/lib/data/game_translations_ko.dart +++ b/lib/data/game_translations_ko.dart @@ -784,3 +784,320 @@ const Map boringItemTranslationsKo = { 'exit code': '종료 코드', 'errno': 'errno', }; + +/// 몬스터 드롭 아이템 한국어 번역 +/// 몬스터 처치 시 드롭되는 아이템들 (pq_config_data의 Monsters 테이블 3번째 필드) +const Map dropItemTranslationsKo = { + // 레벨 0-5 드롭 + 'misspelling': '오타', + 'yellow flag': '노란 깃발', + 'punctuation': '구두점', + 'question mark': '물음표', + 'red squiggle': '빨간 밑줄', + 'amber light': '주황 신호등', + 'empty pointer': '빈 포인터', + 'array fragment': '배열 조각', + 'infinity shard': '무한 파편', + 'failed check': '실패한 검사', + 'malformed token': '잘못된 토큰', + 'garbled text': '깨진 텍스트', + 'fence post': '울타리 기둥', + 'twisted gate': '비틀린 게이트', + 'spinning wheel': '돌아가는 바퀴', + 'dripping byte': '새는 바이트', + 'overflowing cup': '넘치는 컵', + 'tangled thread': '엉킨 스레드', + 'void fragment': '공허 조각', + 'crash crystal': '충돌 결정', + 'thrown object': '던진 객체', + 'hourglass': '모래시계', + 'severed cable': '끊어진 케이블', + 'missing icon': '없는 아이콘', + 'locked door': '잠긴 문', + + // 레벨 6-10 드롭 + 'leaked byte': '누수 바이트', + 'overflow data': '오버플로우 데이터', + 'null crystal': '널 결정', + 'broken index': '깨진 인덱스', + 'morphed type': '변형된 타입', + 'dangling reference': '댕글링 참조', + 'duplicate key': '중복 키', + 'wrapped number': '래핑된 숫자', + 'format specifier': '포맷 지정자', + 'malicious query': '악성 쿼리', + 'script tag': '스크립트 태그', + 'forged request': '위조된 요청', + 'escaped path': '이스케이프된 경로', + 'shell command': '쉘 명령어', + 'tangled threads': '엉킨 스레드들', + 'locked mutex': '잠긴 뮤텍스', + 'spinning lock': '돌아가는 락', + 'inverted queue': '역전된 큐', + 'hungry process': '굶주린 프로세스', + 'corrupted block': '손상된 블록', + 'crushed frame': '부서진 프레임', + 'garbled bytes': '깨진 바이트들', + 'racing bits': '레이싱 비트', + 'floating reference': '떠다니는 참조', + + // 레벨 11-20 드롭 + 'panic message': '패닉 메시지', + 'blue fragment': '블루 조각', + 'dumped core': '덤프된 코어', + 'segment piece': '세그먼트 조각', + 'bus token': '버스 토큰', + 'missing page': '누락된 페이지', + 'invalid cache': '무효 캐시', + 'translation fail': '변환 실패', + 'transfer error': '전송 오류', + 'signal flood': '신호 홍수', + 'expired timer': '만료된 타이머', + 'rom error': 'ROM 오류', + 'boot failure': '부팅 실패', + 'boot sector': '부트 섹터', + 'infected mbr': '감염된 MBR', + 'hidden process': '숨겨진 프로세스', + 'kernel exploit': '커널 익스플로잇', + 'vm breach': 'VM 침투', + 'management mode': '관리 모드', + 'cpu patch': 'CPU 패치', + 'speculative exec': '추측 실행', + 'kernel leak': '커널 누출', + 'bit flip': '비트 플립', + 'frozen memory': '얼어붙은 메모리', + 'direct access': '직접 접근', + 'timing info': '타이밍 정보', + 'persistent threat': '지속적 위협', + 'boot implant': '부트 임플란트', + 'management engine': '관리 엔진', + + // 레벨 21-30 드롭 + 'apt sample': 'APT 샘플', + 'classified doc': '기밀 문서', + 'undisclosed vuln': '미공개 취약점', + 'compromised package': '침해된 패키지', + 'poisoned source': '오염된 소스', + 'crafted email': '조작된 이메일', + 'system tool': '시스템 도구', + 'memory only': '메모리 전용', + 'mutating code': '변이 코드', + 'self-modifying': '자기 변형', + 'hidden section': '숨겨진 섹션', + + // 레벨 31-40 드롭 + 'propagating mass': '전파되는 덩어리', + 'c2 beacon': 'C2 비콘', + 'encrypted key': '암호화된 키', + 'mining rig': '채굴 장비', + 'stolen data': '탈취된 데이터', + 'password hash': '비밀번호 해시', + 'keystroke log': '키스트로크 로그', + 'captured frame': '캡처된 프레임', + 'clipboard data': '클립보드 데이터', + 'forged record': '위조된 레코드', + + // 레벨 41-45 드롭 + 'plc payload': 'PLC 페이로드', + 'wiper code': '와이퍼 코드', + 'smb exploit': 'SMB 익스플로잇', + 'nsa implant': 'NSA 임플란트', + 'leaked tool': '유출된 도구', + + // 레벨 46-53 드롭 + 'corrupted scale': '손상된 비늘', + 'garbled essence': '깨진 정수', + 'system fragment': '시스템 조각', + 'shattered block': '산산조각난 블록', + 'reality tear': '현실의 균열', + 'divine error': '신성한 오류', + 'primordial bug': '원초적 버그', + + // 추가 몬스터 드롭 (코드 품질, 공격 등) + 'old signature': '오래된 시그니처', + 'outdated syntax': '구식 문법', + 'tangled logic': '꼬인 로직', + 'monolithic blob': '모놀리식 덩어리', + 'loop reference': '루프 참조', + 'unexplained constant': '설명 없는 상수', + 'fixed string': '고정된 문자열', + 'shared state': '공유 상태', + 'duplicate bug': '중복 버그', + 'mysterious ritual': '신비로운 의식', + 'unreachable block': '도달 불가 블록', + 'undead thread': '언데드 스레드', + 'parentless process': '부모 없는 프로세스', + 'ghost reference': '유령 참조', + 'observer effect': '관찰자 효과', + 'quantum state': '양자 상태', + 'deterministic flaw': '결정론적 결함', + 'fractal complexity': '프랙탈 복잡도', + 'catastrophic fail': '재앙적 실패', + 'documentation bug': '문서화 버그', + 'stealth code': '스텔스 코드', + 'compressed threat': '압축된 위협', + 'encrypted payload': '암호화된 페이로드', + 'delivery mechanism': '전달 메커니즘', + 'stage one': '1단계', + 'stage two': '2단계', + 'startup entry': '시작 항목', + 'elevated token': '상승된 토큰', + 'network hop': '네트워크 홉', + 'covert comm': '은밀한 통신', + 'command callback': '명령 콜백', + 'hidden channel': '숨겨진 채널', + 'ping payload': '핑 페이로드', + 'web shell': '웹 쉘', + 'callback conn': '콜백 연결', + 'listening port': '리스닝 포트', + 'uploaded script': '업로드된 스크립트', + 'scheduled task': '예약된 작업', + 'boot persistence': '부트 지속성', + 'dll implant': 'DLL 임플란트', + 'memory injection': '메모리 인젝션', + 'code injection': '코드 인젝션', + 'async payload': '비동기 페이로드', + 'global table': '전역 테이블', + 'transaction ntfs': '트랜잭션 NTFS', + 'mapped memory': '매핑된 메모리', + 'overwritten dll': '덮어쓰인 DLL', + 'fileless dll': '파일리스 DLL', + 'custom loader': '커스텀 로더', + 'direct invoke': '직접 호출', + 'wow64 transition': 'WoW64 전환', + 'nested async': '중첩된 비동기', + 'unhandled await': '처리 안 된 await', + 'main thread': '메인 스레드', + 'gc stress': 'GC 스트레스', + 'allocation spike': '할당 급증', + 'destructor fail': '소멸자 실패', + 'soft memory': '소프트 메모리', + 'pool overflow': '풀 오버플로우', + 'permgen fill': 'PermGen 가득참', + 'off-heap grow': 'Off-heap 증가', + 'nio overflow': 'NIO 오버플로우', + 'tls accumulate': 'TLS 누적', + 'socket drain': '소켓 고갈', + 'descriptor exhaust': '디스크립터 고갈', + 'event handler': '이벤트 핸들러', + 'subscription miss': '구독 누락', + 'pending promise': '대기 중인 Promise', + 'activity ref': '액티비티 참조', + 'image buffer': '이미지 버퍼', + 'db resource': 'DB 리소스', + 'unclosed io': '닫히지 않은 IO', + 'uncommitted tx': '커밋 안 된 TX', + 'orphan session': '고아 세션', + 'unlimited cache': '무제한 캐시', + 'unbounded queue': '무한 큐', + 'circular fail': '순환 실패', + 'mutex fight': '뮤텍스 싸움', + 'cpu spin': 'CPU 스핀', + 'cache line': '캐시 라인', + 'memory locality': '메모리 지역성', + 'core binding': '코어 바인딩', + 'thread thrash': '스레드 스래싱', + 'page table': '페이지 테이블', + 'inter-processor': '프로세서 간', + 'cli hang': 'CLI 행', + 'scheduler race': '스케줄러 레이스', + 'read-copy-update': 'RCU', + 'sequence lock': '시퀀스 락', + 'reader-writer': '리더-라이터', + 'fast mutex': '패스트 뮤텍스', + 'atomic spin': '아토믹 스핀', + 'sync point': '동기화 지점', + 'signal wait': '시그널 대기', + 'count error': '카운트 오류', + 'ipc fail': 'IPC 실패', + 'shm corrupt': 'SHM 손상', + 'fd block': 'FD 블록', + 'network fd': '네트워크 FD', + 'event poll': '이벤트 폴', + 'kernel queue': '커널 큐', + 'completion port': '완료 포트', + 'async io': '비동기 IO', + 'vectored io': '벡터 IO', + 'sendfile fail': 'sendfile 실패', + 'pipe transfer': '파이프 전송', + 'vm splice': 'VM 스플라이스', + 'pipe duplicate': '파이프 복제', + 'preallocate': '사전 할당', + 'sparse file': '희소 파일', + 'o_direct': 'O_DIRECT', + 'fsync fail': 'fsync 실패', + 'fdatasync': 'fdatasync', + 'write barrier': '쓰기 배리어', + 'filesystem log': '파일시스템 로그', + 'metadata exhaust': '메타데이터 고갈', + 'dcache corrupt': 'dcache 손상', + 'block buffer': '블록 버퍼', + 'file cache': '파일 캐시', + 'kernel alloc': '커널 할당', + 'kernel malloc': '커널 malloc', + 'virtual alloc': '가상 할당', + 'high memory': '상위 메모리', + 'low memory': '하위 메모리', + 'out of memory': '메모리 부족', + 'process flood': '프로세스 홍수', + 'decompression': '압축 해제', + 'entity expand': '엔티티 확장', + 'backtrack': '백트래킹', + 'hashtable dos': '해시테이블 DoS', + 'o(n^2) attack': 'O(n²) 공격', + 'slow http': '느린 HTTP', + 'slow post': '느린 POST', + 'range header': '범위 헤더', + 'hash flood': '해시 홍수', + 'tcp handshake': 'TCP 핸드셰이크', + 'datagram storm': '데이터그램 폭풍', + 'ping storm': '핑 폭풍', + 'broadcast amp': '브로드캐스트 증폭', + 'udp amp': 'UDP 증폭', + 'resolver abuse': '리졸버 남용', + 'monlist abuse': 'monlist 남용', + 'upnp abuse': 'UPnP 남용', + 'cache abuse': '캐시 남용', + 'ldap abuse': 'LDAP 남용', + 'spoofed source': '스푸핑된 소스', + 'distributed target': '분산 타겟', + 'burst attack': '버스트 공격', + 'evasive dos': '회피형 DoS', + 'l7 attack': 'L7 공격', + 'handshake abuse': '핸드셰이크 남용', + 'ssl reneg': 'SSL 재협상', + 'ssl downgrade': 'SSL 다운그레이드', + 'compression leak': '압축 누출', + 'http compression': 'HTTP 압축', + 'ssl3 fallback': 'SSL3 폴백', + 'openssl leak': 'OpenSSL 누출', + 'bash bug': 'Bash 버그', + 'copy on write': 'Copy-on-Write', + 'vm escape': 'VM 탈출', + 'buffer overread': '버퍼 오버리드', + 'wifi handshake': 'WiFi 핸드셰이크', + 'wpa3 attack': 'WPA3 공격', + 'wifi frag': 'WiFi 조각화', + 'wifi encryption': 'WiFi 암호화', + 'wifi pmk': 'WiFi PMK', + 'rogue ap': '불량 AP', + 'probe response': '프로브 응답', + 'wifi disassoc': 'WiFi 연결해제', + 'ssid spam': 'SSID 스팸', + 'bt exploit': 'BT 익스플로잇', + 'bt remote': 'BT 원격', + 'ble bug': 'BLE 버그', + 'bt classic': 'BT 클래식', + 'bt key': 'BT 키', + 'bt pairing': 'BT 페어링', + 'docsis bug': 'DOCSIS 버그', + 'upnp vuln': 'UPnP 취약점', + 'tcp/ip bug': 'TCP/IP 버그', + 'tcpip stack': 'TCP/IP 스택', + 'tcp random': 'TCP 랜덤', + 'dns bug': 'DNS 버그', + 'memory bug': '메모리 버그', + 'polkit priv': 'Polkit 권한', + 'privilege escape': '권한 탈출', + 'heap overflow': '힙 오버플로우', +}; diff --git a/lib/src/core/l10n/game_data_l10n.dart b/lib/src/core/l10n/game_data_l10n.dart index 76d9d28..bcda297 100644 --- a/lib/src/core/l10n/game_data_l10n.dart +++ b/lib/src/core/l10n/game_data_l10n.dart @@ -344,32 +344,20 @@ class GameDataL10n { /// 아이템 이름 문자열 파싱 후 번역 (기존 저장 데이터 호환) /// 예: "Golden Iterator of Compilation" → "컴파일의 황금 이터레이터" + /// 예: "index out of bounds Array fragment" → "인덱스 초과의 배열 조각" static String translateItemString(BuildContext context, String itemString) { if (!_isKorean(context) || itemString.isEmpty) return itemString; - // "X Y of Z" 패턴 파싱 - final ofMatch = RegExp(r'^(.+)\s+of\s+(.+)$').firstMatch(itemString); + // 1. specialItem 형식 체크: "Attrib Special of ItemOf" + // itemOfs에 있는 값으로 끝나는지 확인 + final specialItemResult = _tryTranslateSpecialItem(itemString); + if (specialItemResult != null) return specialItemResult; - if (ofMatch != null) { - final beforeOf = ofMatch.group(1)!; // "Golden Iterator" - final afterOf = ofMatch.group(2)!; // "Compilation" + // 2. 몬스터 드롭 형식 체크: "{monster_lowercase} {drop_ProperCase}" + final monsterDropResult = _tryTranslateMonsterDrop(itemString); + if (monsterDropResult != null) return monsterDropResult; - // "X Y" 분리 (마지막 단어가 special) - final words = beforeOf.split(' '); - if (words.length >= 2) { - final attrib = words.sublist(0, words.length - 1).join(' '); - final special = words.last; - - final attribKo = itemAttribTranslationsKo[attrib] ?? attrib; - final specialKo = specialTranslationsKo[special] ?? special; - final itemOfKo = itemOfsTranslationsKo[afterOf] ?? afterOf; - - // 한국어 어순: "ItemOf의 Attrib Special" - return '$itemOfKo의 $attribKo $specialKo'; - } - } - - // "X Y" 패턴 (of 없음) + // 3. interestingItem 형식: "Attrib Special" (2단어) final words = itemString.split(' '); if (words.length == 2) { final attrib = words[0]; @@ -381,7 +369,92 @@ class GameDataL10n { return '$attribKo $specialKo'; } - // 단일 단어 (boringItem 등) - 잡템 번역 시도 - return boringItemTranslationsKo[itemString] ?? itemString; + // 4. 단일 단어 (boringItem 등) - 잡템 번역 시도 + return boringItemTranslationsKo[itemString] ?? + dropItemTranslationsKo[itemString.toLowerCase()] ?? + itemString; + } + + /// specialItem 형식 번역 시도 + /// "Attrib Special of ItemOf" → "ItemOf의 Attrib Special" + static String? _tryTranslateSpecialItem(String itemString) { + // "of" 뒤의 부분이 itemOfs에 있는지 확인 + final ofMatch = RegExp(r'^(.+)\s+of\s+(.+)$').firstMatch(itemString); + if (ofMatch == null) return null; + + final beforeOf = ofMatch.group(1)!; + final afterOf = ofMatch.group(2)!; + + // afterOf가 itemOfs에 있어야 specialItem 형식 + if (!itemOfsTranslationsKo.containsKey(afterOf)) return null; + + // beforeOf를 Attrib + Special로 분리 + final words = beforeOf.split(' '); + if (words.length < 2) return null; + + final attrib = words.sublist(0, words.length - 1).join(' '); + final special = words.last; + + // Attrib와 Special이 유효한지 확인 + if (!itemAttribTranslationsKo.containsKey(attrib) && + !specialTranslationsKo.containsKey(special)) { + return null; + } + + final attribKo = itemAttribTranslationsKo[attrib] ?? attrib; + final specialKo = specialTranslationsKo[special] ?? special; + final itemOfKo = itemOfsTranslationsKo[afterOf] ?? afterOf; + + return '$itemOfKo의 $attribKo $specialKo'; + } + + /// 몬스터 드롭 형식 번역 시도 + /// "{monster_lowercase} {drop_ProperCase}" → "{몬스터}의 {드롭아이템}" + static String? _tryTranslateMonsterDrop(String itemString) { + // dropItemTranslationsKo에서 매칭되는 드롭 아이템 찾기 + // (대소문자 무시, 아이템 문자열 끝에서 매칭) + for (final entry in dropItemTranslationsKo.entries) { + final dropItem = entry.key; + final dropItemProperCase = _properCase(dropItem); + + // 아이템 문자열이 드롭 아이템으로 끝나는지 확인 + if (itemString.endsWith(dropItemProperCase) || + itemString.endsWith(dropItem)) { + // 드롭 아이템 앞 부분이 몬스터 이름 + String monsterPart; + if (itemString.endsWith(dropItemProperCase)) { + monsterPart = + itemString.substring(0, itemString.length - dropItemProperCase.length).trim(); + } else { + monsterPart = + itemString.substring(0, itemString.length - dropItem.length).trim(); + } + + if (monsterPart.isEmpty) continue; + + // 몬스터 이름 번역 (소문자를 원래 형태로 변환하여 찾기) + final monsterNameKey = _toTitleCase(monsterPart); + final monsterKo = + monsterTranslationsKo[monsterNameKey] ?? monsterPart; + + final dropKo = entry.value; + return '$monsterKo의 $dropKo'; + } + } + return null; + } + + /// 첫 글자만 대문자로 (나머지는 그대로) + static String _properCase(String s) { + if (s.isEmpty) return s; + return s[0].toUpperCase() + s.substring(1); + } + + /// 각 단어의 첫 글자를 대문자로 (Title Case) + static String _toTitleCase(String s) { + return s.split(' ').map((word) { + if (word.isEmpty) return word; + return word[0].toUpperCase() + word.substring(1); + }).join(' '); } }