// 게임 텍스트 로컬라이제이션 (BuildContext 없이 사용) // progress_service.dart, pq_logic.dart 등에서 사용 // 지원 언어: 한국어(ko), 영어(en), 일본어(ja) import 'package:asciineverdie/data/game_translations_ko.dart'; import 'package:asciineverdie/data/game_translations_ja.dart'; /// 현재 게임 로케일 설정 (전역) String _currentLocale = 'en'; /// 현재 로케일 가져오기 String get currentGameLocale => _currentLocale; /// 로케일 설정 (앱 시작 시 호출) void setGameLocale(String locale) { _currentLocale = locale; } /// 한국어 여부 확인 bool get isKoreanLocale => _currentLocale == 'ko'; /// 일본어 여부 확인 bool get isJapaneseLocale => _currentLocale == 'ja'; /// 로케일별 문자열 반환 헬퍼 (리팩토링용) /// /// 영문(en), 한국어(ko), 일본어(ja) 순서로 인자를 받아 /// 현재 로케일에 맞는 문자열을 반환합니다. String _l(String en, String ko, String ja) { if (isKoreanLocale) return ko; if (isJapaneseLocale) return ja; return en; } /// 각 단어 첫 글자를 대문자로 변환 (Title Case) /// /// 예: "syntax error" → "Syntax Error" String _toTitleCase(String text) { return text .split(' ') .map((word) { if (word.isEmpty) return word; return word[0].toUpperCase() + word.substring(1).toLowerCase(); }) .join(' '); } // ============================================================================ // 프롤로그 텍스트 // ============================================================================ const _prologueTextsEn = [ 'Receiving an ominous vision from the Code God', 'The old Compiler Sage reveals a prophecy: "The Glitch God has awakened"', 'A sudden Buffer Overflow resets your village, leaving you as the sole survivor', 'With unexpected resolve, you embark on a perilous journey to the Null Kingdom', ]; const _prologueTextsKo = [ '코드의 신으로부터 불길한 환영을 받다', '늙은 컴파일러 현자가 예언을 밝히다: "글리치 신이 깨어났다"', '갑작스러운 버퍼 오버플로우가 마을을 초기화하고, 당신만이 유일한 생존자로 남다', '예상치 못한 결의로 널(Null) 왕국을 향한 위험한 여정을 시작하다', ]; const _prologueTextsJa = [ 'コードの神から不吉な幻影を受ける', '老いたコンパイラー賢者が予言を明かす:「グリッチゴッドが目覚めた」', '突然のバッファオーバーフローが村をリセットし、あなただけが唯一の生存者となる', '予想外の決意で、ヌル(Null)王国への危険な旅に出発する', ]; List get prologueTexts { if (isKoreanLocale) return _prologueTextsKo; if (isJapaneseLocale) return _prologueTextsJa; return _prologueTextsEn; } // ============================================================================ // 태스크 캡션 // ============================================================================ String get taskCompiling => _l('Compiling', '컴파일 중', 'コンパイル中'); String get taskPrologue => _l('Prologue', '프롤로그', 'プロローグ'); String taskHeadingToMarket() => _l( 'Heading to the Data Market to trade loot', '전리품을 팔기 위해 데이터 마켓으로 이동 중', '戦利品を売るためデータマーケットへ移動中', ); String taskUpgradingHardware() => _l( 'Upgrading hardware at the Tech Shop', '테크 샵에서 하드웨어 업그레이드 중', 'テックショップでハードウェアをアップグレード中', ); String taskEnteringDebugZone() => _l('Entering the Debug Zone', '디버그 존 진입 중', 'デバッグゾーンに進入中'); String taskDebugging(String monsterName) => _l( 'Debugging $monsterName', '$monsterName 디버깅 중', '$monsterName をデバッグ中', ); String taskFinalBoss(String bossName) => _l( 'Final Battle: $bossName', '최종 보스와 대결: $bossName', '最終ボスと対決: $bossName', ); String taskSelling(String itemDescription) => _l( 'Selling $itemDescription', '$itemDescription 판매 중', '$itemDescription を販売中', ); // ============================================================================ // 부활 시퀀스 메시지 // ============================================================================ /// 부활 애니메이션 중 표시 메시지 String get animationResurrecting => _l('Resurrecting...', '부활 중...', '復活中...'); String get taskReturningToTown => _l('Returning to town...', '마을로 귀환 중...', '町に戻っている...'); String get taskRestockingAtShop => _l('Restocking at shop...', '상점에서 장비 정비 중...', 'ショップで装備を整備中...'); String get taskHeadingToHuntingGrounds => _l('Heading to hunting grounds...', '사냥터로 이동 중...', '狩り場へ向かっている...'); // ============================================================================ // 사망 화면 메시지 // ============================================================================ String get deathYouDied => _l('YOU DIED', '사망', '死亡'); String get deathSacrificedToResurrect => _l('Sacrificed to Resurrect', '부활 대가로 희생됨', '復活のために犠牲'); String get deathEquipment => _l('Equipment', '장비', '装備'); String get deathNoSacrificeNeeded => _l('No sacrifice needed', '희생 없이 부활', '犠牲なしで復活'); String get deathCoinRemaining => _l('Coin Remaining', '남은 코인', '残りコイン'); String get deathResurrect => _l('Resurrect', '부활', '復活'); String get deathAutoResurrect => _l('Auto Resurrect', '자동 부활', '自動復活'); String get deathCombatLog => _l('Combat Log', '전투 기록', '戦闘ログ'); String deathKilledBy(String killerName) => _l('Killed by $killerName', '$killerName에게 사망', '$killerNameに倒された'); String get deathEnvironmentalHazard => _l('Environmental hazard', '환경 피해로 사망', '環境ダメージで死亡'); // ============================================================================ // UI 일반 메시지 // ============================================================================ String get uiNoPotions => _l('No potions', '포션 없음', 'ポーションなし'); String get uiTapToContinue => _l('Tap to continue', '탭하여 계속', 'タップして続行'); String get uiNoSkills => _l('No skills', '습득한 스킬이 없습니다', 'スキルなし'); String get uiNoBonusStats => _l('No bonus stats', '추가 스탯 없음', 'ボーナスステータスなし'); String get uiNoActiveBuffs => _l('No active buffs', '활성 버프 없음', 'アクティブバフなし'); String get uiReady => _l('Ready', '준비', '準備完了'); String get uiPotions => _l('Potions', '포션', 'ポーション'); String get uiBuffs => _l('Buffs', '버프', 'バフ'); // ============================================================================ // 스탯 약어 // ============================================================================ String get statStr => _l('STR', '힘', '筋力'); String get statCon => _l('CON', '체력', '耐久'); String get statDex => _l('DEX', '민첩', '敏捷'); String get statInt => _l('INT', '지능', '知力'); String get statWis => _l('WIS', '지혜', '精神'); String get statCha => _l('CHA', '매력', '魅力'); // ============================================================================ // 패시브 능력 설명 // ============================================================================ // HP/MP 보너스는 동일 형식이므로 그대로 유지 String passiveHpBonus(int percent) => 'HP +$percent%'; String passiveMpBonus(int percent) => 'MP +$percent%'; String passivePhysicalBonus(int percent) => _l('Physical +$percent%', '물리 공격 +$percent%', '物理攻撃 +$percent%'); String passiveDefenseBonus(int percent) => _l('Defense +$percent%', '방어력 +$percent%', '防御力 +$percent%'); String passiveMagicBonus(int percent) => _l('Magic +$percent%', '마법 공격 +$percent%', '魔法攻撃 +$percent%'); String passiveEvasionBonus(int percent) => _l('Evasion +$percent%', '회피율 +$percent%', '回避率 +$percent%'); String passiveCritBonus(int percent) => _l('Critical +$percent%', '크리티컬 +$percent%', 'クリティカル +$percent%'); String passiveHpRegen(int percent) => _l( 'Recover $percent% HP after combat', '전투 후 HP $percent% 회복', '戦闘後HP $percent%回復', ); String passiveMpRegen(int percent) => _l( 'Recover $percent% MP after combat', '전투 후 MP $percent% 회복', '戦闘後MP $percent%回復', ); // ============================================================================ // 전투 로그 메시지 // ============================================================================ String combatYouHit(String targetName, int damage) => _l( 'You hit $targetName for $damage damage', '$targetName에게 $damage 데미지', '$targetNameに$damageダメージ', ); String combatYouEvaded(String targetName) => _l( 'You evaded $targetName\'s attack!', '$targetName의 공격 회피!', '$targetNameの攻撃を回避!', ); String combatEvadedAttackFrom(String targetName) => _l( 'Evaded attack from $targetName', '$targetName의 공격 회피', '$targetNameの攻撃を回避', ); String combatHealedFor(int amount) => _l('Healed for $amount HP', 'HP $amount 회복', 'HP $amount回復'); String combatCritical(int damage, String targetName) => _l( 'CRITICAL! $damage damage to $targetName!', '크리티컬! $targetName에게 $damage 데미지!', 'クリティカル! $targetNameに$damageダメージ!', ); String combatMonsterHitsYou(String monsterName, int damage) => _l( '$monsterName hits you for $damage damage', '$monsterName이(가) $damage 데미지', '$monsterNameが$damageダメージを与えた', ); String combatMonsterEvaded(String monsterName) => _l( '$monsterName evaded your attack!', '$monsterName이(가) 공격 회피!', '$monsterNameが攻撃を回避!', ); String combatBlocked(int damage) => _l( 'Blocked! Reduced to $damage damage', '방어! $damage 데미지로 감소', 'ブロック! $damageダメージに軽減', ); String combatParried(int damage) => _l( 'Parried! Reduced to $damage damage', '패리! $damage 데미지로 감소', 'パリィ! $damageダメージに軽減', ); // 스킬 관련 전투 메시지 String combatSkillCritical(String skillName, int damage) => _l( 'CRITICAL $skillName! $damage damage!', '크리티컬 $skillName! $damage 데미지!', 'クリティカル$skillName! $damageダメージ!', ); String combatSkillDamage(String skillName, int damage) => _l('$skillName: $damage damage', '$skillName: $damage 데미지', '$skillName: $damageダメージ'); // HP 형식이 동일하므로 단순화 String combatSkillHeal(String skillName, int amount) => '$skillName: +$amount HP'; String get uiHeal => _l('Heal', '힐', 'ヒール'); String combatBuffActivated(String skillName) => _l('$skillName activated!', '$skillName 발동!', '$skillName 発動!'); String combatDebuffApplied(String skillName, String targetName) => _l( '$skillName applied to $targetName!', '$skillName → $targetName에 적용!', '$skillName → $targetNameに適用!', ); String combatDotTick(String skillName, int damage) => _l( '$skillName ticks for $damage damage', '$skillName: $damage 지속 데미지', '$skillName: $damage 継続ダメージ', ); // 포션 형식이 동일하므로 단순화 String combatPotionUsed(String potionName, int amount, String statName) => '$potionName: +$amount $statName'; String combatPotionDrop(String potionName) => _l('Dropped: $potionName', '획득: $potionName', '獲得: $potionName'); // 사망 화면 전투 로그 (death overlay) String combatBlockedAttack(String monsterName, int reducedDamage) => _l( 'Blocked $monsterName\'s attack ($reducedDamage reduced)', '$monsterName의 공격 방어 ($reducedDamage 감소)', '$monsterNameの攻撃を防御 ($reducedDamage軽減)', ); String combatParriedAttack(String monsterName, int reducedDamage) => _l( 'Parried $monsterName\'s attack ($reducedDamage reduced)', '$monsterName의 공격 패리 ($reducedDamage 감소)', '$monsterNameの攻撃をパリィ ($reducedDamage軽減)', ); String get deathSelfInflicted => _l('Self-inflicted damage', '자해 데미지로 사망', '自傷ダメージで死亡'); // ============================================================================ // 퀘스트 캡션 // ============================================================================ String questPatch(String name) => _l('Patch $name', '$name 패치하기', '$name をパッチする'); String questLocate(String item) => _l('Locate $item', '$item 찾기', '$item を探す'); String questTransfer(String item) => _l('Transfer this $item', '이 $item 전송하기', 'この$item を転送する'); String questDownload(String item) => _l('Download $item', '$item 다운로드하기', '$item をダウンロードする'); String questStabilize(String name) => _l('Stabilize $name', '$name 안정화하기', '$name を安定化する'); // ============================================================================ // Act 제목 // ============================================================================ String actTitle(String romanNumeral) => _l('Act $romanNumeral', '$romanNumeral막', '第$romanNumeral幕'); // ============================================================================ // 시네마틱 텍스트 - 시나리오 1: 캐시 존 // ============================================================================ String cinematicCacheZone1() => _l( 'Exhausted, you reach a safe Cache Zone in the corrupted network', '지쳐서 손상된 네트워크의 안전한 캐시 존에 도착하다', '疲れ果てて、破損したネットワークの安全なキャッシュゾーンに到着する', ); String cinematicCacheZone2() => _l( 'You reconnect with old allies and fork new ones', '옛 동맹들과 재연결하고 새로운 동료들을 포크하다', '古い同盟者と再接続し、新しい仲間をフォークする', ); String cinematicCacheZone3() => _l( 'You attend a council of the Debugger Knights', '디버거 기사단 회의에 참석하다', 'デバッガー騎士団の会議に参加する', ); String cinematicCacheZone4() => _l( 'Many bugs await. You are chosen to patch them!', '많은 버그들이 기다린다. 당신이 패치하도록 선택되었다!', '多くのバグが待っている。あなたがパッチを当てるよう選ばれた!', ); // ============================================================================ // 시네마틱 텍스트 - 시나리오 2: 전투 // ============================================================================ String cinematicCombat1() => _l( 'Your target is in sight, but a critical bug blocks your path!', '목표가 눈앞에 있지만, 치명적인 버그가 길을 막는다!', 'ターゲットは目の前だが、致命的なバグが道を塞ぐ!', ); String cinematicCombat2(String nemesis) => _l( 'A desperate debugging session begins with $nemesis', '$nemesis와의 필사적인 디버깅 세션이 시작되다', '$nemesisとの必死のデバッグセッションが始まる', ); String cinematicCombatLocked(String nemesis) => _l( 'Locked in intense debugging with $nemesis', '$nemesis와 치열한 디버깅 중', '$nemesisと激しいデバッグ中', ); String cinematicCombatCorrupts(String nemesis) => _l( '$nemesis corrupts your stack trace', '$nemesis가 당신의 스택 트레이스를 손상시키다', '$nemesisがあなたのスタックトレースを破損させる', ); String cinematicCombatWorking(String nemesis) => _l( 'Your patch seems to be working against $nemesis', '당신의 패치가 $nemesis에게 효과를 보이는 것 같다', 'あなたのパッチが$nemesisに効いているようだ', ); String cinematicCombatVictory(String nemesis) => _l( 'Victory! $nemesis is patched! System reboots for recovery', '승리! $nemesis가 패치되었다! 복구를 위해 시스템이 재부팅된다', '勝利!$nemesisはパッチされた!復旧のためシステムが再起動する', ); String cinematicCombatWakeUp() => _l( 'You wake up in a Safe Mode, but the kernel awaits', '안전 모드에서 깨어나지만, 커널이 기다린다', 'セーフモードで目覚めるが、カーネルが待ち構えている', ); // ============================================================================ // 시네마틱 텍스트 - 시나리오 3: 배신 // ============================================================================ String cinematicBetrayal1(String guy) => _l( 'What relief! You reach the secure server of $guy', '안도감! $guy의 보안 서버에 도착하다', '安堵!$guyのセキュアサーバーに到着する', ); String cinematicBetrayal2(String guy) => _l( 'There is celebration, and a suspicious private handshake with $guy', '축하가 이어지고, $guy와 수상한 비밀 핸드셰이크를 나누다', '祝賀が続き、$guyと怪しい秘密のハンドシェイクを交わす', ); String cinematicBetrayal3(String item) => _l( 'You forget your $item and go back to retrieve it', '$item을 잊고 다시 가져오러 돌아가다', '$itemを忘れて取りに戻る', ); String cinematicBetrayal4() => _l( 'What is this!? You intercept a corrupted packet!', '이게 뭐지!? 손상된 패킷을 가로채다!', 'これは何だ!?破損したパケットを傍受する!', ); String cinematicBetrayal5(String guy) => _l( 'Could $guy be a backdoor for the Glitch God?', '$guy가 글리치 신의 백도어일 수 있을까?', '$guyはグリッチゴッドのバックドアなのか?', ); String cinematicBetrayal6() => _l( 'Who can be trusted with this intel!? -- The Binary Temple, of course', '이 정보를 누구에게 맡길 수 있을까!? -- 바이너리 신전이다', 'この情報を誰に託せるか!? -- バイナリ神殿だ', ); // ============================================================================ // 몬스터 수식어 // ============================================================================ String modifierDead(String s) => _l('fallen $s', '쓰러진 $s', '倒れた$s'); String modifierComatose(String s) => _l('lurking $s', '잠복하는 $s', '潜む$s'); String modifierCrippled(String s) => _l('twisted $s', '흉측한 $s', '歪んだ$s'); String modifierSick(String s) => _l('tainted $s', '오염된 $s', '汚染された$s'); String modifierUndernourished(String s) => _l('ravenous $s', '굶주린 $s', '飢えた$s'); String modifierFoetal(String s) => _l('nascent $s', '태동기 $s', '胎動期$s'); String modifierBaby(String s) => _l('fledgling $s', '초기형 $s', '初期型$s'); String modifierPreadolescent(String s) => _l('evolving $s', '진화 중인 $s', '進化中の$s'); String modifierTeenage(String s) => _l('lesser $s', '하급 $s', '下級$s'); String modifierUnderage(String s) => _l('incomplete $s', '불완전한 $s', '不完全な$s'); String modifierGreater(String s) => _l('greater $s', '상위 $s', '上位$s'); String modifierMassive(String s) => _l('massive $s', '거대한 $s', '巨大な$s'); String modifierEnormous(String s) => _l('enormous $s', '초거대 $s', '超巨大$s'); String modifierGiant(String s) => _l('giant $s', '자이언트 $s', 'ジャイアント$s'); String modifierTitanic(String s) => _l('titanic $s', '타이타닉 $s', 'タイタニック$s'); String modifierVeteran(String s) => _l('veteran $s', '베테랑 $s', 'ベテラン$s'); String modifierBattle(String s) => _l('Battle-$s', '전투-$s', '戦闘-$s'); String modifierCursed(String s) => _l('cursed $s', '저주받은 $s', '呪われた$s'); String modifierWarrior(String s) => _l('warrior $s', '전사 $s', '戦士$s'); String modifierWere(String s) => _l('Were-$s', '늑대인간-$s', '狼男-$s'); String modifierUndead(String s) => _l('undead $s', '언데드 $s', 'アンデッド$s'); String modifierDemon(String s) => _l('demon $s', '데몬 $s', 'デーモン$s'); String modifierMessianic(String s) => _l('messianic $s', '메시아닉 $s', 'メシアニック$s'); String modifierImaginary(String s) => _l('imaginary $s', '상상의 $s', '想像上の$s'); String modifierPassing(String s) => _l('passing $s', '지나가는 $s', '通りすがりの$s'); // ============================================================================ // 시간 표시 // ============================================================================ String roughTimeSeconds(int seconds) => _l('$seconds seconds', '$seconds초', '$seconds秒'); String roughTimeMinutes(int minutes) => _l('$minutes minutes', '$minutes분', '$minutes分'); String roughTimeHours(int hours) => _l('$hours hours', '$hours시간', '$hours時間'); String roughTimeDays(int days) => _l('$days days', '$days일', '$days日'); // ============================================================================ // 영어 문법 함수 (한국어/일본어에서는 단순화) // ============================================================================ /// 관사 + 명사 (한국어/일본어: 수량만 표시) String indefiniteL10n(String s, int qty) { if (isKoreanLocale) { return qty == 1 ? s : '$qty $s'; } if (isJapaneseLocale) { return qty == 1 ? s : '$qty $s'; } // 영어 로직 if (qty == 1) { const vowels = 'AEIOUÜaeiouü'; final first = s.isNotEmpty ? s[0] : 'a'; final article = vowels.contains(first) ? 'an' : 'a'; return '$article $s'; } return '$qty ${_pluralize(s)}'; } /// the + 명사 (한국어/일본어: 그냥 명사) String definiteL10n(String s, int qty) { if (isKoreanLocale || isJapaneseLocale) { return s; } // 영어 로직 if (qty > 1) { s = _pluralize(s); } return 'the $s'; } /// 복수형 (영어만 해당) String _pluralize(String s) { if (s.endsWith('y')) return '${s.substring(0, s.length - 1)}ies'; if (s.endsWith('us')) return '${s.substring(0, s.length - 2)}i'; if (s.endsWith('ch') || s.endsWith('x') || s.endsWith('s')) return '${s}es'; if (s.endsWith('f')) return '${s.substring(0, s.length - 1)}ves'; if (s.endsWith('man') || s.endsWith('Man')) { return '${s.substring(0, s.length - 2)}en'; } return '${s}s'; // ignore: unnecessary_brace_in_string_interp } // ============================================================================ // impressiveGuy 관련 // ============================================================================ String impressiveGuyPattern1(String title, String race) { if (isKoreanLocale) { // ignore: unnecessary_brace_in_string_interps return '${race}들의 $title'; // 한국어 조사 연결을 위해 중괄호 필요 } if (isJapaneseLocale) { // ignore: unnecessary_brace_in_string_interps return '${race}たちの$title'; // 일본어 연결을 위해 중괄호 필요 } return 'the $title of the ${_pluralize(race)}'; } String impressiveGuyPattern2(String title, String name1, String name2) { if (isKoreanLocale) return '$name2의 $title $name1'; if (isJapaneseLocale) return '$name2の$title $name1'; return '$title $name1 of $name2'; } // ============================================================================ // namedMonster 관련 // ============================================================================ String namedMonsterFormat(String generatedName, String monsterType) { if (isKoreanLocale) return '$monsterType $generatedName'; if (isJapaneseLocale) return '$monsterType $generatedName'; return '$generatedName the $monsterType'; } // ============================================================================ // 게임 데이터 번역 함수 (BuildContext 없이 사용) // 지원 언어: 한국어(ko), 영어(en), 일본어(ja) // ============================================================================ /// 몬스터 이름 번역 (기본 + 고급 몬스터 포함) /// /// 대소문자 무시 검색: "syntax error" → "Syntax Error"로 변환 후 검색 String translateMonster(String englishName) { // 대소문자 무시를 위해 Title Case로 변환 final titleCaseName = _toTitleCase(englishName); if (isKoreanLocale) { return monsterTranslationsKo[titleCaseName] ?? advancedMonsterTranslationsKo[titleCaseName] ?? monsterTranslationsKo[englishName] ?? advancedMonsterTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return monsterTranslationsJa[titleCaseName] ?? advancedMonsterTranslationsJa[titleCaseName] ?? monsterTranslationsJa[englishName] ?? advancedMonsterTranslationsJa[englishName] ?? englishName; } return englishName; } /// 종족 이름 번역 String translateRace(String englishName) { if (isKoreanLocale) return raceTranslationsKo[englishName] ?? englishName; if (isJapaneseLocale) return raceTranslationsJa[englishName] ?? englishName; return englishName; } /// 직업 이름 번역 String translateKlass(String englishName) { if (isKoreanLocale) return klassTranslationsKo[englishName] ?? englishName; if (isJapaneseLocale) return klassTranslationsJa[englishName] ?? englishName; return englishName; } /// 칭호 이름 번역 String translateTitle(String englishName) { if (isKoreanLocale) return titleTranslationsKo[englishName] ?? englishName; if (isJapaneseLocale) return titleTranslationsJa[englishName] ?? englishName; return englishName; } /// 인상적인 칭호 번역 (impressiveTitles용) String translateImpressiveTitle(String englishName) { if (isKoreanLocale) { return impressiveTitleTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return impressiveTitleTranslationsJa[englishName] ?? englishName; } return englishName; } /// 특수 아이템 이름 번역 String translateSpecial(String englishName) { if (isKoreanLocale) return specialTranslationsKo[englishName] ?? englishName; if (isJapaneseLocale) return specialTranslationsJa[englishName] ?? englishName; return englishName; } /// 아이템 속성 이름 번역 (기본 + 추가 속성 포함) String translateItemAttrib(String englishName) { if (isKoreanLocale) { return itemAttribTranslationsKo[englishName] ?? additionalItemAttribTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return itemAttribTranslationsJa[englishName] ?? additionalItemAttribTranslationsJa[englishName] ?? englishName; } return englishName; } /// 아이템 "~의" 접미사 번역 (기본 + 추가 포함) String translateItemOf(String englishName) { if (isKoreanLocale) { return itemOfsTranslationsKo[englishName] ?? additionalItemOfsTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return itemOfsTranslationsJa[englishName] ?? additionalItemOfsTranslationsJa[englishName] ?? englishName; } return englishName; } /// 단순 아이템 번역 (기본 + 추가 드롭 포함) String translateBoringItem(String englishName) { if (isKoreanLocale) { return boringItemTranslationsKo[englishName] ?? dropItemTranslationsKo[englishName] ?? additionalDropTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return boringItemTranslationsJa[englishName] ?? dropItemTranslationsJa[englishName] ?? additionalDropTranslationsJa[englishName] ?? englishName; } return englishName; } /// interestingItem 번역 (attrib + special 조합) /// 예: "Golden Iterator" → "황금 이터레이터" / "黄金のイテレーター" String translateInterestingItem(String attrib, String special) { if (isKoreanLocale) { final translatedAttrib = itemAttribTranslationsKo[attrib] ?? additionalItemAttribTranslationsKo[attrib] ?? attrib; final translatedSpecial = specialTranslationsKo[special] ?? special; return '$translatedAttrib $translatedSpecial'; } if (isJapaneseLocale) { final translatedAttrib = itemAttribTranslationsJa[attrib] ?? additionalItemAttribTranslationsJa[attrib] ?? attrib; final translatedSpecial = specialTranslationsJa[special] ?? special; return '$translatedAttrib$translatedSpecial'; } return '$attrib $special'; } /// 아이템 이름 문자열 전체 번역 (판매, 로그 등에 사용) /// 예: "Golden Iterator of Compilation" → "컴파일의 황금 이터레이터" /// 예: "Syntax Error fragment" → "구문 오류 조각" String translateItemNameL10n(String itemString) { if (!isKoreanLocale && !isJapaneseLocale) return itemString; if (itemString.isEmpty) return itemString; // 1. specialItem 형식: "Attrib Special of ItemOf" final ofMatch = RegExp(r'^(.+)\s+of\s+(.+)$').firstMatch(itemString); if (ofMatch != null) { final beforeOf = ofMatch.group(1)!; final afterOf = ofMatch.group(2)!; // afterOf가 itemOfs 목록에 있는지 확인 final itemOfKo = itemOfsTranslationsKo[afterOf] ?? additionalItemOfsTranslationsKo[afterOf]; final itemOfJa = itemOfsTranslationsJa[afterOf] ?? additionalItemOfsTranslationsJa[afterOf]; if (itemOfKo != null || itemOfJa != null) { // beforeOf를 interestingItem으로 분리 (attrib + special) final beforeWords = beforeOf.split(' '); if (beforeWords.length >= 2) { final attrib = beforeWords[0]; final special = beforeWords.sublist(1).join(' '); final translatedBefore = translateInterestingItem(attrib, special); if (isKoreanLocale) { return '$itemOfKo의 $translatedBefore'; } else if (isJapaneseLocale) { return '$itemOfJaの$translatedBefore'; } } } } // 2. 몬스터 드롭 형식: "{monster} {drop}" (예: "syntax error fragment") final words = itemString.split(' '); if (words.length >= 2) { // 2-1. 마지막 2단어가 드롭 아이템인지 먼저 확인 (예: "outdated syntax") // boringItemTranslations도 확인 (2단어 boringItem: "null pointer" 등) if (words.length >= 3) { final lastTwoWords = '${words[words.length - 2]} ${words.last}' .toLowerCase(); final dropKo2 = dropItemTranslationsKo[lastTwoWords] ?? additionalDropTranslationsKo[lastTwoWords] ?? boringItemTranslationsKo[lastTwoWords]; final dropJa2 = dropItemTranslationsJa[lastTwoWords] ?? additionalDropTranslationsJa[lastTwoWords] ?? boringItemTranslationsJa[lastTwoWords]; if (dropKo2 != null || dropJa2 != null) { final monsterPart = words.sublist(0, words.length - 2).join(' '); final translatedMonster = translateMonster(monsterPart); if (isKoreanLocale && dropKo2 != null) { return '$translatedMonster $dropKo2'; } else if (isJapaneseLocale && dropJa2 != null) { return '$translatedMonsterの$dropJa2'; } } } // 2-2. 마지막 단어가 드롭 아이템인지 확인 // boringItemTranslations도 확인 (monsterPart로 사용되는 경우) final lastWord = words.last.toLowerCase(); final dropKo = dropItemTranslationsKo[lastWord] ?? additionalDropTranslationsKo[lastWord] ?? boringItemTranslationsKo[lastWord]; final dropJa = dropItemTranslationsJa[lastWord] ?? additionalDropTranslationsJa[lastWord] ?? boringItemTranslationsJa[lastWord]; if (dropKo != null || dropJa != null) { // 앞 부분은 몬스터 이름 final monsterPart = words.sublist(0, words.length - 1).join(' '); final translatedMonster = translateMonster(monsterPart); if (isKoreanLocale && dropKo != null) { return '$translatedMonster $dropKo'; } else if (isJapaneseLocale && dropJa != null) { return '$translatedMonsterの$dropJa'; } } // 3. interestingItem 형식: "Attrib Special" (2단어) if (words.length == 2) { return translateInterestingItem(words[0], words[1]); } } // 4. 단일 단어 - boringItem 번역 시도 return translateBoringItem(itemString); } // ============================================================================ // 스토리/시네마틱 번역 함수 (Story/Cinematic Translation Functions) // ============================================================================ /// Act 제목 번역 String translateActTitle(String englishTitle) { if (isKoreanLocale) return actTitleTranslationsKo[englishTitle] ?? englishTitle; if (isJapaneseLocale) return actTitleTranslationsJa[englishTitle] ?? englishTitle; return englishTitle; } /// Act 보스 이름 번역 String translateActBoss(String englishBoss) { if (isKoreanLocale) return actBossTranslationsKo[englishBoss] ?? englishBoss; if (isJapaneseLocale) return actBossTranslationsJa[englishBoss] ?? englishBoss; return englishBoss; } /// Act 퀘스트 번역 String translateActQuest(String englishQuest) { if (isKoreanLocale) return actQuestTranslationsKo[englishQuest] ?? englishQuest; if (isJapaneseLocale) return actQuestTranslationsJa[englishQuest] ?? englishQuest; return englishQuest; } /// 시네마틱 텍스트 번역 String translateCinematic(String englishText) { if (isKoreanLocale) return cinematicTranslationsKo[englishText] ?? englishText; if (isJapaneseLocale) return cinematicTranslationsJa[englishText] ?? englishText; return englishText; } /// 지역 이름 번역 String translateLocation(String englishLocation) { if (isKoreanLocale) return locationTranslationsKo[englishLocation] ?? englishLocation; if (isJapaneseLocale) return locationTranslationsJa[englishLocation] ?? englishLocation; return englishLocation; } /// 세력/조직 이름 번역 String translateFaction(String englishFaction) { if (isKoreanLocale) return factionTranslationsKo[englishFaction] ?? englishFaction; if (isJapaneseLocale) return factionTranslationsJa[englishFaction] ?? englishFaction; return englishFaction; } /// 스킬/주문 이름 번역 (전투 로그용) String translateSpell(String englishName) { if (isKoreanLocale) { return spellTranslationsKo[englishName] ?? englishName; } if (isJapaneseLocale) { return spellTranslationsJa[englishName] ?? englishName; } return englishName; } // ============================================================================ // 프론트 화면 텍스트 // ============================================================================ String get uiHallOfFame => _l('Hall of Fame', '명예의 전당', '栄誉の殿堂'); String get uiLocalArena => _l('Local Arena', '로컬 아레나', 'ローカルアリーナ'); String get frontDescription => _l( 'A retro-style offline single-player RPG', '레트로 감성의 오프라인 싱글플레이어 RPG', 'レトロ感のあるオフラインシングルプレイヤーRPG', ); String get frontTodayFocus => _l("Today's focus", '오늘의 중점', '今日のフォーカス'); // ============================================================================ // 명예의 전당 화면 텍스트 // ============================================================================ String get hofNoHeroes => _l('No heroes yet', '영웅이 아직 없습니다', 'まだ英雄がいません'); String get hofDefeatGlitchGod => _l( 'Defeat the Glitch God to enshrine your legend!', '글리치 신을 처치하여 전설을 남기세요!', 'グリッチゴッドを倒して伝説を刻もう!', ); String get hofVictory => _l('VICTORY!', '승리!', '勝利!'); String get hofDefeatedGlitchGod => _l( 'You have defeated the Glitch God!', '글리치 신을 처치했습니다!', 'グリッチゴッドを倒しました!', ); String get hofLegendEnshrined => _l( 'Your legend has been enshrined in the Hall of Fame!', '당신의 전설이 명예의 전당에 기록되었습니다!', 'あなたの伝説が栄誉の殿堂に刻まれました!', ); String get hofViewHallOfFame => _l('View Hall of Fame', '명예의 전당 보기', '栄誉の殿堂を見る'); String get hofNewGame => _l('New Game', '새 게임', '新しいゲーム'); String get hofLevel => _l('Level', '레벨', 'レベル'); String get hofTime => _l('Time', '시간', '時間'); String get hofDeaths => _l('Deaths', '사망', '死亡'); String get hofQuests => _l('Quests', '퀘스트', 'クエスト'); String get hofStats => _l('Statistics', '통계', '統計'); String get hofMonsters => _l('Monsters', '몬스터', 'モンスター'); String get hofCleared => _l('Cleared', '클리어', 'クリア'); String get hofSkills => _l('Skills', '스킬', 'スキル'); String get hofNoSkills => _l('No Skills', '스킬 없음', 'スキルなし'); String get hofCombatStats => _l('Combat Stats', '전투 스탯', '戦闘ステータス'); String get hofCharacterPreview => _l('Character Preview', '캐릭터 미리보기', 'キャラクタープレビュー'); String get buttonClose => _l('Close', '닫기', '閉じる'); // Lv. 형식이 모든 언어에서 동일 String uiLevel(int level) => 'Lv.$level'; // ============================================================================ // 시네마틱 뷰 텍스트 // ============================================================================ String get uiSkip => _l('SKIP', '건너뛰기', 'スキップ'); // ============================================================================ // 게임 플레이 화면 텍스트 // ============================================================================ String get uiLevelUp => _l('Level Up!', '레벨 업!', 'レベルアップ!'); String uiQuestComplete(String questName) => _l('Quest Complete: $questName', '퀘스트 완료: $questName', 'クエスト完了: $questName'); // ============================================================================ // 장비 패널 텍스트 // ============================================================================ String get uiEquipmentScore => _l('Equipment Score', '장비 점수', '装備スコア'); String get uiEmpty => _l('(empty)', '(비어있음)', '(空)'); String uiWeight(int weight) => _l('Wt.$weight', '무게 $weight', '重量 $weight'); /// 남은 시간 표시 String uiTimeRemaining(String time) => _l('$time remaining', '$time 남음', '残り$time'); // 장비 슬롯 이름 String get slotWeapon => _l('Weapon', '무기', '武器'); String get slotShield => _l('Shield', '방패', '盾'); String get slotHelm => _l('Helm', '투구', '兜'); String get slotHauberk => _l('Hauberk', '갑옷', '鎧'); String get slotBrassairts => _l('Brassairts', '상완갑', '上腕甲'); String get slotVambraces => _l('Vambraces', '전완갑', '前腕甲'); String get slotGauntlets => _l('Gauntlets', '건틀릿', 'ガントレット'); String get slotGambeson => _l('Gambeson', '패딩', 'パッデッドアーマー'); String get slotCuisses => _l('Cuisses', '허벅지갑', '腿当て'); String get slotGreaves => _l('Greaves', '정강이갑', '脛当て'); String get slotSollerets => _l('Sollerets', '철제부츠', '鉄靴'); // 스탯 약어 (장비용) String get statAtk => _l('ATK', '공격', '攻撃'); String get statMAtk => _l('MATK', '마공', '魔攻'); String get statCri => _l('CRI', '치명', 'クリ'); String get statParry => _l('PARRY', '패리', 'パリィ'); String get statDef => _l('DEF', '방어', '防御'); String get statMDef => _l('MDEF', '마방', '魔防'); String get statBlock => _l('BLOCK', '블록', 'ブロック'); String get statEva => _l('EVA', '회피', '回避'); // HP/MP는 모든 언어에서 동일 String get statHp => 'HP'; String get statMp => 'MP'; String get statSpeed => _l('SPEED', '속도', '速度'); // ============================================================================ // 스킬 패널 텍스트 // ============================================================================ String get uiDot => _l('DOT', '지속', 'DOT'); // ============================================================================ // 아이템 희귀도 // ============================================================================ String get rarityCommon => _l('COMMON', '일반', 'コモン'); String get rarityUncommon => _l('UNCOMMON', '고급', 'アンコモン'); String get rarityRare => _l('RARE', '희귀', 'レア'); String get rarityEpic => _l('EPIC', '영웅', 'エピック'); String get rarityLegendary => _l('LEGENDARY', '전설', 'レジェンダリー'); // ============================================================================ // 캐릭터 생성 화면 텍스트 // ============================================================================ String uiRollHistory(int count) => _l('$count roll(s) in history', '리롤 기록: $count회', 'リロール履歴: $count回'); String get uiEnterName => _l( 'Please enter a name.', '이름을 입력해주세요.', '名前を入力してください。', ); String get uiTestMode => _l('Test Mode', '테스트 모드', 'テストモード'); String get uiTestModeDesc => _l( 'Use mobile layout on web', '웹에서 모바일 레이아웃 사용', 'Webでモバイルレイアウトを使用', ); // ============================================================================ // 캐로셀 네비게이션 텍스트 // ============================================================================ String get navSkills => _l('Skills', '스킬', 'スキル'); String get navInventory => _l('Inventory', '인벤토리', '所持品'); String get navEquipment => _l('Equip', '장비', '装備'); String get navCharacter => _l('Character', '캐릭터', 'キャラ'); String get navCombatLog => _l('Combat', '전투로그', '戦闘ログ'); String get navStory => _l('Story', '스토리', 'ストーリー'); String get navQuest => _l('Quest', '퀘스트', 'クエスト'); // ============================================================================ // 옵션 메뉴 텍스트 // ============================================================================ String get menuOptions => _l('Options', '옵션', 'オプション'); String get menuPause => _l('Pause', '일시정지', '一時停止'); String get menuResume => _l('Resume', '재개', '再開'); String get menuSpeed => _l('Speed', '속도', '速度'); String get menuSave => _l('Save', '저장', 'セーブ'); String get menuSaved => _l('Game saved', '저장되었습니다', '保存しました'); String get menuLanguage => _l('Language', '언어', '言語'); String get languageEnglish => _l('English', '영어', '英語'); String get languageKorean => _l('Korean', '한국어', '韓国語'); String get languageJapanese => _l('Japanese', '일본어', '日本語'); String get menuDeleteSave => _l('Delete Save', '세이브 삭제', 'セーブ削除'); String get menuNewGame => _l('New Game', '새로하기', '新規ゲーム'); String get confirmDeleteTitle => _l('Delete Save', '세이브 삭제', 'セーブ削除'); String get confirmDeleteMessage => _l( 'Are you sure?\nAll progress will be lost.', '정말 삭제하시겠습니까?\n모든 진행 상황이 사라집니다.', '本当に削除しますか?\nすべての進行状況が失われます。', ); String get buttonConfirm => _l('Confirm', '확인', '確認'); String get buttonCancel => _l('Cancel', '취소', 'キャンセル'); // ============================================================================ // 프론트 화면 경고/푸터 텍스트 // ============================================================================ String get uiWarning => _l('Warning', '경고', '警告'); String get warningDeleteSave => _l( 'Existing save file will be deleted. Continue?', '기존 저장 파일이 삭제됩니다. 계속하시겠습니까?', '既存のセーブファイルが削除されます。続行しますか?', ); // 카피라이트 텍스트는 언어에 따라 변하지 않음 String get copyrightText => '© 2025 NatureBridgeAi & cclabs all rights reserved'; // ============================================================================ // 테마 설정 텍스트 // ============================================================================ String get menuTheme => _l('Theme', '테마', 'テーマ'); String get themeLight => _l('Light', '라이트', 'ライト'); String get themeDark => _l('Dark', '다크', 'ダーク'); String get themeSystem => _l('System', '시스템', 'システム'); // ============================================================================ // 로딩 텍스트 // ============================================================================ String get uiLoading => _l('Loading...', '불러오는 중...', '読み込み中...'); // ============================================================================ // 설정 화면 텍스트 // ============================================================================ String get uiSettings => _l('Settings', '설정', '設定'); String get uiStatistics => _l('Statistics', '통계', '統計'); String get uiHelp => _l('Help', '도움말', 'ヘルプ'); String get uiTheme => _l('Theme', '테마', 'テーマ'); String get uiThemeLight => _l('Light', '라이트', 'ライト'); String get uiThemeDark => _l('Dark', '다크', 'ダーク'); String get uiThemeSystem => _l('System', '시스템', 'システム'); String get uiLanguage => _l('Language', '언어', '言語'); String get uiSound => _l('Sound', '사운드', 'サウンド'); String get uiBgmVolume => _l('BGM Volume', 'BGM 볼륨', 'BGM音量'); String get uiSfxVolume => _l('SFX Volume', '효과음 볼륨', '効果音音量'); String get uiSoundOff => _l('Muted', '음소거', 'ミュート'); String get uiAnimationSpeed => _l('Animation Speed', '애니메이션 속도', 'アニメーション速度'); String get uiSpeedSlow => _l('Slow', '느림', '遅い'); String get uiSpeedNormal => _l('Normal', '보통', '普通'); String get uiSpeedFast => _l('Fast', '빠름', '速い'); String get uiAbout => _l('About', '정보', '情報'); String get uiAboutDescription => _l( 'An offline single-player RPG with ASCII art and retro vibes.', 'ASCII 아트와 레트로 감성의 오프라인 싱글플레이어 RPG입니다.', 'ASCIIアートとレトロ感のあるオフラインシングルプレイヤーRPGです。', ); // ============================================================================ // 공통 UI 액션 텍스트 // ============================================================================ String get uiConfirm => _l('Confirm', '확인', '確認'); String get uiCancel => _l('Cancel', '취소', 'キャンセル'); String get uiDelete => _l('Delete', '삭제', '削除'); String get uiConfirmDelete => _l('Are you sure you want to delete?', '정말로 삭제하시겠습니까?', '本当に削除しますか?'); String get uiDeleted => _l('Deleted', '삭제되었습니다', '削除されました'); String get uiError => _l('An error occurred', '오류가 발생했습니다', 'エラーが発生しました'); String get uiSaved => _l('Saved', '저장됨', '保存しました'); String get uiSaveBattleLog => _l('Save Battle Log', '배틀로그 저장', 'バトルログ保存');