Jelajahi Sumber

better IMGUI implementation

Scrublord1336 6 tahun lalu
induk
melakukan
bfe15de571

+ 3 - 1
CHANGELOG.md

@@ -1,5 +1,7 @@
-### 2.7.1
+### 2.8.0
  * Fixed whitespace handling to honor configuration more appropriately
+ * IMGUI enabled by default, now supports numbers in translated texts
+ * Support for overwriting IMGUI hook events
 
 ### 2.7.0
  * Additional installation instructions for standalone installation through ReiPatcher

+ 2 - 1
README.md

@@ -36,7 +36,7 @@ OutputFile=Translation\_AutoGeneratedTranslations.{lang}.txt   ;File to insert g
 EnableUGUI=True                  ;Enable or disable UGUI translation
 EnableNGUI=True                  ;Enable or disable NGUI translation
 EnableTextMeshPro=True           ;Enable or disable TextMeshProp translation
-EnableIMGUI=False                ;Enable of disable IMGUI translation
+EnableIMGUI=True                 ;Enable of disable IMGUI translation
 AllowPluginHookOverride=True     ;Allow other text translation plugins to override this plugin's hooks
 
 [Behaviour]
@@ -136,4 +136,5 @@ Here's how it works, and what is required:
     1. UGUI: public static event Func<object, string, string> OnUnableToTranslateUGUI
     2. TextMeshPro: public static event Func<object, string, string> OnUnableToTranslateTextMeshPro
     3. NGUI: public static event Func<object, string, string> OnUnableToTranslateNGUI
+    3. IMGUI: public static event Func<object, string, string> OnUnableToTranslateIMGUI
  * Also, the events can be either instance based or static.

+ 30 - 30
src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs

@@ -217,21 +217,21 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       private TranslationJob GetOrCreateTranslationJobFor( TranslationKeys key )
       {
-         if( _unstartedJobs.TryGetValue( key.RelevantKey, out TranslationJob job ) )
+         if( _unstartedJobs.TryGetValue( key.GetDictionaryLookupKey(), out TranslationJob job ) )
          {
             return job;
          }
 
          foreach( var completedJob in _completedJobs )
          {
-            if( completedJob.Keys.RelevantKey == key.RelevantKey )
+            if( completedJob.Keys.GetDictionaryLookupKey() == key.GetDictionaryLookupKey() )
             {
                return completedJob;
             }
          }
 
          job = new TranslationJob( key );
-         _unstartedJobs.Add( key.RelevantKey, job );
+         _unstartedJobs.Add( key.GetDictionaryLookupKey(), job );
 
          CheckThresholds();
 
@@ -298,7 +298,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       private void AddTranslation( TranslationKeys key, string value )
       {
-         _translations[ key.RelevantKey ] = value;
+         _translations[ key.GetDictionaryLookupKey() ] = value;
          _translatedTexts.Add( value );
       }
 
@@ -318,21 +318,20 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
       private void QueueNewUntranslatedForDisk( TranslationKeys key )
       {
-         _newUntranslated.Add( key.RelevantKey );
+         _newUntranslated.Add( key.GetDictionaryLookupKey() );
       }
 
       private void QueueNewTranslationForDisk( TranslationKeys key, string value )
       {
          lock( _writeToFileSync )
          {
-            _newTranslations[ key.RelevantKey ] = value;
+            _newTranslations[ key.GetDictionaryLookupKey() ] = value;
          }
       }
 
       private bool TryGetTranslation( TranslationKeys key, out string value )
       {
-         return ( Settings.IgnoreWhitespaceInDialogue && key.IsDialogue && _translations.TryGetValue( key.DialogueKey, out value ) ) 
-            || _translations.TryGetValue( key.OriginalKey, out value );
+         return _translations.TryGetValue( key.GetDictionaryLookupKey(), out value );
       }
 
       private string Override_TextChanged( object ui, string text )
@@ -360,13 +359,15 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
       }
 
