public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                         EventInfo.Param param)
        {
            var key = TextResourceHelper.GetSpecializedKey(param, param.Name);

            if (string.IsNullOrEmpty(key))
            {
                return(false);
            }
            var result = false;

            if (cache.TryGetTranslation(key, true, out var translated))
            {
                param.Name = translated;
                TrackReplacement(calculatedModificationPath, key, translated);
                TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                result = true;
            }
            else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                     LanguageHelper.IsTranslatable(key))
            {
                cache.AddTranslationToCache(key, !string.IsNullOrEmpty(param.Name) ? param.Name : string.Empty);
            }

            return(result);
        }
Beispiel #2
0
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref ExcelData asset, IAssetOrResourceLoadedContext context)
        {
            var cache = new SimpleTextTranslationCache(calculatedModificationPath, true, true, false);

            foreach (var param in asset.list)
            {
                for (int i = 0; i < param.list.Count; i++)
                {
                    var key = param.list[i];
                    if (!string.IsNullOrEmpty(key))
                    {
                        if (cache.TryGetTranslation(key, true, out var translated))
                        {
                            param.list[i] = translated;
                        }
                        else if (IsDumpingEnabled && LanguageHelper.IsTranslatable(key))
                        {
                            cache.AddTranslationToCache(key, key);
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #3
0
        private bool TryRegisterTranslation(SimpleTextTranslationCache cache, ScenarioData.Param param, int i,
                                            string calculatedModificationPath)
        {
            var key = TextResourceHelper.GetSpecializedKey(param, i, out var value);

            if (!string.IsNullOrEmpty(key))
            {
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    var result = TextResourceHelper.GetSpecializedTranslation(param, i, translated);
                    TranslationHelper.RegisterRedirectedResourceTextToPath(result, calculatedModificationPath);
                    param.Args[i] = result;
                    Logger.DebugLogDebug($"{GetType()} handled {calculatedModificationPath}");
                    return(true);
                }

                if (LanguageHelper.IsTranslatable(key))
                {
                    TranslationHelper.RegisterRedirectedResourceTextToPath(key, calculatedModificationPath);
                    if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                    {
                        cache.AddTranslationToCache(key, value);
                    }
                }
            }

            return(false);
        }
Beispiel #4
0
        public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                         VoiceInfo.Param param)
        {
            var result = false;
            var key    = param.Personality;

            if (string.IsNullOrEmpty(key))
            {
                return(false);
            }
            if (cache.TryGetTranslation(key, true, out var translated))
            {
                _personalityById[param.No] = translated;
                _personalityByName[key]    = translated;
                TrackReplacement(calculatedModificationPath, key, translated);
                TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                result = true;
            }
            else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                     LanguageHelper.IsTranslatable(key))
            {
                cache.AddTranslationToCache(key, string.Empty);
            }

            return(result);
        }
        private TextAndEncoding Translate(SimpleTextTranslationCache cache, ref TextAsset textAsset)
        {
            string TranslateCell(string cellText)
            {
                if (cache.TryGetTranslation(cellText, false, out string newText))
                {
                    return(newText);
                }
                else
                {
                    if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                    {
                        if (!string.IsNullOrEmpty(cellText) && LanguageHelper.IsTranslatable(cellText))
                        {
                            cache.AddTranslationToCache(cellText, cellText);
                        }
                    }
                }
                return(null);
            }

            string result = textAssetHelper.ProcessTable(textAsset, TranslateCell, out TextAssetHelper.TableResult tableResult);

            //Logger.Log( BepinLogLevel.Debug, $"{this.GetType()}: {tableResult.RowsUpdated}/{tableResult.Rows} rows updated" );
            if (tableResult.RowsUpdated > 0)
            {
                return(new TextAndEncoding(result, Encoding.UTF8));
            }

            return(null);
        }
        public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                         TitleSkillName.Param param)
        {
            var result = false;
            var key    = param.name0;

            if (string.IsNullOrEmpty(key))
            {
                return(false);
            }
            if (cache.TryGetTranslation(key, true, out var translated))
            {
                param.name0 = translated;
                TrackReplacement(calculatedModificationPath, key, translated);
                TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                result = true;
            }
            else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                     LanguageHelper.IsTranslatable(key))
            {
                cache.AddTranslationToCache(key, !string.IsNullOrEmpty(param.name1) ? param.name1 : key);
            }

            return(result);
        }
 private void GameSpecificReplaceOrUpdateAsset(string calculatedModificationPath, ref MapInfo asset, IAssetOrResourceLoadedContext context, SimpleTextTranslationCache cache, bool shouldTrack)
 {
     foreach (var key in asset.param.Select(GetMapDisplayName).Where(k => !string.IsNullOrEmpty(k)))
     {
         if (cache.TryGetTranslation(key, true, out var translated))
         {
             if (string.IsNullOrEmpty(translated))
             {
                 continue;
             }
             _displayNameLookup[key] = translated;
             _reverseDisplayNameLookup[translated] = key;
             if (shouldTrack)
             {
                 TrackReplacement(calculatedModificationPath, key, translated);
             }
             TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
         }
         else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                  !string.IsNullOrEmpty(key) && LanguageHelper.IsTranslatable(key))
         {
             cache.AddTranslationToCache(key, key);
         }
     }
 }
