Ver código fonte

translation fix, still missing softlock #4

Scrublord1336 6 anos atrás
pai
commit
afba73c418

+ 131 - 136
src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs

@@ -43,6 +43,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
       /// </summary>
       private List<TranslationJob> _completedJobs = new List<TranslationJob>();
       private Dictionary<string, TranslationJob> _unstartedJobs = new Dictionary<string, TranslationJob>();
+      private Dictionary<string, TranslationJob> _ongoingJobs = new Dictionary<string, TranslationJob>();
 
       /// <summary>
       /// All the translations are stored in this dictionary.
@@ -74,7 +75,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
       /// the translation plugin.
       /// </summary>
       private HashSet<object> _ongoingOperations = new HashSet<object>();
-      private HashSet<string> _startedOperationsForNonStabilizableComponents = new HashSet<string>();
 
       /// <summary>
       /// This function will check if there are symbols of a given language contained in a string.
@@ -103,7 +103,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
          if( Settings.EnableConsole ) DebugConsole.Enable();
 
-         HooksSetup.InstallHooks( Override_TextChanged );
+         HooksSetup.InstallHooks();
 
          try
          {
@@ -244,32 +244,43 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       private TranslationJob GetOrCreateTranslationJobFor( object ui, TranslationKey key, TranslationContext context )
       {
-         if( _unstartedJobs.TryGetValue( key.GetDictionaryLookupKey(), out TranslationJob job ) )
+         var lookupKey = key.GetDictionaryLookupKey();
+
+         if( _unstartedJobs.TryGetValue( lookupKey, out TranslationJob unstartedJob ) )
+         {
+            unstartedJob.Associate( context );
+            return unstartedJob;
+         }
+
+         if( _ongoingJobs.TryGetValue( lookupKey, out TranslationJob ongoingJob ) )
          {
-            job.Associate( context );
-            return job;
+            ongoingJob.Associate( context );
+            return ongoingJob;
          }
 
          foreach( var completedJob in _completedJobs )
          {
-            if( completedJob.Key.GetDictionaryLookupKey() == key.GetDictionaryLookupKey() )
+            if( completedJob.Key.GetDictionaryLookupKey() == lookupKey )
             {
                completedJob.Associate( context );
                return completedJob;
             }
          }
 
-         Logger.Current.Debug( "Queued translation for: " + key.GetDictionaryLookupKey() );
+         Logger.Current.Debug( "Queued translation for: " + lookupKey );
 
-         job = new TranslationJob( key );
-         job.OriginalSources.Add( ui );
-         job.Associate( context );
+         ongoingJob = new TranslationJob( key );
+         if( ui != null )
+         {
+            ongoingJob.OriginalSources.Add( ui );
+         }
+         ongoingJob.Associate( context );
 
-         _unstartedJobs.Add( key.GetDictionaryLookupKey(), job );
+         _unstartedJobs.Add( lookupKey, ongoingJob );
 
          CheckThresholds();
 
-         return job;
+         return ongoingJob;
       }
 
       private void CheckThresholds()
@@ -278,6 +289,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          {
             _unstartedJobs.Clear();
             _completedJobs.Clear();
+            _ongoingJobs.Clear();
             Settings.IsShutdown = true;
 
             Logger.Current.Error( $"SPAM DETECTED: More than {Settings.MaxUnstartedJobs} queued for translations due to unknown reasons. Shutting down plugin." );
@@ -304,6 +316,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
             {
                _unstartedJobs.Clear();
                _completedJobs.Clear();
+               _ongoingJobs.Clear();
                Settings.IsShutdown = true;
 
                Logger.Current.Error( $"SPAM DETECTED: More than {Settings.MaxTranslationsQueuedPerSecond} translations per seconds queued for a {Settings.MaxSecondsAboveTranslationThreshold} second period. Shutting down plugin." );
@@ -377,7 +390,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          return _translations.TryGetValue( key.GetDictionaryLookupKey(), out value );
       }
 
-      public string Override_TextChanged( object ui, string text )
+      public string Hook_TextChanged_WithResult( object ui, string text )
       {
          if( _hooksEnabled )
          {
@@ -537,10 +550,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
          // Get the trimmed text
          text = ( text ?? ui.GetText() ).Trim();
 
-         Logger.Current.Debug( ui.GetType().Name );
-
-         // INPUT PROBLEM: Related to AdvCommandSelection first, then UguiNovelText second, GAH
-
          // Ensure that we actually want to translate this text and its owning UI element. 
          if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslate( ui ) && !IsCurrentlySetting( info ) )
          {
@@ -548,64 +557,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
             var textKey = new TranslationKey( text, !supportsStabilization && context == null, context != null );
 
 
-            if( context == null )
-            {
-               var parser = UnityTextParsers.GetTextParserByGameEngine();
-               if( parser != null )
-               {
-                  var result = parser.Parse( text );
-                  if( result.Arguments.Count > 1 )
-                  {
-                     Logger.Current.Info( "Attemping part translation for " + ui.GetType().Name );
-
-                     Dictionary<string, string> translations = new Dictionary<string, string>();
-                     context = new TranslationContext( ui, result );
-
-                     // attempt to lookup ALL strings immediately; return result if possible; queue operations
-                     foreach( var kvp in result.Arguments )
-                     {
-                        var key = kvp.Key;
-                        var value = kvp.Value.Trim();
-                        if( !string.IsNullOrEmpty( value ) && IsTranslatable( value ) )
-                        {
-                           var valueKey = new TranslationKey( value, false, true );
-                           string partTranslation;
-                           if( TryGetTranslation( valueKey, out partTranslation ) )
-                           {
-                              translations.Add( key, partTranslation );
-                           }
-                           else
-                           {
-                              Logger.Current.Info( "Starting part translation for " + value );
-
-                              // incomplete, must start job
-                              TranslateOrQueueWebJobImmediate( ui, value, info, supportsStabilization, context );
-                           }
-                        }
-                        else
-                        {
-                           // the value will do
-                           translations.Add( key, value );
-                        }
-                     }
-
-                     Logger.Current.Info( $"Should untemplate: {result.Arguments.Count}, {translations.Count}." );
-                     if( result.Arguments.Count == translations.Count )
-                     {
-                        return result.Untemplate( translations );
-                     }
-                     else
-                     {
-                        return null; // could not perform complete translation
-                     }
-                  }
-               }
-            }
-
-
-
-
-
             // if we already have translation loaded in our _translatios dictionary, simply load it and set text
             string translation;
             if( TryGetTranslation( textKey, out translation ) )
@@ -620,7 +571,25 @@ namespace XUnity.AutoTranslator.Plugin.Core
             }
             else
             {
-               if( supportsStabilization && context != null ) // never stabilize a text that is contextualized
+               if( context == null )
+               {
+                  var parser = UnityTextParsers.GetTextParserByGameEngine();
+                  if( parser != null )
+                  {
+                     var result = parser.Parse( text );
+                     if( result.HasRichSyntax )
+                     {
+                        translation = TranslateOrQueueWebJobImmediateByParserResult( ui, result, true );
+                        if( translation != null )
+                        {
+                           SetTranslatedText( ui, translation, textKey, info );
+                        }
+                        return translation;
+                     }
+                  }
+               }
+
+               if( supportsStabilization && context == null ) // never stabilize a text that is contextualized or that does not support stabilization
                {
                   // if we dont know what text to translate it to, we need to figure it out.
                   // this might take a while, so add the UI text component to the ongoing operations
@@ -668,6 +637,24 @@ namespace XUnity.AutoTranslator.Plugin.Core
                                  }
                                  else
                                  {
+                                    if( context == null )
+                                    {
+                                       var parser = UnityTextParsers.GetTextParserByGameEngine();
+                                       if( parser != null )
+                                       {
+                                          var result = parser.Parse( stabilizedText );
+                                          if( result.HasRichSyntax )
+                                          {
+                                             var translatedText = TranslateOrQueueWebJobImmediateByParserResult( ui, result, true );
+                                             if( translatedText != null )
+                                             {
+                                                SetTranslatedText( ui, translatedText, stabilizedTextKey, info );
+                                             }
+                                             return;
+                                          }
+                                       }
+                                    }
+
                                     // Lets try not to spam a service that might not be there...
                                     if( _endpoint != null )
                                     {
@@ -675,8 +662,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
                                        {
                                           var job = GetOrCreateTranslationJobFor( ui, stabilizedTextKey, context );
                                           job.Components.Add( ui );
-
-                                          Logger.Current.Debug( "Queued from A " + supportsStabilization + " " + context );
                                        }
                                     }
                                     else
@@ -695,27 +680,18 @@ namespace XUnity.AutoTranslator.Plugin.Core
                }
                else
                {
-                  if( !_startedOperationsForNonStabilizableComponents.Contains( textKey.GetDictionaryLookupKey() ) )
+                  // Lets try not to spam a service that might not be there...
+                  if( _endpoint != null )
                   {
-                     _startedOperationsForNonStabilizableComponents.Add( textKey.GetDictionaryLookupKey() );
-
-                     QueueNewUntranslatedForClipboard( textKey );
-
-                     // Lets try not to spam a service that might not be there...
-                     if( _endpoint != null )
+                     if( _consecutiveErrors < Settings.MaxErrors && !Settings.IsShutdown )
                      {
-                        if( _consecutiveErrors < Settings.MaxErrors && !Settings.IsShutdown )
-                        {
-                           var job = GetOrCreateTranslationJobFor( ui, textKey, context );
-
-                           Logger.Current.Debug( "Queued from A " + supportsStabilization + " " + context + " " + ui.GetType().Name );
-                        }
-                     }
-                     else
-                     {
-                        QueueNewUntranslatedForDisk( textKey );
+                        var job = GetOrCreateTranslationJobFor( ui, textKey, context );
                      }
                   }
+                  else
+                  {
+                     QueueNewUntranslatedForDisk( textKey );
+                  }
                }
             }
          }
@@ -723,6 +699,47 @@ namespace XUnity.AutoTranslator.Plugin.Core
          return null;
       }
 
+      private string TranslateOrQueueWebJobImmediateByParserResult( object ui, ParserResult result, bool allowStartJob )
+      {
+         Dictionary<string, string> translations = new Dictionary<string, string>();
+
+         // attempt to lookup ALL strings immediately; return result if possible; queue operations
+         foreach( var kvp in result.Arguments )
+         {
+            var key = kvp.Key;
+            var value = kvp.Value.Trim();
+            if( !string.IsNullOrEmpty( value ) && IsTranslatable( value ) )
+            {
+               var valueKey = new TranslationKey( value, false, true );
+               string partTranslation;
+               if( TryGetTranslation( valueKey, out partTranslation ) )
+               {
+                  translations.Add( key, partTranslation );
+               }
+               else if( allowStartJob )
+               {
+                  // incomplete, must start job
+                  var context = new TranslationContext( ui, result );
+                  TranslateOrQueueWebJobImmediate( null, value, null, false, context );
+               }
+            }
+            else
+            {
+               // the value will do
+               translations.Add( key, value );
+            }
+         }
+
+         if( result.Arguments.Count == translations.Count )
+         {
+            return result.Untemplate( translations );
+         }
+         else
+         {
+            return null; // could not perform complete translation
+         }
+      }
+
       /// <summary>
       /// Utility method that allows me to wait to call an action, until
       /// the text has stopped changing. This is important for 'story'
@@ -823,7 +840,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                var kvps = _unstartedJobs.Take( Settings.BatchSize ).ToList();
                var batch = new TranslationBatch();
-               bool addedAny = false;
 
                foreach( var kvp in kvps )
                {
@@ -831,14 +847,13 @@ namespace XUnity.AutoTranslator.Plugin.Core
                   var job = kvp.Value;
                   _kickedOff.Add( key );
 
-                  batch.Add( job );
-
-                  if( !job.AnyComponentsStillHasOriginalUntranslatedText() ) continue;
+                  if( !job.AnyComponentsStillHasOriginalUntranslatedTextOrContextual() ) continue;
 
-                  addedAny = true;
+                  batch.Add( job );
+                  _ongoingJobs[ key ] = job;
                }
 
-               if( addedAny )
+               if( !batch.IsEmpty )
                {
                   StartCoroutine( _endpoint.Translate( batch.GetFullTranslationKey(), Settings.FromLanguage, Settings.Language, translatedText => OnBatchTranslationCompleted( batch, translatedText ),
                   () => OnTranslationFailed( batch ) ) );
@@ -856,7 +871,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
                _kickedOff.Add( key );
 
                // lets see if the text should still be translated before kicking anything off
-               if( !job.AnyComponentsStillHasOriginalUntranslatedText() ) continue;
+               if( !job.AnyComponentsStillHasOriginalUntranslatedTextOrContextual() ) continue;
+
+               _ongoingJobs[ key ] = job;
 
                StartCoroutine( _endpoint.Translate( job.Key.GetDictionaryLookupKey(), Settings.FromLanguage, Settings.Language, translatedText => OnSingleTranslationCompleted( job, translatedText ),
                () => OnTranslationFailed( job ) ) );
@@ -906,6 +923,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                }
 
                job.State = TranslationJobState.Succeeded;
+               _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() );
             }
          }
          else