-      private void SetTranslatedText( object ui, string text, TranslationInfo info )
+      private void SetTranslatedText( object ui, string translatedText, TranslationKeys key, TranslationInfo info )
       {
-         info?.SetTranslatedText( text );
+         var untemplatedTranslatedText = key.Untemplate( translatedText );
+
+         info?.SetTranslatedText( untemplatedTranslatedText );
 
          if( _isInTranslatedMode )
          {
-            SetText( ui, text, true, info );
+            SetText( ui, untemplatedTranslatedText, true, info );
          }
       }
 
@@ -456,17 +457,17 @@ namespace XUnity.AutoTranslator.Plugin.Core
             return null;
          }
 
-
-         if( Settings.Delay == 0 || !SupportsStabilization( ui ) )
+         var supportsStabilization = SupportsStabilization( ui );
+         if( Settings.Delay == 0 || !supportsStabilization )
          {
-            return TranslateOrQueueWebJobImmediate( ui, text, info );
+            return TranslateOrQueueWebJobImmediate( ui, text, info, supportsStabilization );
          }
          else
          {
             StartCoroutine(
                DelayForSeconds( Settings.Delay, () =>
                {
-                  TranslateOrQueueWebJobImmediate( ui, text, info );
+                  TranslateOrQueueWebJobImmediate( ui, text, info, supportsStabilization );
                } ) );
          }
 
@@ -484,7 +485,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
       /// Translates the string of a UI  text or queues it up to be translated
       /// by the HTTP translation service.
       /// </summary>