Beispiel #8
0
        public override bool TranslateObject(ref ChaListData obj, SimpleTextTranslationCache cache,
                                             string calculatedModificationPath)
        {
            var idx = obj.lstKey.IndexOf("Name");

            if (idx == -1)
            {
                return(false);
            }
            var result      = false;
            var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

            foreach (var entry in obj.dictList.Values)
            {
                if (entry.Count <= idx || !cache.TryGetTranslation(entry[idx], true, out var translation))
                {
                    continue;
                }

                if (shouldTrack)
                {
                    TrackReplacement(calculatedModificationPath, entry[idx], translation);
                }
                TranslationHelper.RegisterRedirectedResourceTextToPath(translation, calculatedModificationPath);
                result     = true;
                entry[idx] = translation;
            }

            return(result);
        }
Beispiel #9
0
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref ScenarioData asset, IAssetOrResourceLoadedContext context)
        {
            var cache = new SimpleTextTranslationCache(calculatedModificationPath, true);

            foreach (var param in asset.list)
            {
                if (param.Command == Command.Text)
                {
                    for (int i = 0; i < param.Args.Length; i++)
                    {
                        var key = param.Args[i];
                        if (!key.IsNullOrWhiteSpace())
                        {
                            if (cache.TryGetTranslation(key, true, out var translated))
                            {
                                param.Args[i] = translated;
                            }
                            else if (IsDumpingEnabled && LanguageHelper.IsTranslatable(key))
                            {
                                cache.AddTranslationToCache(key, key);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #10
0
        private bool TryGetTranslation(string input, out string translatedText)
        {
            translatedText = string.Empty;
            if (_currentTranslationCache == null)
            {
                return(false);
            }

            string fallback   = null;
            var    cleanInput = _whitespaceRemover.Replace(input, string.Empty);

            foreach (var scope in GetSearchScopes())
            {
                if (!AutoTranslator.Default.TryTranslate(input, scope, out var result))
                {
                    Logger.DebugLogDebug($"{nameof(TryGetTranslation)}: No result for {input} in scope {scope}");
                    continue;
                }

                Logger.DebugLogDebug($"{nameof(TryGetTranslation)}: {input} => {result} (scope: {scope})");
                // skip if it's just whitespace, caused by some splitters
                if (cleanInput == _whitespaceRemover.Replace(result, string.Empty))
                {
                    continue;
                }

                // keep incomplete translation for last resort
                if (!result.IsRedirected() && LanguageHelper.IsTranslatable(result))
                {
                    Logger.DebugLogDebug(
                        $"{nameof(TryGetTranslation)}: {input} => {result} (scope: {scope}): partial translation");
                    if (string.IsNullOrEmpty(fallback))
                    {
                        fallback = result;
                    }
                    continue;
                }

                // skip any translations that match what's in the auto translation cache (unedited MTL)
                if (_currentTranslationCache.TryGetTranslation(input, true, out var mtlTranslation) &&
                    mtlTranslation == result)
                {
                    Logger.DebugLogDebug(
                        $"{nameof(TryGetTranslation)}: {input} => {result} (scope: {scope}): discarding as it's in auto-cache");
                    continue;
                }

                Logger.DebugLogDebug($"{nameof(TryGetTranslation)}: {input} => {result} (scope: {scope}): accepted");
                translatedText = result;
                return(true);
            }

            if (string.IsNullOrEmpty(fallback))
            {
                return(false);
            }
            Logger.DebugLogDebug($"{nameof(TryGetTranslation)}: {input} => {fallback}: accepting fallback");
            translatedText = fallback;
            return(true);
        }
Beispiel #11
0
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref ScenarioData asset, IAssetOrResourceLoadedContext context)
        {
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                outputFile: defaultTranslationFile,
                inputStreams: streams,
                allowTranslationOverride: false,
                closeStreams: true);

            foreach (var param in asset.list)
            {
                if (param.Command == Command.Text)
                {
                    for (int i = 0; i < param.Args.Length; i++)
                    {
                        var key = param.Args[i];
                        if (!string.IsNullOrEmpty(key))
                        {
                            if (cache.TryGetTranslation(key, true, out var translated))
                            {
                                param.Args[i] = translated;
                            }
                            else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled && LanguageHelper.IsTranslatable(key))
                            {
                                cache.AddTranslationToCache(key, key);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #12
0
        public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                         EventInfo.Param param)
        {
            var result  = false;
            var origKey = param.Name;

            foreach (var key in TextResourceHelper.GetTranslationKeys(param, origKey))
            {
                if (string.IsNullOrEmpty(key))
                {
                    continue;
                }

                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    param.Name = translated;
                    TrackReplacement(calculatedModificationPath, origKey, translated);
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                    result = true;
                    break;
                }

                if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                    LanguageHelper.IsTranslatable(origKey))
                {
                    cache.AddTranslationToCache(key, !string.IsNullOrEmpty(param.Name) ? param.Name : string.Empty);
                }
            }

            return(result);
        }
        private bool UpdateClipData(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                    Param param, ClipData clipData)
        {
            var key    = clipData.name;
            var result = false;

            if (string.IsNullOrEmpty(key))
            {
                return(false);
            }
            if (cache.TryGetTranslation(key, true, out var translated))
            {
                clipData.name = translated;
                TrackReplacement(calculatedModificationPath, key, translated);
                TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                result = true;
            }
            else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                     LanguageHelper.IsTranslatable(key))
            {
                DefaultDumpParam(cache, param, clipData, clipData.name);
            }

            return(result);
        }
Beispiel #14
0
        protected virtual bool UpdateParamField(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                                ref string[] field, string prefix = null)
        {
            var rawKey = field[0];

            if (string.IsNullOrEmpty(rawKey))
            {
                return(false);
            }

            var keys = new List <string>();

            if (!string.IsNullOrEmpty(prefix))
            {
                keys.Add($"{prefix}{field[0]}");
            }
            keys.Add(field[0]);

            var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

            foreach (var key in keys)
            {
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    field[0] = translated;
                    if (shouldTrack)
                    {
                        TrackReplacement(calculatedModificationPath, rawKey, translated);
                    }
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                    return(true);
                }

                if (EnableInternalAssetTranslation.Value && TranslatedIndex > 0 && field.Length > TranslatedIndex)
                {
                    var possible = field[TranslatedIndex];
                    if (Plugin.TextResourceHelper.IsValidStringArrayParamAssetTranslation(key, possible))
                    {
                        field[0] = possible;
                        if (shouldTrack)
                        {
                            TrackReplacement(calculatedModificationPath, rawKey, possible);
                        }
                        TranslationHelper.RegisterRedirectedResourceTextToPath(possible,
                                                                               calculatedModificationPath + " (original asset)");
                        return(true);
                    }
                }

                if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                    LanguageHelper.IsTranslatable(key))
                {
                    DumpParamField(cache, field);
                }
            }

            return(false);
        }
        /// <summary>
        ///     Caches forward and reverse translation of assets as they're loaded, but does not apply them.
        ///     to avoid breaking code that relies on original names being present.
        /// </summary>
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref MapInfo asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            // updating the MapInfo assets directly breaks places that are doing lookups by mapName
            // instead of id, so we just register this as a place to lookup MapInfo translations and
            // return true so it appears handled
            Hooks.Init();

            // register new translations with helper without replacing
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty)
            {
                return(true);
            }

            var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

            // register with helper or dump without translating here
            foreach (var key in asset.param
                     .Select(entry => TextResourceHelper.GetSpecializedKey(entry, GetMapName(entry)))
                     .Where(k => !string.IsNullOrEmpty(k)))
            {
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    if (string.IsNullOrEmpty(translated))
                    {
                        continue;
                    }
                    _mapLookup[key] = translated;
                    _reverseMapLookup[translated] = key;
                    if (shouldTrack)
                    {
                        TrackReplacement(calculatedModificationPath, key, translated);
                    }
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                         !string.IsNullOrEmpty(key) && LanguageHelper.IsTranslatable(key))
                {
                    cache.AddTranslationToCache(key, key);
                }
            }

            return(true);
        }
        private bool TryRegisterTranslation(SimpleTextTranslationCache cache, ScenarioData.Param param, int i)
        {
            var key = textResourceHelper.GetSpecializedKey(param, i, out string value);

            if (!string.IsNullOrEmpty(key))
            {
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    param.Args[i] = textResourceHelper.GetSpecializedTranslation(param, i, translated);
                    return(true);
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled && LanguageHelper.IsTranslatable(key))
                {
                    cache.AddTranslationToCache(key, value);
                }
            }
            return(false);
        }
        public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                         VoiceAllData.Param param)
        {
            var result = false;

            foreach (var voiceData in param.data)
            {
                foreach (var voiceInfo in voiceData.info)
                {
                    if (string.IsNullOrEmpty(voiceInfo.word))
                    {
                        continue;
                    }
                    if (ApplyLastMatch(calculatedModificationPath, voiceInfo))
                    {
                        result = true;
                        continue;
                    }

                    if (cache.TryGetTranslation(voiceInfo.word, true, out var translated))
                    {
                        SaveLastMatch(calculatedModificationPath, voiceInfo.word, translated);
                        voiceInfo.word = translated;

                        // H & Free-H scopes
                        TrackReplacement(calculatedModificationPath, voiceInfo.word, translated, 8, 9, -1);
                        TranslationHelper.RegisterRedirectedResourceTextToPath(translated,
                                                                               calculatedModificationPath);
                        result = true;
                    }
                    else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                             LanguageHelper.IsTranslatable(voiceInfo.word))
                    {
                        DefaultDumpParam(cache, param, voiceInfo, voiceInfo.word);
                    }
                }
            }

            return(result);
        }
        protected virtual bool DefaultUpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache,
                                                  TParam param, string key, ApplyParamTranslation applyParamTranslation)
        {
            if (string.IsNullOrEmpty(key))
            {
                return(false);
            }
            if (cache.TryGetTranslation(key, true, out var translated))
            {
                ApplyTranslationToParam(applyParamTranslation, calculatedModificationPath, param, translated);
                TrackReplacement(calculatedModificationPath, key, translated);
                TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                return(true);
            }

            if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                LanguageHelper.IsTranslatable(key))
            {
                DefaultDumpParam(cache, param, key);
            }

            return(false);
        }
