Ver Fonte

work on #4

Scrublord1336 há 6 anos atrás
pai
commit
f69117bb88

+ 164 - 12
src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs

@@ -27,6 +27,7 @@ using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Debugging;
 using XUnity.AutoTranslator.Plugin.Core.Batching;
 using Harmony;
+using XUnity.AutoTranslator.Plugin.Core.Parsing;
 
 namespace XUnity.AutoTranslator.Plugin.Core
 {
@@ -241,10 +242,11 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
       }
 
-      private TranslationJob GetOrCreateTranslationJobFor( object ui, TranslationKey key )
+      private TranslationJob GetOrCreateTranslationJobFor( object ui, TranslationKey key, TranslationContext context )
       {
          if( _unstartedJobs.TryGetValue( key.GetDictionaryLookupKey(), out TranslationJob job ) )
          {
+            job.Associate( context );
             return job;
          }
 
@@ -252,6 +254,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
          {
             if( completedJob.Key.GetDictionaryLookupKey() == key.GetDictionaryLookupKey() )
             {
+               completedJob.Associate( context );
                return completedJob;
             }
          }
@@ -260,6 +263,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
          job = new TranslationJob( key );
          job.OriginalSources.Add( ui );
+         job.Associate( context );
 
          _unstartedJobs.Add( key.GetDictionaryLookupKey(), job );
 
@@ -528,17 +532,79 @@ 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, bool supportsStabilization )
+      private string TranslateOrQueueWebJobImmediate( object ui, string text, TranslationInfo info, bool supportsStabilization, TranslationContext context = null )
       {
          // 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 ) )
          {
             info?.Reset( text );
+            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
+                     }
+                  }
+               }
+            }
+
+
+
 
-            var textKey = new TranslationKey( text, !supportsStabilization );
 
             // if we already have translation loaded in our _translatios dictionary, simply load it and set text
             string translation;
@@ -554,7 +620,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
             }
             else
             {
-               if( supportsStabilization )
+               if( supportsStabilization && context != null ) // never stabilize a text that is contextualized
                {
                   // 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
@@ -607,8 +673,10 @@ namespace XUnity.AutoTranslator.Plugin.Core
                                     {
                                        if( _consecutiveErrors < Settings.MaxErrors && !Settings.IsShutdown )
                                        {
-                                          var job = GetOrCreateTranslationJobFor( ui, stabilizedTextKey );
+                                          var job = GetOrCreateTranslationJobFor( ui, stabilizedTextKey, context );
                                           job.Components.Add( ui );
+
+                                          Logger.Current.Debug( "Queued from A " + supportsStabilization + " " + context );
                                        }
                                     }
                                     else
@@ -638,7 +706,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
                      {
                         if( _consecutiveErrors < Settings.MaxErrors && !Settings.IsShutdown )
                         {
-                           GetOrCreateTranslationJobFor( ui, textKey );
+                           var job = GetOrCreateTranslationJobFor( ui, textKey, context );
+
+                           Logger.Current.Debug( "Queued from A " + supportsStabilization + " " + context + " " + ui.GetType().Name );
                         }
                      }
                      else
@@ -771,7 +841,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                if( addedAny )
                {
                   StartCoroutine( _endpoint.Translate( batch.GetFullTranslationKey(), Settings.FromLanguage, Settings.Language, translatedText => OnBatchTranslationCompleted( batch, translatedText ),
-                  () => OnTranslationFailed() ) );
+                  () => OnTranslationFailed( batch ) ) );
                }
             }
          }
@@ -789,7 +859,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                if( !job.AnyComponentsStillHasOriginalUntranslatedText() ) continue;
 
                StartCoroutine( _endpoint.Translate( job.Key.GetDictionaryLookupKey(), Settings.FromLanguage, Settings.Language, translatedText => OnSingleTranslationCompleted( job, translatedText ),
-               () => OnTranslationFailed() ) );
+               () => OnTranslationFailed( job ) ) );
             }
          }
 
@@ -834,6 +904,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
                   QueueNewTranslationForDisk( job.Key, translatedText );
                   _completedJobs.Add( job );
                }
+
+               job.State = TranslationJobState.Succeeded;
             }
          }
          else
@@ -879,12 +951,46 @@ namespace XUnity.AutoTranslator.Plugin.Core
             QueueNewTranslationForDisk( job.Key, translatedText );
             _completedJobs.Add( job );
          }
+
+         job.State = TranslationJobState.Succeeded;
       }
 
