From a5572d8834601099689de48705f4df3c92ea20e3 Mon Sep 17 00:00:00 2001 From: t0stiman <18124323+t0stiman@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:03:25 +0100 Subject: [PATCH 1/5] fix "Failed to find locale language" warning --- Mapify/Locale.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mapify/Locale.cs b/Mapify/Locale.cs index 193a2c8..353bddc 100644 --- a/Mapify/Locale.cs +++ b/Mapify/Locale.cs @@ -48,8 +48,8 @@ public static string Get(string key) return MISSING_TRANSLATION; } + Mapify.LogWarning($"Failed to find locale language '{locale}', using default language '{DEFAULT_LANGUAGE}'"); locale = DEFAULT_LANGUAGE; - Mapify.LogWarning($"Failed to find locale language {locale}"); } Dictionary localeDict = csv[locale]; From 0960a6b56bc9fb323cf9d192c85235bed091625a Mon Sep 17 00:00:00 2001 From: t0stiman <18124323+t0stiman@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:23:12 +0100 Subject: [PATCH 2/5] easier debug logging --- Mapify/Mapify.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Mapify/Mapify.cs b/Mapify/Mapify.cs index 068ddac..ac5355f 100644 --- a/Mapify/Mapify.cs +++ b/Mapify/Mapify.cs @@ -43,7 +43,7 @@ private static bool Load(UnityModManager.ModEntry modEntry) private static void LoadLocale() { string localePath = Path.Combine(ModEntry.Path, LOCALE_FILE); - if (!Locale.Load(localePath)) + if (!Locale.LoadCSV(localePath)) LogError($"Failed to find locale file at {localePath}! Please make sure it's there."); } @@ -63,12 +63,22 @@ public static void LogDebugExtreme(Func resolver) LogDebug(resolver); } + public static void LogDebugExtreme(object msg) + { + LogDebugExtreme(() => msg); + } + public static void LogDebug(Func resolver) { if (Settings.VerboseLogging) ModEntry.Logger.Log($"[Debug] {resolver.Invoke()}"); } + public static void LogDebug(object msg) + { + LogDebug(() => msg); + } + public static void Log(object msg) { ModEntry.Logger.Log($"[Info] {msg}"); From 1d49bc162d960ee87f52d0a5686b211391c5be39 Mon Sep 17 00:00:00 2001 From: t0stiman <18124323+t0stiman@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:58:28 +0100 Subject: [PATCH 3/5] Add more languages --- locale.csv | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/locale.csv b/locale.csv index c080492..a564618 100644 --- a/locale.csv +++ b/locale.csv @@ -1,8 +1,13 @@ -Keys,Description,English -launcher/session_map,,Map: -session/map_selector,,Map -session/map_selector__tooltip,,Select a Map -launcher/map_selector__tooltip_disabled,, -loading/please_wait,,"loading{0}, please wait... {1}%" -loading/loading_map,,Loading map {0} -launcher/session_map_not_installed,,The map {0} isn't installed! Please install it before loading this save. +Keys,Description,English,Dutch,Chinese_Simplified,Chinese_Traditional,German,Italian,French,Russian,Hungarian,Spanish +launcher/session_map,,Map:,Kaart:,地图:,地圖:,Karte:,Mappa:,Carte:,карта,Térkép,Mapa: +session/map_selector,,Map,Kaart,地图,地圖,Karte,Mappa,Carte,выбор карты,Térkép,Mapa +session/map_selector__tooltip,,Select a Map,Kies een kaart,选择一张地图,選擇壹張地圖:,Wähle eine Karte,Seleziona una mappa,Selectionner une carte,,Válasszon ki egy térkép,Selecciona un mapa +launcher/map_selector__tooltip_disabled,,,,,,,,,,, +loading/please_wait,,"loading{0}, please wait... {1}%","laden{0}, even wachten aub... {1}%","加载中{0}, 请稍等...{1}%","加載中{0}, 請稍等...{1}%",Lädt {0} bitte warten ....{1}%,"caricamento{0}, attendere... {1}%","chargement{0}, veuillez patienter..{1}%","Загрузка{0}, пожалуйста подождите... {1}%","Betöltés{0}, kérem várjon... {1}%","cargando{0}, por favor espere... {1}%" +loading/loading_map,,Loading map {0},Kaart aan het laden: {0},"加载地图""{0}""中","加載地圖""{0}""中",Karte wird geladen... {0}%,Caricamento mappa {0},Chargement de la carte {0},Загрузка карты {0},Térkép betöltés{0},Cargando mapa {0} +launcher/session_map_not_installed,,The map {0} isn't installed! Please install it before loading this save.,De kaart {0} is niet geïnstalleerd! Installeer het a.u.b. voordat u dit opgeslagen spel laadt.,"""{0}""这张地图还没下载呢!请你在加载这个存档之前先下载它","""{0}""這張地圖還沒下載呢!請妳在加載這個存檔之前先下載它",Die Karte {0} ist nicht installiert! Bitte installieren Sie die Karte bevor Sie diesen Spielstand laden.,La mappa {0} non è installata! Per favore installala prima di caricare questo salvataggio.,La carte {0} n'est pas installée sur le système! Veuillez l'installer avant de charger cette sauvegarde. ,Карта не установлена. Установите карту прежде чем загружать сохранение.,A {0} térkép nincs telepítve!! Kérem telepítése mielőtt betőlti a játékot,"¡El mapa {0} no está instalado! Por favor, instálalo antes de cargar esta partida." +,,,,,,,,,,, +,,,,,,,,,,, +,,,,,,,,,,, +,,,,,,,,,,, +Translator:,,Insprill,Tostiman,我叫无聊 My Name Is BorING,我叫无聊 My Name Is BorING,kev & Coookie,tablesidecat02,"Corpet, Louvet & Cie",RaY,Dank_memey,The72 From d7cf1f76436bc251712e5de470cd02ad8ff6ff65 Mon Sep 17 00:00:00 2001 From: t0stiman <18124323+t0stiman@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:59:00 +0100 Subject: [PATCH 4/5] ignore empty lines in locale.csv --- Mapify/Utils/CSVParser.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mapify/Utils/CSVParser.cs b/Mapify/Utils/CSVParser.cs index 8df6da2..6056214 100644 --- a/Mapify/Utils/CSVParser.cs +++ b/Mapify/Utils/CSVParser.cs @@ -21,13 +21,16 @@ public static ReadOnlyDictionary> Parse(strin List keys = ParseLine(lines[0]); foreach (string key in keys) + { + if(key == "") continue; columns.Add(key, new Dictionary()); + } for (int i = 1; i < lines.Length; i++) { string line = lines[i]; List values = ParseLine(line); - if (values.Count == 0) + if (values.Count == 0 || values[0] == "") continue; string key = values[0]; for (int j = 0; j < values.Count; j++) From 1c46d035514c1bb15a61f317c05c0c01c90166b7 Mon Sep 17 00:00:00 2001 From: t0stiman <18124323+t0stiman@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:04:07 +0100 Subject: [PATCH 5/5] add ability to translate station names --- Mapify/Locale.cs | 82 +++++++++++++++++-- Mapify/Map/MapLifeCycle.cs | 8 +- Mapify/Mapify.cs | 13 +-- Mapify/Mapify.csproj | 2 +- .../GameContent/StationSetup.cs | 2 +- .../GameContent/WorldMapSetup.cs | 11 +-- Mapify/Utils/Extensions.cs | 10 +++ 7 files changed, 102 insertions(+), 26 deletions(-) diff --git a/Mapify/Locale.cs b/Mapify/Locale.cs index 353bddc..7d95499 100644 --- a/Mapify/Locale.cs +++ b/Mapify/Locale.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; +using System.Linq; using I2.Loc; using Mapify.Utils; @@ -9,42 +10,78 @@ namespace Mapify { public static class Locale { + private const string LOCALE_FILE = "locale.csv"; private const string DEFAULT_LANGUAGE = "English"; private const string MISSING_TRANSLATION = "[ MISSING TRANSLATION ]"; + public const string PREFIX = "mapify/"; + private static readonly char[] PREFIX_CHARS = PREFIX.ToCharArray(); + public const string STATION_PREFIX = PREFIX + "station/"; public const string SESSION__MAP_SELECTOR = PREFIX + "session/map_selector"; public const string LAUNCHER__SESSION_MAP = PREFIX + "launcher/session_map"; public const string LAUNCHER__SESSION_MAP_NOT_INSTALLED = PREFIX + "launcher/session_map_not_installed"; public const string LOADING__PLEASE_WAIT = PREFIX + "loading/please_wait"; public const string LOADING__LOADING_MAP = PREFIX + "loading/loading_map"; - private static readonly char[] PREFIX_CHARS = PREFIX.ToCharArray(); private static bool initializeAttempted; - private static ReadOnlyDictionary> csv; + private static ReadOnlyDictionary> mapifyTranslations; + private static bool mapSpecificTranslationsLoaded = false; + private static ReadOnlyDictionary> mapSpecificTranslations = new (new Dictionary>()); - public static bool Load(string localeFilePath) + public static bool LoadCSV(string modDir) { initializeAttempted = true; + var localeFilePath = Path.Combine(modDir, LOCALE_FILE); if (!File.Exists(localeFilePath)) + { + Mapify.LogError($"Failed to find locale file at {localeFilePath}! Please make sure it's there."); return false; - csv = CSV.Parse(File.ReadAllText(localeFilePath)); + } + + mapifyTranslations = CSV.Parse(File.ReadAllText(localeFilePath)); return true; } + public static void LoadMapCSV(string mapDir) + { + var localeFilePath = Path.Combine(mapDir, LOCALE_FILE); + if (!File.Exists(localeFilePath)) + { + Mapify.LogDebug(nameof(LoadMapCSV)+$" no map CSV at {localeFilePath}"); + return; + } + + mapSpecificTranslations = CSV.Parse(File.ReadAllText(localeFilePath)); + mapSpecificTranslationsLoaded = true; + + Mapify.LogDebug(nameof(LoadMapCSV)+$" loaded map CSV at {localeFilePath}"); + } + + public static void UnloadMapCSV() + { + mapSpecificTranslations = new (new Dictionary>()); + mapSpecificTranslationsLoaded = false; + } + public static string Get(string key) { if (!initializeAttempted) throw new InvalidOperationException("Not initialized"); + if (TryGetMapSpecificTranslation(key, out var translation)) + { + return translation; + } + string locale = LocalizationManager.CurrentLanguage; - if (!csv.ContainsKey(locale)) + if (!mapifyTranslations.ContainsKey(locale)) { if (locale == DEFAULT_LANGUAGE) { Mapify.LogError($"Failed to find locale language {locale}! Something is broken, this shouldn't happen. Dumping CSV data:"); - Mapify.LogError($"\n{CSV.Dump(csv)}"); + Mapify.LogError($"\n{CSV.Dump(mapifyTranslations)}"); return MISSING_TRANSLATION; } @@ -52,20 +89,47 @@ public static string Get(string key) locale = DEFAULT_LANGUAGE; } - Dictionary localeDict = csv[locale]; + Dictionary localeDict = mapifyTranslations[locale]; if (localeDict.TryGetValue(key.TrimStart(PREFIX_CHARS), out string value)) { return value; } // If there is no translation for this station's name, don't translate it. - if (key.StartsWith(STATION_PREFIX)) { - return key.Replace(STATION_PREFIX, "");; + if (key.StartsWith(STATION_PREFIX)) + { + var stationID = key.Replace(STATION_PREFIX, ""); + var stationName = StationController.allStations + .Select(stationController => stationController.stationInfo) + .Where(stationInfo => stationInfo.YardID == stationID) + .Select(stationInfo => stationInfo.Name) + .ToList() + .FirstOrDefault(); + return stationName; } return MISSING_TRANSLATION; } + public static bool TryGetMapSpecificTranslation(string key, out string translation) + { + translation = ""; + if (!mapSpecificTranslationsLoaded) return false; + + var locale = LocalizationManager.CurrentLanguage; + Mapify.LogDebug($"{nameof(TryGetMapSpecificTranslation)} key: '{key}' locale: '{locale}'"); + + if (!mapSpecificTranslations.ContainsKey(locale)) return false; + + var success = mapSpecificTranslations[locale].TryGetValue(key.TrimStart(PREFIX_CHARS), out translation); + success = success && translation != ""; + if (success) + { + Mapify.LogDebug($"translation: '{translation}'"); + } + return success; + } + public static string Get(string key, params object[] placeholders) { return string.Format(Get(key), placeholders); diff --git a/Mapify/Map/MapLifeCycle.cs b/Mapify/Map/MapLifeCycle.cs index 71bee18..297e502 100644 --- a/Mapify/Map/MapLifeCycle.cs +++ b/Mapify/Map/MapLifeCycle.cs @@ -50,8 +50,12 @@ public static IEnumerator LoadMap(BasicMapInfo basicMapInfo) loadingInfo.UpdateLoadingStatus(loadingMapLogMsg, 0); yield return null; - // Load asset bundles string mapDir = Maps.GetDirectory(basicMapInfo); + + // Register translations + Locale.LoadMapCSV(mapDir+"/../"); + + // Load asset bundles string[] assets_assetBundlePaths = Maps.GetMapAssets(Names.ASSETS_ASSET_BUNDLES_PREFIX+"*", mapDir); assets_assetBundles = new List(assets_assetBundlePaths.Length); @@ -269,6 +273,8 @@ private static void Cleanup() scenes = null; } + Locale.UnloadMapCSV(); + isMapLoaded = false; } } diff --git a/Mapify/Mapify.cs b/Mapify/Mapify.cs index ac5355f..0284e6a 100644 --- a/Mapify/Mapify.cs +++ b/Mapify/Mapify.cs @@ -13,7 +13,6 @@ public static class Mapify { private static UnityModManager.ModEntry ModEntry { get; set; } private static Settings Settings; - private const string LOCALE_FILE = "locale.csv"; internal static Harmony Harmony { get; private set; } @@ -27,7 +26,10 @@ private static bool Load(UnityModManager.ModEntry modEntry) try { - LoadLocale(); + if (!Locale.LoadCSV(ModEntry.Path)) + { + return false; + } Maps.Init(); Patch(); } @@ -40,13 +42,6 @@ private static bool Load(UnityModManager.ModEntry modEntry) return true; } - private static void LoadLocale() - { - string localePath = Path.Combine(ModEntry.Path, LOCALE_FILE); - if (!Locale.LoadCSV(localePath)) - LogError($"Failed to find locale file at {localePath}! Please make sure it's there."); - } - private static void Patch() { Log("Patching..."); diff --git a/Mapify/Mapify.csproj b/Mapify/Mapify.csproj index 350321b..155c128 100644 --- a/Mapify/Mapify.csproj +++ b/Mapify/Mapify.csproj @@ -2,7 +2,7 @@ net48 - 7.3 + 9 Mapify true diff --git a/Mapify/SceneInitializers/GameContent/StationSetup.cs b/Mapify/SceneInitializers/GameContent/StationSetup.cs index 5a6ede1..e2ab32c 100644 --- a/Mapify/SceneInitializers/GameContent/StationSetup.cs +++ b/Mapify/SceneInitializers/GameContent/StationSetup.cs @@ -32,7 +32,7 @@ public override void Run() StationController stationController = stationObject.GetComponent(); // Station info - stationController.stationInfo = new StationInfo(station.stationName, " ", station.stationID, station.color, Locale.STATION_PREFIX+station.stationName); + stationController.stationInfo = new StationInfo(station.stationName, " ", station.stationID, station.color, Locale.STATION_PREFIX+station.stationID); // Station tracks stationController.storageRailtracksGONames = station.storageTrackNames; diff --git a/Mapify/SceneInitializers/GameContent/WorldMapSetup.cs b/Mapify/SceneInitializers/GameContent/WorldMapSetup.cs index 0b436fc..c509a35 100644 --- a/Mapify/SceneInitializers/GameContent/WorldMapSetup.cs +++ b/Mapify/SceneInitializers/GameContent/WorldMapSetup.cs @@ -52,11 +52,12 @@ private static void UpdateMapOverview(Transform transform) name.FindChildByName("Color").GetComponent().color = station.color; name.FindChildByName("IndustryCode").GetComponent().text = station.stationID; name.FindChildByName("OriginalName").GetComponent().text = station.stationName; - GameObject localizedName = name.FindChildByName("LocalizedName"); - localizedName.GetComponent().text = station.stationName; - foreach (Localize i2Localize in localizedName.GetComponents()) + GameObject localizedNameObject = name.FindChildByName("LocalizedName"); + localizedNameObject.GetComponent().text = station.GetLocalizedStationName(); + + foreach (Localize i2Localize in localizedNameObject.GetComponents()) Object.DestroyImmediate(i2Localize); - Object.DestroyImmediate(localizedName.GetComponent()); + Object.DestroyImmediate(localizedNameObject.GetComponent()); } Object.Destroy(listItemPrefab.gameObject); @@ -117,7 +118,7 @@ private static void ShowNamesOnMap(Transform mapTransform) TMP_Text tmp = name.GetComponent(); tmp.rectTransform.localPosition = station.YardCenter.position.ToXZ().Scale(0, Maps.LoadedMap.worldSize, -0.175f, 0.175f); - tmp.text = ShowStationNamesOnMap ? station.stationName : station.stationID; + tmp.text = ShowStationNamesOnMap ? station.GetLocalizedStationName() : station.stationID; } Object.Destroy(namePrefab); diff --git a/Mapify/Utils/Extensions.cs b/Mapify/Utils/Extensions.cs index 4e7a1ed..da27415 100644 --- a/Mapify/Utils/Extensions.cs +++ b/Mapify/Utils/Extensions.cs @@ -232,6 +232,16 @@ public static GameObject Replace(this VanillaObject vanillaObject, bool active = return vanillaObject.gameObject.Replace(AssetCopier.Instantiate(vanillaObject.asset, active, originShift), preserveTypes, vanillaObject.keepChildren, vanillaObject.rotationOffset); } + public static string GetLocalizedStationName(this Station station) + { + if(Locale.TryGetMapSpecificTranslation(Locale.STATION_PREFIX+station.stationID, out var localizedName)) + { + return localizedName; + } + + return station.stationName; + } + #endregion } }