Beispiel #19
0
        public virtual bool TryRegisterScenarioTranslation(SimpleTextTranslationCache cache, ScenarioData.Param param, int i,
                                                           string calculatedModificationPath)
        {
            var origKey = param.Args.SafeGet(i);

            if (origKey.IsNullOrEmpty())
            {
                return(false);
            }
            foreach (var key in GetTranslationKeys(param, i))
            {
                if (string.IsNullOrEmpty(key))
                {
                    return(false);
                }
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    var result = GetSpecializedTranslation(param, i, translated);
                    TranslationHelper.RegisterRedirectedResourceTextToPath(result, calculatedModificationPath);
                    param.Args[i] = result;
                    Logger.DebugLogDebug("{0} handled {1}", GetType(), calculatedModificationPath);
                    return(true);
                }

                if (!LanguageHelper.IsTranslatable(origKey))
                {
                    return(false);
                }
                TranslationHelper.RegisterRedirectedResourceTextToPath(key, calculatedModificationPath);
                if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                {
                    cache.AddTranslationToCache(key, key);
                }
            }

            return(false);
        }
Beispiel #20
0
        protected virtual bool ChaListDataTranslate(ref ChaListData chaListData, SimpleTextTranslationCache cache,
                                                    string calculatedModificationPath)
        {
            var idx    = chaListData.lstKey.IndexOf("Name");
            var result = false;

            if (idx == -1)
            {
                return(result);
            }
            foreach (var entry in chaListData.dictList.Values)
            {
                if (entry.Count <= idx || !cache.TryGetTranslation(entry[idx], true, out var translation))
                {
                    continue;
                }

                TranslationHelper.RegisterRedirectedResourceTextToPath(translation, calculatedModificationPath);
                result     = true;
                entry[idx] = translation;
            }

            return(result);
        }
        public override bool UpdateParam(string calculatedModificationPath, SimpleTextTranslationCache cache, EstheticVoiceInfo.Param param)
        {
            var result = false;

            foreach (var voiceAsset in param.voiceAssets)
            {
                if (string.IsNullOrEmpty(voiceAsset.voice))
                {
                    continue;
                }
                if (ApplyLastMatch(calculatedModificationPath, voiceAsset))
                {
                    result = true;
                    continue;
                }

                if (cache.TryGetTranslation(voiceAsset.voice, true, out var translated))
                {
                    SaveLastMatch(calculatedModificationPath, voiceAsset.voice, translated);
                    voiceAsset.voice = translated;

                    // Esthetic Scene
                    TrackReplacement(calculatedModificationPath, voiceAsset.voice, translated, 13, -1);
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated,
                                                                           calculatedModificationPath);
                    result = true;
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                         LanguageHelper.IsTranslatable(voiceAsset.voice))
                {
                    DefaultDumpParam(cache, param, voiceAsset, voiceAsset.voice);
                }
            }

            return(result);
        }
