using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using AibisDream.Framework; using AibisDream.Kit; using AibisDream.Utility; using NUnit.Framework; using UnityEditor; using UnityEngine; using YarnProjectDefinition = Yarn.Compiler.Project; namespace AibisDream.SystemEditor.Tests { public sealed class LocalizationExpansionTests { private const string FirstRuntimeChapterPath = "Assets/ScriptableObjects/SceneSO/Demo/Day0_Prologue.asset"; private static readonly string[] AddedLocaleCodes = { "ru", "es", "pt-BR" }; private static readonly MethodInfo GetLocalizedNameMethod = typeof(CharacterVo).GetMethod( "GetLocalizedNameByKind", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo GetCharacterVoByKeyMethod = typeof(YarnUtil).GetMethod( "GetCharacterVoByKey", BindingFlags.Static | BindingFlags.NonPublic); [TestCase("ru", LocaleKind.Ru)] [TestCase("ru-RU", LocaleKind.Ru)] [TestCase("es", LocaleKind.Es)] [TestCase("es-ES", LocaleKind.Es)] [TestCase("pt", LocaleKind.PtBr)] [TestCase("pt-BR", LocaleKind.PtBr)] public void GetLocaleKind_AddedLocaleCode_ReturnsExpectedKind( string localeCode, LocaleKind expected) { Assert.That(LocalizationKit.GetLocaleKind(localeCode), Is.EqualTo(expected)); } [TestCase(SystemLanguage.Russian, "ru")] [TestCase(SystemLanguage.Spanish, "es")] [TestCase(SystemLanguage.Portuguese, "pt-BR")] public void MapSystemLanguage_AddedSystemLanguage_ReturnsSupportedLocale( SystemLanguage systemLanguage, string expected) { Assert.That(LocalizationKit.MapSystemLanguage(systemLanguage), Is.EqualTo(expected)); } [Test] public void CharacterVo_LocalizedName_ReturnsOnlySelectedLocaleContent() { Assert.That(GetLocalizedNameMethod, Is.Not.Null); var translated = new CharacterVo { key = "actor_key", ru = "Русское имя", es = "Nombre español", ptBr = "Nome português", }; Assert.That(GetLocalizedName(translated, LocaleKind.Ru), Is.EqualTo(translated.ru)); Assert.That(GetLocalizedName(translated, LocaleKind.Es), Is.EqualTo(translated.es)); Assert.That(GetLocalizedName(translated, LocaleKind.PtBr), Is.EqualTo(translated.ptBr)); var untranslated = new CharacterVo { key = "actor_key" }; Assert.That(GetLocalizedName(untranslated, LocaleKind.Cn), Is.Null); Assert.That(GetLocalizedName(untranslated, LocaleKind.En), Is.Null); Assert.That(GetLocalizedName(untranslated, LocaleKind.Ja), Is.Null); Assert.That(GetLocalizedName(untranslated, LocaleKind.Ru), Is.Null); Assert.That(GetLocalizedName(untranslated, LocaleKind.Es), Is.Null); Assert.That(GetLocalizedName(untranslated, LocaleKind.PtBr), Is.Null); } [Test] public void CharacterCsv_AddedLocaleColumns_ParseSuccessfully() { string csvPath = Path.Combine( Application.streamingAssetsPath, "Config", "character.csv"); List characters = CsvUtil.ReadAsBean(csvPath); Assert.That(characters, Is.Not.Empty); Character peipei = characters.Single(character => character.Key == "peipei"); Assert.That(peipei.Ru, Is.Empty); Assert.That(peipei.Es, Is.Empty); Assert.That(peipei.PtBr, Is.Empty); } [Test] public void RuntimeYarnProjects_DeclareAddedLocales() { TalkSceneSO firstChapter = AssetDatabase.LoadAssetAtPath(FirstRuntimeChapterPath); Assert.That(firstChapter, Is.Not.Null); var pending = new Queue(); var visited = new HashSet(); pending.Enqueue(firstChapter); while (pending.Count > 0) { TalkSceneSO chapter = pending.Dequeue(); if (chapter == null || !visited.Add(chapter)) continue; Assert.That(chapter.yarnProject, Is.Not.Null, chapter.name); AssertYarnProjectDeclaresAddedLocales(chapter); if (chapter.exits == null) continue; foreach (SceneExit sceneExit in chapter.exits) { if (sceneExit?.targetScene != null) pending.Enqueue(sceneExit.targetScene); } } Assert.That(visited, Is.Not.Empty); } private static string GetLocalizedName(CharacterVo character, LocaleKind localeKind) { return (string)GetLocalizedNameMethod.Invoke(character, new object[] { localeKind }); } private static void AssertYarnProjectDeclaresAddedLocales(TalkSceneSO chapter) { string assetPath = AssetDatabase.GetAssetPath(chapter.yarnProject); string projectRoot = Directory.GetParent(Application.dataPath).FullName; string absolutePath = Path.GetFullPath(Path.Combine(projectRoot, assetPath)); YarnProjectDefinition project = YarnProjectDefinition.LoadFromFile(absolutePath); foreach (string localeCode in AddedLocaleCodes) { Assert.That( project.Localisation.ContainsKey(localeCode), Is.True, $"{chapter.name} ({assetPath}) does not declare Locale {localeCode}."); } } } }