feat(l10n): 몬스터 드롭 아이템 번역 로직 개선
- dropItemTranslationsKo 추가 (250+ 드롭 아이템 번역)
- translateItemString 함수 리팩터링:
- specialItem 형식 정확히 감지 (itemOfs 검증)
- 몬스터 드롭 형식 지원 ("{monster} {drop}" → "{몬스터}의 {드롭}")
- 인벤토리 아이템이 올바르게 한글로 표시됨
This commit is contained in:
@@ -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