using System; using System.Collections.Generic; using System.Linq; using Crowdin.Plugin.Server_API.Helpers; using JetBrains.Annotations; using UnityEditor; using UnityEngine; namespace Crowdin.Plugin.Helpers { using Api; using Models; using Models.Translations; using Models.Translations.Items; using ScriptableObjects; public static class TranslationsHelper { private const string FileName = "CrowdinTranslations"; public const string FileFormat = "csv"; private static readonly string TranslationsPath = $"Crowdin/{FileName}"; private static readonly string FullTranslationsPath = $"{FolderHelper.resourcesDirectory}/{FileName}.asset"; private static CrowdinTranslations Translations { get; set; } static TranslationsHelper() { TryLoadTranslations(); if (Translations == null) { TryCreateTranslations(); TryLoadTranslations(); } } [CanBeNull] public static IEnumerable GetTranslationStrings() { return Translations.translationStrings; } public static IEnumerable GetTranslationStrings(string table) { var result = new List(); foreach (var translationString in Translations.translationStrings) { if (translationString.exportedFromTable == table) result.Add(translationString); } return result; } public static IEnumerable GetTranslationAssets() { return Translations.translationAssets; } public static void RefreshAllStringsTranslation() { Translations?.translationStrings?.Clear(); } public static void RefreshAllAssetsTranslations() { Translations?.translationAssets?.Clear(); } public static IEnumerable GetTranslationAssets(string table) { return Translations.translationAssets.Where(asset => asset.exportedFromTable == table); } [CanBeNull] public static TranslationString TryGetTranslationStringByKey(string key, string table) { var index = TryFindTranslationIndexByKey(key, table, TranslationType.Text); return index != -1 ? Translations.translationStrings[index] : null; } public static bool TryAddOrUpdateTranslation( IBaseCrowdinTranslation crowdinTranslation, bool? preserveEntryIds = null) { bool preserveIds = preserveEntryIds ?? SettingsHelper.GetToggleStatus_PreserveEntryIdsOnImport(); int index = preserveIds && crowdinTranslation.EntryId.HasValue ? TryFindTranslationIndexByEntryId( crowdinTranslation.EntryId.Value, crowdinTranslation.ExportedFrom, GetTranslationType(crowdinTranslation)) : TryFindTranslationIndexByKey( crowdinTranslation.Key, crowdinTranslation.ExportedFrom, GetTranslationType(crowdinTranslation)); return index == -1 ? AddTranslation(crowdinTranslation) : TryUpdateTranslations(index, crowdinTranslation); } private static TranslationType GetTranslationType(IBaseCrowdinTranslation crowdinTranslation) { switch (crowdinTranslation) { case IBaseCrowdinTranslation _: return TranslationType.Text; case IBaseCrowdinTranslation _: return TranslationType.AnyAsset; } return TranslationType.None; } private static void TryCreateTranslations() { var asset = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(asset, FullTranslationsPath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); } private static void TryLoadTranslations() { var translations = Resources.Load(TranslationsPath); if (translations is null) { TryCreateTranslations(); translations = Resources.Load(TranslationsPath); } Translations = translations; EditorUtility.SetDirty(translations); } private static int TryFindTranslationIndexByKey(string key, string table, TranslationType type) { switch (type) { case TranslationType.Text: return Translations.translationStrings? .FindIndex(str => str.key == key && str.exportedFromTable == table) ?? -1; case TranslationType.AnyAsset: return Translations.translationAssets?.FindIndex(asset => asset.key == key) ?? -1; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } private static int TryFindTranslationIndexByEntryId(long entryId, string table, TranslationType type) { switch (type) { case TranslationType.Text: return Translations.translationStrings? .FindIndex(@string => @string.entryId == entryId && @string.exportedFromTable == table) ?? -1; case TranslationType.AnyAsset: return Translations.translationAssets?.FindIndex(asset => asset.entryId == entryId) ?? -1; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } private static bool TryUpdateTranslations(int findIndex, IBaseCrowdinTranslation crowdinTranslation) { switch (crowdinTranslation) { case IBaseCrowdinTranslation textTranslation: { var findTxtTranslation = Translations.translationStrings[findIndex]; findTxtTranslation.exportedFromTable = textTranslation.ExportedFrom; if (crowdinTranslation is TranslationTextObj pulledTranslation) { findTxtTranslation.sourceString = pulledTranslation.SourceText; findTxtTranslation.context = pulledTranslation.Context; } foreach (var translation in textTranslation.Translations) { if (findTxtTranslation.translations == null) { findTxtTranslation.translations = new List(); } var findLangIndex = findTxtTranslation.translations.FindIndex( item => item.language == translation.language ); if (findLangIndex == -1) { findTxtTranslation.translations.Add(translation); } else if (!string.IsNullOrEmpty(translation.text)) { findTxtTranslation.translations[findLangIndex].text = translation.text; } } return true; } case IBaseCrowdinTranslation assetTranslation: { TranslationAsset asset = Translations.translationAssets[findIndex]; foreach (TranslationAssetItem translation in assetTranslation.Translations) { int findLangIndex = asset.translations .FindIndex(item => item.language == translation.language); if (findLangIndex is -1) { asset.translations.Add(translation); } else if (translation.asset != null) { asset.translations[findLangIndex].asset = translation.asset; } } return true; } } return false; } private static bool AddTranslation(IBaseCrowdinTranslation crowdinTranslation) { switch (crowdinTranslation) { case IBaseCrowdinTextTranslation textTranslation: { Translations.translationStrings = Translations.translationStrings ?? new List(); Translations.translationStrings.Add(new TranslationString { key = textTranslation.Key, entryId = textTranslation.EntryId.GetValueOrDefault(), sourceString = textTranslation.SourceText, context = textTranslation.Context, exportedFromTable = textTranslation.ExportedFrom, translations = textTranslation.Translations }); return true; } case IBaseCrowdinTranslation assetTranslation: { Translations.translationAssets.Add(new TranslationAsset { key = assetTranslation.Key, exportedFromTable = assetTranslation.ExportedFrom, translations = assetTranslation.Translations }); return true; } } return false; } } }