Files
AutoMorpherDecompiled/Assets/@Eden_Tools/Eden_AutoMorpher/LanguageManager/LanguageManager.cs
2026-02-01 14:24:15 +09:00

286 lines
9.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
namespace Eden.AutoMorpher
{
public enum Language
{
Korean = 0,
Japanese = 1,
English = 2,
}
[Serializable]
public class LocalizationEntry
{
public string key;
public string value;
}
[Serializable]
public class LocalizationFile
{
public LocalizationEntry[] entries;
}
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
public static class LanguageManager
{
private const string PREF_KEY_LANG = "EdenAutoMorpher_Language";
private const string PATH_KO = "Language/Language_ko";
private const string PATH_JA = "Language/Language_ja";
private const string PATH_EN = "Language/Language_en";
private static Language _currentLanguage = Language.Korean;
private static Dictionary<string, string> _koTable;
private static Dictionary<string, string> _jaTable;
private static Dictionary<string, string> _enTable;
public static Language CurrentLanguage
{
get => _currentLanguage;
set
{
if (_currentLanguage == value) return;
_currentLanguage = value;
#if UNITY_EDITOR
EditorPrefs.SetInt(PREF_KEY_LANG, (int)_currentLanguage);
#else
PlayerPrefs.SetInt(PREF_KEY_LANG, (int)_currentLanguage);
PlayerPrefs.Save();
#endif
}
}
static LanguageManager()
{
// Editor 시작 시 언어 로드
#if UNITY_EDITOR
int saved = EditorPrefs.GetInt(PREF_KEY_LANG, (int)Language.Korean);
#else
int saved = PlayerPrefs.GetInt(PREF_KEY_LANG, (int)Language.Korean);
#endif
_currentLanguage = (Language)Mathf.Clamp(saved, 0, 2);
}
/// <summary>
/// 현재 언어에서 문자열 가져오기.
/// key 없으면 fallback → 다른 언어 → 최종적으로 key 자체 반환.
/// </summary>
public static string Get(string key)
{
if (string.IsNullOrEmpty(key))
return string.Empty;
// 현재 언어 테이블에서 먼저 검색
if (TryGetFromCurrentLanguage(key, out string value))
return value;
return FormatKeyNotFound(key);
}
/// <summary>
/// 언어별로 다른 키를 쓰고 싶을 때 (번호 기반 등)도 가능하도록
/// 번호를 바로 key 문자열로 변환해서 사용하는 버전.
/// </summary>
public static string GetById(int id)
{
// 예: "ID.1001" 이런 식으로 통일하면 관리가 편함
string key = $"ID.{id}";
return Get(key);
}
public static void SetLanguage(Language lang)
{
CurrentLanguage = lang;
}
// ================== 내부 구현 ==================
private static bool TryGetFromCurrentLanguage(string key, out string value)
{
var table = GetTable(_currentLanguage);
if (table != null && table.TryGetValue(key, out value))
return true;
value = null;
return false;
}
private static bool TryGetFromOtherLanguages(string key, out string value)
{
// 현재 언어 제외한 나머지 순회
foreach (Language lang in System.Enum.GetValues(typeof(Language)))
{
if (lang == _currentLanguage)
continue;
var table = GetTable(lang);
if (table != null && table.TryGetValue(key, out value))
return true;
}
value = null;
return false;
}
private static Dictionary<string, string> GetTable(Language lang)
{
switch (lang)
{
case Language.Korean:
if (_koTable == null)
_koTable = LoadTable(PATH_KO);
return _koTable;
case Language.Japanese:
if (_jaTable == null)
_jaTable = LoadTable(PATH_JA);
return _jaTable;
case Language.English:
if (_enTable == null)
_enTable = LoadTable(PATH_EN);
return _enTable;
default:
return null;
}
}
// fileName: "lang_ko", "lang_ja", "lang_en" 처럼 사용
private static Dictionary<string, string> LoadTable(string fileName)
{
var dict = new Dictionary<string, string>();
#if UNITY_EDITOR
// 스크립트 기준 Language 폴더 아래의 json 경로
string assetPath = GetLanguageJsonAssetPath(fileName);
// Assets/... 형식 경로를 실제 디스크 경로로 변환
string fullPath = Path.GetFullPath(assetPath);
if (!File.Exists(fullPath))
{
Debug.LogWarning($"[AutoMorpherLanguage] Localization file not found: {fullPath}");
return dict;
}
string jsonText;
try
{
// ✅ 강제로 UTF-8 로 읽기 (BOM 유무 상관 없음)
jsonText = File.ReadAllText(fullPath, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
}
catch (System.Exception ex)
{
Debug.LogError($"[AutoMorpherLanguage] Failed to read localization file: {fullPath}\n{ex}");
return dict;
}
try
{
var file = JsonUtility.FromJson<LocalizationFile>(jsonText);
if (file?.entries != null)
{
foreach (var entry in file.entries)
{
if (string.IsNullOrEmpty(entry.key))
continue;
dict[entry.key] = entry.value ?? string.Empty;
}
}
}
catch (System.Exception ex)
{
Debug.LogError($"[AutoMorpherLanguage] Failed to parse localization file: {fullPath}\n{ex}");
}
#else
// 런타임 빌드에서 쓸 계획이 없으면 비워둬도 됨
#endif
return dict;
}
private static string FormatKeyNotFound(string key)
{
// 먼저 현재 언어의 "Error.KeyNotFound" 가져오기
if (TryGetFromCurrentLanguage("Error.KeyNotFound", out string template))
return template.Replace("{0}", key);
// JSON 자체가 없어서 템플릿도 없는 경우 (최후 fallback)
switch (CurrentLanguage)
{
case Language.Korean:
return $"[KO] 해당 키를 찾을 수 없습니다: {key}";
case Language.Japanese:
return $"[JP] キーが見つかりません: {key}";
default:
return $"[EN] Could not find key: {key}";
}
}
public static string GetLanguageFolderPath()
{
string scriptDir = "Assets\\@Eden_Tools\\Eden_AutoMorpher\\LanguageManager\\Language";
#if UNITY_EDITOR
// AutoMorpherLanguage 스크립트의 GUID 찾기
string[] guids = AssetDatabase.FindAssets("LanguageManager t:MonoScript");
if (guids == null || guids.Length == 0)
{
Debug.LogError("[LanguageManager] Could not find LanguageManager.cs script.");
return "Assets"; // 최소 fallback
}
string scriptPath = AssetDatabase.GUIDToAssetPath(guids[0]); // 예: Assets/@Eden_Tools/.../AutoMorpherLanguage.cs
scriptDir = Path.GetDirectoryName(scriptPath); // 그 폴더
// 폴더가 없으면 에디터에서 자동 생성
if (!Directory.Exists(scriptDir))
{
Directory.CreateDirectory(scriptDir);
AssetDatabase.Refresh();
}
#endif
// Unity Asset 경로 포맷으로 정리
scriptDir = scriptDir.Replace("\\", "/");
return scriptDir;
}
public static string GetLanguageJsonAssetPath(string fileNameWithoutExt)
{
string folder = GetLanguageFolderPath();
string path = Path.Combine(folder, fileNameWithoutExt + ".json");
return path.Replace("\\", "/");
}
public static string GetFormat(string key, params object[] args)
{
string raw = Get(key);
if (string.IsNullOrEmpty(raw))
return string.Empty;
try
{
return string.Format(raw, args);
}
catch (Exception ex)
{
Debug.LogError($"[LanguageManager] Format failed for key: {key}\n{ex}");
return raw; // 최소한 원문이라도 보여주기
}
}
}
}