-      private string TranslateOrQueueWebJobImmediate( object ui, string text, TranslationInfo info )
+      private string TranslateOrQueueWebJobImmediate( object ui, string text, TranslationInfo info, bool supportsStabilization )
       {
          // Get the trimmed text
          text = ( text ?? ui.GetText() ).Trim();
@@ -494,7 +495,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          {
             info?.Reset( text );
 
-            var textKey = new TranslationKeys( text );
+            var textKey = new TranslationKeys( text, !supportsStabilization );
 
             // if we already have translation loaded in our _translatios dictionary, simply load it and set text
             string translation;
@@ -504,13 +505,13 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                if( !string.IsNullOrEmpty( translation ) )
                {
-                  SetTranslatedText( ui, translation, info );
+                  SetTranslatedText( ui, translation, textKey, info );
                   return translation;
                }
             }
             else
             {
-               if( SupportsStabilization( ui ) )
+               if( supportsStabilization )
                {
                   // 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
@@ -542,7 +543,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
                               if( !string.IsNullOrEmpty( stabilizedText ) && IsTranslatable( stabilizedText ) )
                               {
-                                 var stabilizedTextKey = new TranslationKeys( stabilizedText );
+                                 var stabilizedTextKey = new TranslationKeys( stabilizedText, false );
 
                                  QueueNewUntranslatedForClipboard( stabilizedTextKey );
 
@@ -553,7 +554,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                                  {
                                     if( !string.IsNullOrEmpty( translation ) )
                                     {
-                                       SetTranslatedText( ui, translation, info );
+                                       SetTranslatedText( ui, translation, stabilizedTextKey, info );
                                     }
                                  }
                                  else
@@ -583,9 +584,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
                }
                else
                {
-                  if( !_startedOperationsForNonStabilizableComponents.Contains( text ) && !text.ContainsNumbers() )
+                  if( !_startedOperationsForNonStabilizableComponents.Contains( textKey.GetDictionaryLookupKey() ) )
                   {
-                     _startedOperationsForNonStabilizableComponents.Add( text );
+                     _startedOperationsForNonStabilizableComponents.Add( textKey.GetDictionaryLookupKey() );
 
                      QueueNewUntranslatedForClipboard( textKey );
 
@@ -703,7 +704,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
             // lets see if the text should still be translated before kicking anything off
             if( !job.AnyComponentsStillHasOriginalUntranslatedText() ) continue;
 
-            StartCoroutine( AutoTranslateClient.TranslateByWWW( job.Keys.RelevantKey, Settings.FromLanguage, Settings.Language, translatedText =>
+            StartCoroutine( AutoTranslateClient.TranslateByWWW( job.Keys.GetDictionaryLookupKey(), Settings.FromLanguage, Settings.Language, translatedText =>
             {
                _consecutiveErrors = 0;
 
@@ -712,8 +713,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                   translatedText = translatedText.SplitToLines( Settings.ForceSplitTextAfterCharacters, '\n', ' ', ' ' );
                }
 
-
-               job.TranslatedText = translatedText;
+               job.TranslatedText = job.Keys.RepairTemplate( translatedText );
 
                if( !string.IsNullOrEmpty( translatedText ) )
                {
@@ -766,10 +766,10 @@ namespace XUnity.AutoTranslator.Plugin.Core
                {
                   // 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.Keys.OriginalKey )
+                  if( text == job.Keys.OriginalText )
                   {
                      var info = component.GetTranslationInfo( false );
-                     SetTranslatedText( component, job.TranslatedText, info );
+                     SetTranslatedText( component, job.TranslatedText, job.Keys, info );
                   }
                }
 
@@ -787,10 +787,10 @@ namespace XUnity.AutoTranslator.Plugin.Core
             var info = kvp.Value as TranslationInfo;
             if( info != null && !string.IsNullOrEmpty( info.OriginalText ) )
             {
-               var key = new TranslationKeys( info.OriginalText );
+               var key = new TranslationKeys( info.OriginalText, false );
                if( TryGetTranslation( key, out string translatedText ) && !string.IsNullOrEmpty( translatedText ) )
                {
-                  SetTranslatedText( kvp.Key, translatedText, info );
+                  SetTranslatedText( kvp.Key, translatedText, key, info );
                }
             }
          }

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

@@ -77,7 +77,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
          TranslationDirectory = Config.Current.Preferences[ "Files" ][ "Directory" ].GetOrDefault( @"Translation" );
          OutputFile = Config.Current.Preferences[ "Files" ][ "OutputFile" ].GetOrDefault( @"Translation\_AutoGeneratedTranslations.{lang}.txt" );
 
-         EnableIMGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableIMGUI" ].GetOrDefault( false );
+         EnableIMGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableIMGUI" ].GetOrDefault( true );
          EnableUGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableUGUI" ].GetOrDefault( true );
          EnableNGUI = Config.Current.Preferences[ "TextFrameworks" ][ "EnableNGUI" ].GetOrDefault( true );
          EnableTextMeshPro = Config.Current.Preferences[ "TextFrameworks" ][ "EnableTextMeshPro" ].GetOrDefault( true );

+ 1 - 0
src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEvents.cs

@@ -10,5 +10,6 @@ namespace XUnity.AutoTranslator.Plugin.Core.Constants
       public static string OnUnableToTranslateUGUI = "OnUnableToTranslateUGUI";
       public static string OnUnableToTranslateTextMeshPro = "OnUnableToTranslateTextMeshPro";
       public static string OnUnableToTranslateNGUI = "OnUnableToTranslateNGUI";
+      public static string OnUnableToTranslateIMGUI = "OnUnableToTranslateIMGUI";
    }
 }

+ 122 - 0
src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs

@@ -33,6 +33,128 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
          '9'
       };
 
+      private static readonly HashSet<char> NumbersWithDot = new HashSet<char>
+      {
+         '0',
+         '1',
+         '2',
+         '3',
+         '4',
+         '5',
+         '6',
+         '7',
+         '8',
+         '9',
+         '0',
+         '1',
+         '2',
+         '3',
+         '4',
+         '5',
+         '6',
+         '7',
+         '8',
+         '9',
+         '.'
+      };
+
+      public static TemplatedString TemplatizeByNumbers( this string str )
+      {
+         var dict = new Dictionary<string, string>();
+         bool isNumber = false;
+         StringBuilder carg = null;
+         char arg = 'A';
+
+         for( int i = 0 ; i < str.Length ; i++ )
+         {
+            var c = str[ i ];
+            if( isNumber )
+            {
+               if( NumbersWithDot.Contains( c ) )
+               {
+                  carg.Append( c );
+               }
+               else
+               {
+                  // end current number
+                  var variable = carg.ToString();
+                  var ok = true;
+                  var c1 = variable[ 0 ];
+                  if( c1 == '.' )
+                  {
+                     if( variable.Length == 1 )
+                     {
+                        ok = false;
+                     }
+                     else
+                     {
+                        var c2 = variable[ 1 ];
+                        ok = Numbers.Contains( c2 );
+                     }
+                  }
+
+                  if( ok && !dict.ContainsKey( variable ) )
+                  {
+                     dict.Add( variable, "{{" + arg + "}}" );
+                     arg++;
+                  }
+
+                  carg = null;
+                  isNumber = false;
+               }
+            }
+            else
+            {
+               if( NumbersWithDot.Contains( c ) )
+               {
+                  isNumber = true;
+                  carg = new StringBuilder();
+                  carg.Append( c );
+               }
+            }
+         }
+
+         if( carg != null )
+         {
+            // end current number
+            var variable = carg.ToString();
+            var ok = true;
+            var c1 = variable[ 0 ];
+            if( c1 == '.' )
+            {
+               if( variable.Length == 1 )
+               {
+                  ok = false;
+               }
+               else
+               {
+                  var c2 = variable[ 1 ];
+                  ok = Numbers.Contains( c2 );
+               }
+            }
+
+            if( ok && !dict.ContainsKey( variable ) )
+            {
+               dict.Add( variable, "{{" + arg + "}}" );
+               arg++;
+            }
+         }
+
+         if( dict.Count > 0 )
+         {
+            foreach( var kvp in dict )
+            {
+               str = str.Replace( kvp.Key, kvp.Value );
+            }
+
+            return new TemplatedString( str, dict.ToDictionary( x => x.Value, x => x.Key ) );
+         }
+         else
+         {
+            return null;
+         }
+      }
+
       public static string SplitToLines( this string text, int maxStringLength, params char[] splitOnCharacters )
       {
          var sb = new StringBuilder();

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

@@ -76,7 +76,18 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
          {
             if( Settings.EnableIMGUI )
             {
-               harmony.PatchAll( IMGUIHooks.All );
+               success = SetupHook( KnownEvents.OnUnableToTranslateNGUI, defaultHook );
+               if( !success )
+               {
+                  harmony.PatchAll( IMGUIHooks.All );
+
+                  // This wont work in "newer" unity versions!
+                  try
+                  {
+                     harmony.PatchType( typeof( DoButtonGridHook ) );
+                  }
+                  catch { }
+               }
             }
          }
          catch( Exception e )

+ 21 - 22
src/XUnity.AutoTranslator.Plugin.Core/Hooks/IMGUIHooks.cs

@@ -19,7 +19,6 @@ namespace XUnity.AutoTranslator.Plugin.Core.IMGUI
          typeof( DoButtonHook ),
          typeof( DoModalWindowHook ),
          typeof( DoWindowHook ),
-         //typeof( DoButtonGridHook ),
          typeof( DoTextFieldHook ),
          typeof( DoToggleHook ),
       };
@@ -159,27 +158,27 @@ namespace XUnity.AutoTranslator.Plugin.Core.IMGUI
       }
    }
 
-   //[Harmony, HarmonyAfter( Constants.KnownPlugins.DynamicTranslationLoader )]
-   //public static class DoButtonGridHook
-   //{
-   //   static bool Prepare( HarmonyInstance instance )
-   //   {
-   //      return Constants.Types.GUI != null;
-   //   }
-
-   //   static MethodBase TargetMethod( HarmonyInstance instance )
-   //   {
-   //      return AccessTools.Method( Constants.Types.GUI, "DoButtonGrid", new[] { typeof( Rect ), typeof( int ), typeof( GUIContent[] ), typeof( int ), typeof( GUIStyle ), typeof( GUIStyle ), typeof( GUIStyle ), typeof( GUIStyle ) } );
-   //   }
-
-   //   static void Prefix( GUIContent[] contents )
-   //   {
-   //      foreach( var content in contents )
-   //      {
-   //         AutoTranslationPlugin.Current.Hook_TextChanged( content );
-   //      }
-   //   }
-   //}
+   [Harmony, HarmonyAfter( Constants.KnownPlugins.DynamicTranslationLoader )]
+   public static class DoButtonGridHook
+   {
+      static bool Prepare( HarmonyInstance instance )
+      {
+         return Constants.Types.GUI != null;
+      }
+
+      static MethodBase TargetMethod( HarmonyInstance instance )
+      {
+         return AccessTools.Method( Constants.Types.GUI, "DoButtonGrid", new[] { typeof( Rect ), typeof( int ), typeof( GUIContent[] ), typeof( int ), typeof( GUIStyle ), typeof( GUIStyle ), typeof( GUIStyle ), typeof( GUIStyle ) } );
+      }
+
+      static void Prefix( GUIContent[] contents )
+      {
+         foreach( var content in contents )
+         {
+            AutoTranslationPlugin.Current.Hook_TextChanged( content );
+         }
+      }
+   }
 
    [Harmony, HarmonyAfter( Constants.KnownPlugins.DynamicTranslationLoader )]
    public static class DoTextFieldHook

+ 32 - 0
src/XUnity.AutoTranslator.Plugin.Core/TemplatedString.cs

@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+namespace XUnity.AutoTranslator.Plugin.Core
+{
+   public class TemplatedString
+   {
+      public TemplatedString( string template, Dictionary<string, string> arguments )
+      {
+         Template = template;
+         Arguments = arguments;
+      }
+
+      public string Template { get; private set; }
+
+      public Dictionary<string, string> Arguments { get; private set; }
+
+      public string Untemplate( string text )
+      {
+         foreach( var kvp in Arguments )
+         {
+            text = text.Replace( kvp.Key, kvp.Value );
+         }
+         return text;
+      }
+
+      public string RepairTemplate( string text )
+      {
+         // TODO: Implement template repairation. The web services might have mangled our parameterization
+         return text;
+      }
+   }
+}

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

@@ -30,7 +30,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          foreach( var component in Components )
          {
             var text = component.GetText().Trim();
-            if( text == Keys.OriginalKey )
+            if( text == Keys.OriginalText )
             {
                return true;
             }

+ 51 - 7
src/XUnity.AutoTranslator.Plugin.Core/TranslationKeys.cs

@@ -9,18 +9,62 @@ namespace XUnity.AutoTranslator.Plugin.Core
 {
    public struct TranslationKeys
    {
-      public TranslationKeys( string key )
+      public TranslationKeys( string key, bool templatizeByNumbers )
       {
-         OriginalKey = key;
-         DialogueKey = key.RemoveWhitespace();
+         OriginalText = key;
+
+         if( Settings.IgnoreWhitespaceInDialogue && key.Length > Settings.MinDialogueChars )
+         {
+            RelevantKey = key.RemoveWhitespace();
+         }
+         else
+         {
+            RelevantKey = key;
+         }
+
+         if( templatizeByNumbers )
+         {
+            TemplatedKey = RelevantKey.TemplatizeByNumbers();
+         }
+         else
+         {
+            TemplatedKey = null;
+         }
+      }
+
+      public TemplatedString TemplatedKey { get; }
+
+      public string RelevantKey { get; }
+
+      public string OriginalText { get; set; }
+
+      public string GetDictionaryLookupKey()
+      {
+         if( TemplatedKey != null )
+         {
+            return TemplatedKey.Template;
+         }
+         return RelevantKey;
       }
 
-      public string OriginalKey { get; }
+      public string Untemplate( string text )
+      {
+         if( TemplatedKey != null )
+         {
+            return TemplatedKey.Untemplate( text );
+         }
 
-      public string DialogueKey { get; }
+         return text;
+      }
 
-      public string RelevantKey => IsDialogue && Settings.IgnoreWhitespaceInDialogue ? DialogueKey : OriginalKey;
+      public string RepairTemplate( string text )
+      {
+         if( TemplatedKey != null )
+         {
+            return TemplatedKey.RepairTemplate( text );
+         }
 
-      public bool IsDialogue => OriginalKey.Length > Settings.MinDialogueChars;
+         return text;
+      }
    }
 }