-      private void OnTranslationFailed()
+      private void OnTranslationFailed( TranslationJob job )
       {
          _consecutiveErrors++;
 
+         job.State = TranslationJobState.Failed;
+
+         if( !Settings.IsShutdown )
+         {
+            if( _consecutiveErrors > Settings.MaxErrors )
+            {
+               if( _endpoint.ShouldGetSecondChanceAfterFailure() )
+               {
+                  Logger.Current.Warn( $"More than {Settings.MaxErrors} consecutive errors occurred. Entering fallback mode." );
+                  _consecutiveErrors = 0;
+               }
+               else
+               {
+                  Settings.IsShutdown = true;
+                  Logger.Current.Error( $"More than {Settings.MaxErrors} consecutive errors occurred. Shutting down plugin." );
+
+                  _unstartedJobs.Clear();
+                  _completedJobs.Clear();
+               }
+            }
+         }
+      }
+
+      private void OnTranslationFailed( TranslationBatch batch )
+      {
+         _consecutiveErrors++;
+
+         foreach( var tracker in batch.Trackers )
+         {
+            tracker.Job.State = TranslationJobState.Failed;
+         }
+
          if( !Settings.IsShutdown )
          {
             if( _consecutiveErrors > Settings.MaxErrors )
@@ -915,18 +1021,66 @@ namespace XUnity.AutoTranslator.Plugin.Core
                var job = _completedJobs[ i ];
                _completedJobs.RemoveAt( i );
 
+               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
+               foreach( var context in job.Contexts )
+               {
+                  // are all jobs within this context completed? If so, we can set the text
+                  if( context.Jobs.All( x => x.State == TranslationJobState.Succeeded ) )
+                  {
+                     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 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( result.Untemplate( translations ), job.TranslatedText, job.Key, info );
+                  }
                }
 
-               //Logger.Current.Debug( "FINISH: " + job.TranslatedText + ", " + string.Join( ", ", job.OriginalSources.Select( x => x.GetType().Name ).ToArray() ) );
 
                // Utage support
                if( Constants.Types.AdvCommand != null && Constants.Types.AdvEngine != null
@@ -934,8 +1088,6 @@ namespace XUnity.AutoTranslator.Plugin.Core
                {
                   _nextAdvUpdate = Time.time + 0.5f;
                }
-
-               AddTranslation( job.Key, job.TranslatedText );
             }
          }
       }

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

@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Parsing
+{
+   public class ParserResult
+   {
+      public ParserResult( string template, Dictionary<string, string> args )
+      {
+         Template = template;
+         Arguments = args;
+      }
+
+      public string Template { get; private set; }
+
+      public Dictionary<string, string> Arguments { get; private set; }
+
+      public string Untemplate( Dictionary<string, string> arguments )
+      {
+         string result = Template;
+         foreach( var kvp in arguments )
+         {
+            result = result.Replace( kvp.Key, kvp.Value );
+         }
+         return result;
+      }
+   }
+}

+ 8 - 30
src/XUnity.AutoTranslator.Plugin.Core/Parsing/UnityTextParserBase.cs

@@ -6,15 +6,6 @@ using System.Text;
 
 namespace XUnity.AutoTranslator.Plugin.Core.Parsing
 {
-
-   public class UtageTextParser : UnityTextParserBase
-   {
-      public UtageTextParser()
-      {
-         AddIgnoredTag( "ruby" );
-      }
-   }
-
    public abstract class UnityTextParserBase
    {
       private static readonly HashSet<char> ValidTagNameChars = new HashSet<char>
@@ -29,7 +20,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
 
       }
 
-      public void AddIgnoredTag( string name )
+      protected void AddIgnoredTag( string name )
       {
          _ignored.Add( name );
       }
@@ -202,7 +193,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          return new ParserResult( templateString, args );
       }
 