Beispiel #22
0
        public override TextAndEncoding TranslateTextAsset(string calculatedModificationPath, TextAsset asset,
                                                           IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()} attempt to handle {calculatedModificationPath}");
            if (!Enabled || !TextAssetTableHelper.IsTable(asset))
            {
                Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath}");
                return(null);
            }

            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty)
            {
                Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath} (no cache)");
                return(null);
            }

            GetTableRules(calculatedModificationPath, asset, context, out var rowAllowed, out var colAllowed);


            bool DoTranslation(int rowIndex, int colIndex, string cellText, out string newCellText)
            {
                newCellText = null;
                if (rowAllowed != null && !rowAllowed(rowIndex) || colAllowed != null && !colAllowed(colIndex))
                {
                    return(false);
                }

                if (cache.TryGetTranslation(cellText, false, out newCellText))
                {
                    TranslationHelper.RegisterRedirectedResourceTextToPath(newCellText, calculatedModificationPath);
                    return(true);
                }


                if (string.IsNullOrEmpty(cellText) || !LanguageHelper.IsTranslatable(cellText))
                {
                    return(false);
                }

                TranslationHelper.RegisterRedirectedResourceTextToPath(cellText, calculatedModificationPath);
                if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                {
                    cache.AddTranslationToCache(cellText, cellText);
                }

                return(false);
            }

            if (TextAssetTableHelper.TryTranslateTextAsset(ref asset, DoTranslation, out var result))
            {
                Logger.DebugLogDebug($"{GetType()} handled {calculatedModificationPath}");
                return(new TextAndEncoding(result, TextAssetTableHelper.TextAssetEncoding));
            }

            Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath}");
            return(null);
        }
        /// <inheritdoc />
        /// <remarks>Always returns <c>true</c> to signal nothing else should handle these.</remarks>
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref NickName asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            // updating the NickName assets directly causes issues, but after SaveData.LoadNickNameParam() they
            // are safe to manipulate
            InitHooks();

            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            if (cache.IsEmpty)
            {
                return(true);
            }

            var replacementKey = calculatedModificationPath
                                 .Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
                                 .LastOrDefault();

            // don't touch "player" entry
            if (string.IsNullOrEmpty(replacementKey) ||
                replacementKey.Equals("player", StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            if (!_replacements.TryGetValue(replacementKey, out var replacements))
            {
                _replacements[replacementKey] = replacements = new Dictionary <string, string>();
            }

            foreach (var entry in asset.param)
            {
                if (!entry.isSpecial)
                {
                    continue;
                }
                var key = TextResourceHelper.GetSpecializedKey(entry, entry.Name);
                if (string.IsNullOrEmpty(key))
                {
                    continue;
                }
                if (cache.TryGetTranslation(key, true, out var translated))
                {
                    replacements[key] = translated;
                    TranslationHelper.RegisterRedirectedResourceTextToPath(translated, calculatedModificationPath);
                }
                else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled &&
                         LanguageHelper.IsTranslatable(key))
                {
                    cache.AddTranslationToCache(key, entry.Name);
                }
            }

            return(true);
        }
        protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref ExcelData asset,
                                                     IAssetOrResourceLoadedContext context)
        {
            Logger.DebugLogDebug($"{GetType()} attempt to handle {calculatedModificationPath}");
            var defaultTranslationFile = Path.Combine(calculatedModificationPath, "translation.txt");
            var redirectedResources    = RedirectedDirectory.GetFilesInDirectory(calculatedModificationPath, ".txt");
            var streams = redirectedResources.Select(x => x.OpenStream());
            var cache   = new SimpleTextTranslationCache(
                defaultTranslationFile,
                streams,
                false,
                true);

            var result = false;

            if (cache.IsEmpty)
            {
                Logger.DebugLogDebug($"{GetType()} unable to handle {calculatedModificationPath} (no cache)");
                return(false);
            }

            var columnsToTranslate =
                new HashSet <int>(TextResourceHelper.GetSupportedExcelColumns(calculatedModificationPath, asset));

            var filter = columnsToTranslate.Count > 0;

            var row = -1;

            var shouldTrack = IsTranslationRegistrationAllowed(calculatedModificationPath);

            foreach (var param in asset.list)
            {
                row++;
                if (param.list == null || param.list.Count < 1 || param.list[0] == "no")
                {
                    continue;
                }

                for (var i = 0; i < param.list.Count; i++)
                {
                    if (filter && !columnsToTranslate.Contains(i))
                    {
                        continue;
                    }

                    foreach (var key in TextResourceHelper.GetExcelRowTranslationKeys(asset.name, param.list, i))
                    {
                        if (string.IsNullOrEmpty(key))
                        {
                            continue;
                        }
                        Logger.DebugLogDebug(
                            $"Attempting excel replacement [{row}, {i}]: Searching for replacement key={key}");
                        if (cache.TryGetTranslation(key, true, out var translated))
                        {
                            result     = true;
                            translated = TextResourceHelper.PrepareTranslationForReplacement(asset, translated);
                            if (shouldTrack)
                            {
                                TrackReplacement(calculatedModificationPath, key, translated);
                            }
                            TranslationHelper.RegisterRedirectedResourceTextToPath(translated,
                                                                                   calculatedModificationPath);
                            Logger.DebugLogDebug(
                                $"Replacing [{row}, {i}]: key={key}: {param.list[i]} => {translated}");

                            param.list[i] = translated;
                            break;
                        }

                        if (!LanguageHelper.IsTranslatable(key))
                        {
                            continue;
                        }

                        TranslationHelper.RegisterRedirectedResourceTextToPath(key, calculatedModificationPath);
                        if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled)
                        {
                            cache.AddTranslationToCache(key, key);
                        }
                    }
                }
            }

            Logger.DebugLogDebug(result
                ? $"{GetType()} handled {calculatedModificationPath}"
                : $"{GetType()} unable to handle {calculatedModificationPath}");
            return(result);
        }