@@ -919,6 +937,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                {
                   _unstartedJobs[ key ] = tracker.Job;
                }
+               _ongoingJobs.Remove( key );
             }
 
             Logger.Current.Error( "A batch operation failed. Disabling batching and restarting failed jobs." );
@@ -953,6 +972,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
 
          job.State = TranslationJobState.Succeeded;
+         _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() );
       }
 
       private void OnTranslationFailed( TranslationJob job )
@@ -960,6 +980,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          _consecutiveErrors++;
 
          job.State = TranslationJobState.Failed;
+         _ongoingJobs.Remove( job.Key.GetDictionaryLookupKey() );
 
          if( !Settings.IsShutdown )
          {
@@ -977,6 +998,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                   _unstartedJobs.Clear();
                   _completedJobs.Clear();
+                  _ongoingJobs.Clear();
                }
             }
          }
@@ -989,6 +1011,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          foreach( var tracker in batch.Trackers )
          {
             tracker.Job.State = TranslationJobState.Failed;
+            _ongoingJobs.Remove( tracker.Job.Key.GetDictionaryLookupKey() );
          }
 
          if( !Settings.IsShutdown )
@@ -1007,6 +1030,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                   _unstartedJobs.Clear();
                   _completedJobs.Clear();
+                  _ongoingJobs.Clear();
                }
             }
          }