-      public string TakeAllButLast( StringBuilder builder )
+      private string TakeAllButLast( StringBuilder builder )
       {
          if( builder.Length > 0 )
          {
@@ -213,7 +204,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          return string.Empty;
       }
 
-      public ParsingState ParseText( string s, ref int i )
+      private ParsingState ParseText( string s, ref int i )
       {
          if( s[ i ] == '<' )
          {
@@ -232,7 +223,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          }
       }
 
-      public ParsingState ParseNamingStartTag( string s, ref int i )
+      private ParsingState ParseNamingStartTag( string s, ref int i )
       {
          if( ValidTagNameChars.Contains( s[ i ] ) )
          {
@@ -249,7 +240,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          }
       }
 
-      public ParsingState ParseNamingEndTag( string s, ref int i )
+      private ParsingState ParseNamingEndTag( string s, ref int i )
       {
          if( ValidTagNameChars.Contains( s[ i ] ) )
          {
@@ -266,7 +257,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          }
       }
 
-      public ParsingState ParseFinishingStartTag( string s, ref int i )
+      private ParsingState ParseFinishingStartTag( string s, ref int i )
       {
          if( s[ i ] == '>' )
          {
@@ -278,7 +269,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          }
       }
 
-      public ParsingState ParseFinishingEndTag( string s, ref int i )
+      private ParsingState ParseFinishingEndTag( string s, ref int i )
       {
          if( s[ i ] == '>' )
          {
@@ -290,7 +281,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          }
       }
 
-      public enum ParsingState
+      private enum ParsingState
       {
          Text,
          NamingStartTag,
@@ -299,17 +290,4 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          FinishingEndTag
       }
    }
-
-   public class ParserResult
-   {
-      public ParserResult( string template, Dictionary<string, string> args )
-      {
-         Template = template;
-         Arguments = args;
-      }
-
-      public string Template { get; set; }
-
-      public Dictionary<string, string> Arguments { get; set; }
-   }
 }

+ 22 - 0
src/XUnity.AutoTranslator.Plugin.Core/Parsing/UnityTextParsers.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Parsing
+{
+   public static class UnityTextParsers
+   {
+      private static readonly UtageTextParser UtageTextParser = new UtageTextParser();
+
+      public static UnityTextParserBase GetTextParserByGameEngine()
+      {
+         if( Types.AdvEngine != null )
+         {
+            return UtageTextParser;
+         }
+         return null;
+      }
+   }
+}

+ 10 - 0
src/XUnity.AutoTranslator.Plugin.Core/Parsing/UtageTextParser.cs

@@ -0,0 +1,10 @@
+namespace XUnity.AutoTranslator.Plugin.Core.Parsing
+{
+   public class UtageTextParser : UnityTextParserBase
+   {
+      public UtageTextParser()
+      {
+         AddIgnoredTag( "ruby" );
+      }
+   }
+}

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

@@ -5,6 +5,7 @@ using System.Net;
 using System.Text;
 using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Extensions;
+using XUnity.AutoTranslator.Plugin.Core.Parsing;
 
 namespace XUnity.AutoTranslator.Plugin.Core
 {
@@ -16,16 +17,21 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
          Components = new List<object>();
          OriginalSources = new HashSet<object>();
+         Contexts = new HashSet<TranslationContext>();
       }
 
+      public HashSet<TranslationContext> Contexts { get; private set; }
+
       public List<object> Components { get; private set; }
 
       public HashSet<object> OriginalSources { get; private set; }
-      
+
       public TranslationKey Key { get; private set; }
 
       public string TranslatedText { get; set; }
 
+      public TranslationJobState State { get; set; }
+
       public bool AnyComponentsStillHasOriginalUntranslatedText()
       {
          if( Components.Count == 0 ) return true; // we do not know
@@ -41,5 +47,37 @@ namespace XUnity.AutoTranslator.Plugin.Core
 
          return false;
       }
+
+      public void Associate( TranslationContext context )
+      {
+         if( context != null )
+         {
+            Contexts.Add( context );
+            context.Jobs.Add( this );
+         }
+      }
+   }
+
+   public enum TranslationJobState
+   {
+      RunningOrQueued,
+      Succeeded,
+      Failed
+   }
+
+   public class TranslationContext
+   {
+      public TranslationContext( object component, ParserResult result )
+      {
+         Jobs = new HashSet<TranslationJob>();
+         Component = component;
+         Result = result;
+      }
+
+      public ParserResult Result { get; private set; }
+
+      public HashSet<TranslationJob> Jobs { get; private set; }
+
+      public object Component { get; private set; }
    }
 }

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

@@ -9,11 +9,11 @@ namespace XUnity.AutoTranslator.Plugin.Core
 {
    public struct TranslationKey
    {
-      public TranslationKey( string key, bool templatizeByNumbers )
+      public TranslationKey( string key, bool templatizeByNumbers, bool neverRemoveWhitespace = false )
       {
          OriginalText = key;
 
-         if( Settings.IgnoreWhitespaceInDialogue && key.Length > Settings.MinDialogueChars )
+         if( !neverRemoveWhitespace && Settings.IgnoreWhitespaceInDialogue && key.Length > Settings.MinDialogueChars )
          {
             RelevantText = key.RemoveWhitespace();
          }