286 lines
9.1 KiB
C#
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; // 최소한 원문이라도 보여주기
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|