@@ -1023,23 +1047,15 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                AddTranslation( job.Key, job.TranslatedText );
 
-               Logger.Current.Debug( $"COMPLETED JOB WITH: " + job.Components.Count );
-
                foreach( var component in job.Components )
                {
                   // update the original text, but only if it has not been chaanged already for some reason (could be other translator plugin or game itself)
                   var text = component.GetText().Trim();
                   if( text == job.Key.OriginalText )
                   {
-                     Logger.Current.Debug( $"Setting translated text on {component.GetType().Name} to {text}." );
-
                      var info = component.GetTranslationInfo( false );
                      SetTranslatedText( component, job.TranslatedText, job.Key, info );
                   }
-                  else
-                  {
-                     Logger.Current.Debug( $"Failed setting translated text on {component.GetType().Name} to {text}." );
-                  }
                }
 
                // handle each context
@@ -1051,39 +1067,18 @@ namespace XUnity.AutoTranslator.Plugin.Core
                      Dictionary<string, string> translations = new Dictionary<string, string>();
                      var result = context.Result;
 
-                     // attempt to lookup ALL strings immediately; return result if possible; queue operations
-                     foreach( var kvp in result.Arguments )
+                     var translatedText = TranslateOrQueueWebJobImmediateByParserResult( null, result, false );
+                     if( translatedText != null )
                      {
-                        var key = kvp.Key;
-                        var value = kvp.Value.Trim();
-                        if( !string.IsNullOrEmpty( value ) && IsTranslatable( value ) )
-                        {
-                           var valueKey = new TranslationKey( value, false, true );
-                           string partTranslation;
-                           if( TryGetTranslation( valueKey, out partTranslation ) )
-                           {
-                              translations.Add( key, partTranslation );
-                           }
-                           else
-                           {
-                              Logger.Current.Error( "Expected to find translation for: " + value );
-                           }
-                        }
-                        else
-                        {
-                           // the value will do
-                           translations.Add( key, value );
-                        }
+                        var info = context.Component.GetTranslationInfo( false );
+                        SetTranslatedText( context.Component, translatedText, job.Key, info );
                      }
