feat(l10n): 몬스터 드롭 아이템 번역 로직 개선
- dropItemTranslationsKo 추가 (250+ 드롭 아이템 번역)
- translateItemString 함수 리팩터링:
- specialItem 형식 정확히 감지 (itemOfs 검증)
- 몬스터 드롭 형식 지원 ("{monster} {drop}" → "{몬스터}의 {드롭}")
- 인벤토리 아이템이 올바르게 한글로 표시됨
This commit is contained in:
@@ -784,3 +784,320 @@ const Map<String, String> boringItemTranslationsKo = {
|
||||
'exit code': '종료 코드',
|
||||
'errno': 'errno',
|
||||
};
|
||||
|
||||
/// 몬스터 드롭 아이템 한국어 번역
|
||||
/// 몬스터 처치 시 드롭되는 아이템들 (pq_config_data의 Monsters 테이블 3번째 필드)
|
||||
const Map<String, String> 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': '힙 오버플로우',
|
||||
};
|
||||
|
||||
@@ -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(' ');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user