-
-                     var info = context.Component.GetTranslationInfo( false );
-                     SetTranslatedText( result.Untemplate( translations ), job.TranslatedText, job.Key, info );
                   }
                }
 
 
                // Utage support
-               if( Constants.Types.AdvCommand != null && Constants.Types.AdvEngine != null
+               if( Constants.Types.AdvEngine != null
                   && job.OriginalSources.Any( x => Constants.Types.AdvCommand.IsAssignableFrom( x.GetType() ) ) )
                {
                   _nextAdvUpdate = Time.time + 0.5f;

+ 2 - 0
src/XUnity.AutoTranslator.Plugin.Core/Batching/TranslationBatch.cs

@@ -12,6 +12,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Batching
 
       public List<TranslationLineTracker> Trackers { get; private set; }
 
+      public bool IsEmpty => Trackers.Count == 0;
+
       public int TotalLinesCount { get; set; }
 
       public void Add( TranslationJob job )

+ 2 - 0
src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs

@@ -40,6 +40,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
       public static bool EnableUGUI;
       public static bool EnableNGUI;
       public static bool EnableTextMeshPro;
+      public static bool EnableUtage;
       public static bool AllowPluginHookOverride;
       public static bool IgnoreWhitespaceInDialogue;
       public static int MinDialogueChars;
@@ -87,6 +88,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
          EnableUGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableUGUI" ].GetOrDefault( true );
          EnableNGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableNGUI" ].GetOrDefault( true );
          EnableTextMeshPro = Config.Current.Preferences[ "TextFrameworks" ][ "EnableTextMeshPro" ].GetOrDefault( true );
+         EnableUtage = Config.Current.Preferences[ "TextFrameworks" ][ "EnableUtage" ].GetOrDefault( true );
          AllowPluginHookOverride = Config.Current.Preferences[ "TextFrameworks" ][ "AllowPluginHookOverride" ].GetOrDefault( true );
 
          Delay = Config.Current.Preferences[ "Behaviour" ][ "Delay" ].GetOrDefault( 0f );

+ 4 - 0
src/XUnity.AutoTranslator.Plugin.Core/Extensions/ComponentExtensions.cs

@@ -13,6 +13,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 
       public static string GetText( this object ui )
       {
+         if( ui == null ) return null;
+
          string text = null;
          var type = ui.GetType();
 
@@ -40,6 +42,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 
       public static void SetText( this object ui, string text )
       {
+         if( ui == null ) return;
+
          var type = ui.GetType();
 
          if( type == Constants.Types.UguiNovelText && ( ( Component ) ui ).gameObject.GetFirstComponentInSelfOrAncestor( Constants.Types.AdvUguiSelection ) != null )

+ 8 - 2
src/XUnity.AutoTranslator.Plugin.Core/Extensions/ObjectExtensions.cs

@@ -3,7 +3,8 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading;
-using UnityEngine;
+using UnityEngine.UI;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Utilities;
 
 namespace XUnity.AutoTranslator.Plugin.Core.Extensions
@@ -15,8 +16,13 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
       
       public static bool SupportsStabilization( this object ui )
       {
+         if( ui == null ) return false;
+
          var type = ui.GetType();
-         return !( ui is GUIContent || Constants.Types.AdvCommand.IsAssignableFrom( type ) ) ;
+
+         return ui is Text
+            || ( Types.UILabel != null && Types.UILabel.IsAssignableFrom( type ) )
+            || ( Types.TMP_Text != null && Types.TMP_Text.IsAssignableFrom( type ) );
       }
 
       public static TranslationInfo GetTranslationInfo( this object obj, bool isAwakening )

+ 8 - 12
src/XUnity.AutoTranslator.Plugin.Core/Hooks/HooksSetup.cs

@@ -19,16 +19,16 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
    public static class HooksSetup
    {
-      public static void InstallHooks( Func<object, string, string> defaultHook )
+      public static void InstallHooks()
       {
          var harmony = HarmonyInstance.Create( "gravydevsupreme.xunity.autotranslator" );
 
          bool success = false;
          try
          {
-            if( Settings.EnableUGUI )
+            if( Settings.EnableUGUI || Settings.EnableUtage )
             {
-               success = SetupHook( KnownEvents.OnUnableToTranslateUGUI, defaultHook );
+               success = SetupHook( KnownEvents.OnUnableToTranslateUGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult );
                if( !success )
                {
                   harmony.PatchAll( UGUIHooks.All );
@@ -44,7 +44,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
          {
             if( Settings.EnableTextMeshPro )
             {
-               success = SetupHook( KnownEvents.OnUnableToTranslateTextMeshPro, defaultHook );
+               success = SetupHook( KnownEvents.OnUnableToTranslateTextMeshPro, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult );
                if( !success )
                {
                   harmony.PatchAll( TextMeshProHooks.All );
@@ -60,7 +60,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
          {
             if( Settings.EnableNGUI )
             {
-               success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, defaultHook );
+               success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult );
                if( !success )
                {
                   harmony.PatchAll( NGUIHooks.All );
@@ -76,7 +76,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
          {
             if( Settings.EnableIMGUI )
             {
-               success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, defaultHook );
+               success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, AutoTranslationPlugin.Current.Hook_TextChanged_WithResult );
                if( !success )
                {
                   harmony.PatchAll( IMGUIHooks.All );
@@ -97,13 +97,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
          try
          {
-            if( true )
+            if( Settings.EnableUtage )
             {
-               success = SetupHook( "NANIDESU", defaultHook );
-               if( !success )
-               {
-                  harmony.PatchAll( UtageHooks.All );
-               }
+               harmony.PatchAll( UtageHooks.All );
             }
          }
          catch( Exception e )

+ 1 - 1
src/XUnity.AutoTranslator.Plugin.Core/Hooks/UtageHooks.cs

@@ -29,7 +29,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static void Postfix( object __instance, ref string __result )
       {
-         var result = AutoTranslationPlugin.Current.Override_TextChanged( __instance, __result );
+         var result = AutoTranslationPlugin.Current.Hook_TextChanged_WithResult( __instance, __result );
          if( !string.IsNullOrEmpty( result ) )
          {
             __result = result;

+ 2 - 0
src/XUnity.AutoTranslator.Plugin.Core/Parsing/ParserResult.cs

@@ -14,6 +14,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
 
       public Dictionary<string, string> Arguments { get; private set; }
 
+      public bool HasRichSyntax => Template.Length > 5; // {{A}} <-- 5 chars
+
       public string Untemplate( Dictionary<string, string> arguments )
       {
          string result = Template;

+ 4 - 0
src/XUnity.AutoTranslator.Plugin.Core/TranslationInfo.cs

@@ -31,6 +31,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public void ResizeUI( object graphic )
       {
+         if( graphic == null ) return;
+
          if( graphic is Text )
          {
             var ui = (Text)graphic;
@@ -84,6 +86,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public void UnresizeUI( object graphic )
       {
+         if( graphic == null ) return;
+
          _reset?.Invoke( graphic );
          _reset = null;
       }

+ 2 - 2
src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs

@@ -32,9 +32,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       public TranslationJobState State { get; set; }
 
-      public bool AnyComponentsStillHasOriginalUntranslatedText()
+      public bool AnyComponentsStillHasOriginalUntranslatedTextOrContextual()
       {
-         if( Components.Count == 0 ) return true; // we do not know
+         if( Components.Count == 0 || Contexts.Count > 0 ) return true; // we do not know
 
          foreach( var component in Components )
          {

+ 6 - 7
src/XUnity.AutoTranslator.Plugin.Core/Utilities/TextHelper.cs

@@ -49,10 +49,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Utilities
       /// </summary>
       public static string Decode( string text )
       {
-         // Remove these in newer version
-         text = text.Replace( "\\r", "\r" );
-         text = text.Replace( "\\n", "\n" );
-         return text;
+         return text.Replace( "\\r", "\r" )
+            .Replace( "\\n", "\n" )
+            .Replace( "%3D", "=" );
       }
 
       /// <summary>
@@ -62,9 +61,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Utilities
       /// </summary>
       public static string Encode( string text )
       {
-         text = text.Replace( "\r", "\\r" );
-         text = text.Replace( "\n", "\\n" );
-         return text;
+         return text.Replace( "\r", "\\r" )
+            .Replace( "\n", "\\n" )
+            .Replace( "=", "%3D" );
       }
    }
 }