|
@@ -89,6 +89,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
/// </summary>
|
|
|
private HashSet<string> _immediatelyTranslating = new HashSet<string>();
|
|
|
|
|
|
+ private Dictionary<string, byte[]> _translatedImages = new Dictionary<string, byte[]>( StringComparer.InvariantCultureIgnoreCase );
|
|
|
+ private HashSet<string> _untranslatedImages = new HashSet<string>();
|
|
|
+
|
|
|
private object _advEngine;
|
|
|
private float? _nextAdvUpdate;
|
|
|
|
|
@@ -99,7 +102,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
private float _translationsQueuedPerSecond;
|
|
|
|
|
|
private bool _isInTranslatedMode = true;
|
|
|
- private bool _hooksEnabled = true;
|
|
|
+ private bool _textHooksEnabled = true;
|
|
|
+ private bool _imageHooksEnabled = true;
|
|
|
private bool _batchLogicHasFailed = false;
|
|
|
|
|
|
private int _availableBatchOperations = Settings.MaxAvailableBatchOperations;
|
|
@@ -144,7 +148,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
if( Settings.EnableConsole ) DebugConsole.Enable();
|
|
|
|
|
|
- HooksSetup.InstallHooks();
|
|
|
+ HooksSetup.InstallTextHooks();
|
|
|
+ HooksSetup.InstallImageHooks();
|
|
|
|
|
|
try
|
|
|
{
|
|
@@ -181,6 +186,18 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
_overrideFont = _hasOverrideFont;
|
|
|
}
|
|
|
|
|
|
+ if( Settings.EnableTextureScanOnSceneLoad && ( Settings.EnableTextureDumping || Settings.EnableTextureTranslation ) )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ EnableSceneLoadScan();
|
|
|
+ }
|
|
|
+ catch( Exception e )
|
|
|
+ {
|
|
|
+ Logger.Current.Error( e, "An error occurred while settings up texture scene-load scans." );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
LoadTranslations();
|
|
|
LoadStaticTranslations();
|
|
|
|
|
@@ -201,6 +218,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
.Select( x => x.Replace( "/", "\\" ) );
|
|
|
}
|
|
|
|
|
|
+ private IEnumerable<string> GetTextureFiles()
|
|
|
+ {
|
|
|
+ return Directory.GetFiles( Path.Combine( Config.Current.DataPath, Settings.TextureDirectory ), $"*.png", SearchOption.AllDirectories )
|
|
|
+ .Select( x => x.Replace( "/", "\\" ) );
|
|
|
+ }
|
|
|
+
|
|
|
private void MaintenanceLoop( object state )
|
|
|
{
|
|
|
while( true )
|
|
@@ -255,6 +278,23 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void EnableSceneLoadScan()
|
|
|
+ {
|
|
|
+ // specified in own method, because of chance that this has changed through Unity lifetime
|
|
|
+ SceneManager.sceneLoaded += SceneManager_SceneLoaded;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void SceneManager_SceneLoaded( Scene scene, LoadSceneMode arg1 )
|
|
|
+ {
|
|
|
+ Logger.Current.Info( "SceneLoading..." );
|
|
|
+ var startTime = Time.realtimeSinceStartup;
|
|
|
+
|
|
|
+ ManualHookForTextures();
|
|
|
+
|
|
|
+ var endTime = Time.realtimeSinceStartup;
|
|
|
+ Logger.Current.Info( $"SceneLoaded (took {Math.Round( endTime - startTime, 2 )} seconds)" );
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Loads the translations found in Translation.{lang}.txt
|
|
|
/// </summary>
|
|
@@ -274,6 +314,17 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
LoadTranslationsInFile( fullFileName );
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation || Settings.EnableTextureDumping )
|
|
|
+ {
|
|
|
+ _translatedImages.Clear();
|
|
|
+ _untranslatedImages.Clear();
|
|
|
+ Directory.CreateDirectory( Path.Combine( Config.Current.DataPath, Settings.TextureDirectory ) );
|
|
|
+ foreach( var fullFileName in GetTextureFiles() )
|
|
|
+ {
|
|
|
+ RegisterImageFromFile( fullFileName );
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
catch( Exception e )
|
|
|
{
|
|
@@ -281,11 +332,117 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void RegisterImageFromFile( string fullFileName )
|
|
|
+ {
|
|
|
+ var fileName = Path.GetFileNameWithoutExtension( fullFileName );
|
|
|
+ var startHash = fileName.LastIndexOf( "[" );
|
|
|
+ var endHash = fileName.LastIndexOf( "]" );
|
|
|
+
|
|
|
+ if( endHash > -1 && startHash > -1 && endHash > startHash )
|
|
|
+ {
|
|
|
+ var takeFrom = startHash + 1;
|
|
|
+
|
|
|
+ // load based on whether or not the key is image hashed
|
|
|
+ var parts = fileName.Substring( takeFrom, endHash - takeFrom ).Split( '-' );
|
|
|
+ string key;
|
|
|
+ string originalHash;
|
|
|
+ if( parts.Length == 1 )
|
|
|
+ {
|
|
|
+ key = parts[ 0 ];
|
|
|
+ originalHash = parts[ 0 ];
|
|
|
+ }
|
|
|
+ else if( parts.Length == 2 )
|
|
|
+ {
|
|
|
+ key = parts[ 0 ];
|
|
|
+ originalHash = parts[ 1 ];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Logger.Current.Warn( $"Image not loaded (unknown hash): {fullFileName}." );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var data = File.ReadAllBytes( fullFileName );
|
|
|
+ var currentHash = HashHelper.Compute( data );
|
|
|
+ var isModified = StringComparer.InvariantCultureIgnoreCase.Compare( originalHash, currentHash ) != 0;
|
|
|
+
|
|
|
+ // only load images that someone has modified!
|
|
|
+ if( Settings.LoadUnmodifiedTextures || isModified )
|
|
|
+ {
|
|
|
+ RegisterTranslatedImage( key, data );
|
|
|
+ Logger.Current.Debug( $"Image loaded: {fullFileName}." );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ RegisterUntranslatedImage( key );
|
|
|
+ Logger.Current.Warn( $"Image not loaded (unmodified): {fullFileName}." );
|
|
|
+ }
|
|
|
+
|
|
|
+ //if( Settings.DeleteUnmodifiedTextures && !isModified )
|
|
|
+ //{
|
|
|
+ // try
|
|
|
+ // {
|
|
|
+ // File.Delete( fullFileName );
|
|
|
+ // Logger.Current.Warn( $"Image deleted (unmodified): {fullFileName}." );
|
|
|
+ // }
|
|
|
+ // catch( Exception e )
|
|
|
+ // {
|
|
|
+ // Logger.Current.Warn( e, $"An error occurred while trying to delete unmodified image: {fullFileName}." );
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Logger.Current.Warn( $"Image not loaded (no hash): {fullFileName}." );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RegisterImageFromData( string textureName, string key, byte[] data )
|
|
|
+ {
|
|
|
+ var name = textureName.SanitizeForFileSystem();
|
|
|
+ var root = Path.Combine( Config.Current.DataPath, Settings.TextureDirectory );
|
|
|
+ var originalHash = HashHelper.Compute( data );
|
|
|
+
|
|
|
+ // allow hash and key to be the same; only store one of them then!
|
|
|
+ string fileName;
|
|
|
+ if( key == originalHash )
|
|
|
+ {
|
|
|
+ fileName = name + " [" + key + "].png";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ fileName = name + " [" + key + "-" + originalHash + "].png";
|
|
|
+ }
|
|
|
+
|
|
|
+ var fullName = Path.Combine( root, fileName );
|
|
|
+ File.WriteAllBytes( fullName, data );
|
|
|
+ Logger.Current.Info( "Dumped texture file: " + fileName );
|
|
|
+
|
|
|
+ if( Settings.LoadUnmodifiedTextures )
|
|
|
+ {
|
|
|
+ RegisterTranslatedImage( key, data );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ RegisterUntranslatedImage( key );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RegisterTranslatedImage( string key, byte[] data )
|
|
|
+ {
|
|
|
+ _translatedImages[ key ] = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RegisterUntranslatedImage( string key )
|
|
|
+ {
|
|
|
+ _untranslatedImages.Add( key );
|
|
|
+ }
|
|
|
+
|
|
|
private void LoadTranslationsInFile( string fullFileName )
|
|
|
{
|
|
|
if( File.Exists( fullFileName ) )
|
|
|
{
|
|
|
- Logger.Current.Debug( $"Loading translations from {fullFileName}." );
|
|
|
+ Logger.Current.Debug( $"Loading texts: {fullFileName}." );
|
|
|
|
|
|
string[] translations = File.ReadAllLines( fullFileName, Encoding.UTF8 );
|
|
|
foreach( string translation in translations )
|
|
@@ -584,6 +741,16 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private bool IsImageRegistered( string key )
|
|
|
+ {
|
|
|
+ return _translatedImages.ContainsKey( key ) || _untranslatedImages.Contains( key );
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool TryGetTranslatedImage( string key, out byte[] data )
|
|
|
+ {
|
|
|
+ return _translatedImages.TryGetValue( key, out data );
|
|
|
+ }
|
|
|
+
|
|
|
private void AddTranslation( string key, string value )
|
|
|
{
|
|
|
_translations[ key ] = value;
|
|
@@ -663,9 +830,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
public string Hook_TextChanged_WithResult( object ui, string text )
|
|
|
{
|
|
|
- if( !ui.IsKnownType() ) return null;
|
|
|
+ if( !ui.IsKnownTextType() ) return null;
|
|
|
|
|
|
- if( _hooksEnabled && !_temporarilyDisabled )
|
|
|
+ if( _textHooksEnabled && !_temporarilyDisabled )
|
|
|
{
|
|
|
return TranslateOrQueueWebJob( ui, text, false );
|
|
|
}
|
|
@@ -674,9 +841,9 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
public string ExternalHook_TextChanged_WithResult( object ui, string text )
|
|
|
{
|
|
|
- if( !ui.IsKnownType() ) return null;
|
|
|
+ if( !ui.IsKnownTextType() ) return null;
|
|
|
|
|
|
- if( _hooksEnabled && !_temporarilyDisabled )
|
|
|
+ if( _textHooksEnabled && !_temporarilyDisabled )
|
|
|
{
|
|
|
return TranslateOrQueueWebJob( ui, text, true );
|
|
|
}
|
|
@@ -685,13 +852,29 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
public void Hook_TextChanged( object ui )
|
|
|
{
|
|
|
- if( _hooksEnabled && !_temporarilyDisabled )
|
|
|
+ if( _textHooksEnabled && !_temporarilyDisabled )
|
|
|
{
|
|
|
TranslateOrQueueWebJob( ui, null, false );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void SetTranslatedText( object ui, string translatedText, TranslationInfo info )
|
|
|
+ public void Hook_ImageChangedOnComponent( object source, Texture2D texture = null, bool isPrefixHooked = false )
|
|
|
+ {
|
|
|
+ if( !_imageHooksEnabled ) return;
|
|
|
+ if( !source.IsKnownImageType() ) return;
|
|
|
+
|
|
|
+ HandleImage( source, texture, isPrefixHooked );
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Hook_ImageChanged( Texture2D texture, bool isPrefixHooked = false )
|
|
|
+ {
|
|
|
+ if( !_imageHooksEnabled ) return;
|
|
|
+ if( texture == null ) return;
|
|
|
+
|
|
|
+ HandleImage( null, texture, isPrefixHooked );
|
|
|
+ }
|
|
|
+
|
|
|
+ private void SetTranslatedText( object ui, string translatedText, TextTranslationInfo info )
|
|
|
{
|
|
|
info?.SetTranslatedText( translatedText );
|
|
|
|
|
@@ -705,7 +888,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
{
|
|
|
if( _hasOverrideFont )
|
|
|
{
|
|
|
- var info = ui.GetTranslationInfo();
|
|
|
+ var info = ui.GetTextTranslationInfo();
|
|
|
if( _overrideFont )
|
|
|
{
|
|
|
info?.ChangeFont( ui );
|
|
@@ -718,12 +901,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
if( Settings.ForceUIResizing )
|
|
|
{
|
|
|
- var info = ui.GetTranslationInfo();
|
|
|
+ var info = ui.GetTextTranslationInfo();
|
|
|
if( info?.IsCurrentlySettingText == false )
|
|
|
{
|
|
|
// force UI resizing is highly problematic for NGUI because text should somehow
|
|
|
// be set after changing "resize" properties... brilliant stuff
|
|
|
- if( ui.GetType() != Constants.Types.UILabel )
|
|
|
+ if( ui.GetType() != ClrTypes.UILabel )
|
|
|
{
|
|
|
info?.ResizeUI( ui );
|
|
|
}
|
|
@@ -734,13 +917,13 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
/// <summary>
|
|
|
/// Sets the text of a UI text, while ensuring this will not fire a text changed event.
|
|
|
/// </summary>
|
|
|
- private void SetText( object ui, string text, bool isTranslated, TranslationInfo info )
|
|
|
+ private void SetText( object ui, string text, bool isTranslated, TextTranslationInfo info )
|
|
|
{
|
|
|
if( !info?.IsCurrentlySettingText ?? true )
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- _hooksEnabled = false;
|
|
|
+ _textHooksEnabled = false;
|
|
|
|
|
|
if( info != null )
|
|
|
{
|
|
@@ -778,7 +961,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
- _hooksEnabled = true;
|
|
|
+ _textHooksEnabled = true;
|
|
|
|
|
|
if( info != null )
|
|
|
{
|
|
@@ -801,7 +984,30 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
return str.Length <= ( Settings.MaxCharactersPerTranslation / 2 );
|
|
|
}
|
|
|
|
|
|
- public bool ShouldTranslate( object ui, bool ignoreComponentState )
|
|
|
+ public bool ShouldTranslateImageComponent( object ui )
|
|
|
+ {
|
|
|
+ var component = ui as Component;
|
|
|
+ if( component != null )
|
|
|
+ {
|
|
|
+ // dummy check
|
|
|
+ var go = component.gameObject;
|
|
|
+ var ignore = go.HasIgnoredName();
|
|
|
+ if( ignore )
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ var behaviour = component as Behaviour;
|
|
|
+ if( behaviour?.isActiveAndEnabled == false )
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool ShouldTranslateTextComponent( object ui, bool ignoreComponentState )
|
|
|
{
|
|
|
var component = ui as Component;
|
|
|
if( component != null )
|
|
@@ -823,8 +1029,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var inputField = component.gameObject.GetFirstComponentInSelfOrAncestor( Constants.Types.InputField )
|
|
|
- ?? component.gameObject.GetFirstComponentInSelfOrAncestor( Constants.Types.TMP_InputField );
|
|
|
+ var inputField = component.gameObject.GetFirstComponentInSelfOrAncestor( ClrTypes.InputField )
|
|
|
+ ?? component.gameObject.GetFirstComponentInSelfOrAncestor( ClrTypes.TMP_InputField );
|
|
|
|
|
|
return inputField == null;
|
|
|
}
|
|
@@ -834,7 +1040,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
private string TranslateOrQueueWebJob( object ui, string text, bool ignoreComponentState )
|
|
|
{
|
|
|
- var info = ui.GetTranslationInfo();
|
|
|
+ var info = ui.GetTextTranslationInfo();
|
|
|
|
|
|
if( _ongoingOperations.Contains( ui ) )
|
|
|
{
|
|
@@ -858,19 +1064,248 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- public static bool IsCurrentlySetting( TranslationInfo info )
|
|
|
+ public static bool IsCurrentlySetting( TextTranslationInfo info )
|
|
|
{
|
|
|
if( info == null ) return false;
|
|
|
|
|
|
return info.IsCurrentlySettingText;
|
|
|
}
|
|
|
|
|
|
- private string TranslateImmediate( object ui, string text, TranslationInfo info, bool ignoreComponentState )
|
|
|
+ private void HandleImage( object source, Texture2D texture, bool isPrefixHooked )
|
|
|
+ {
|
|
|
+ if( Settings.EnableTextureDumping )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ DumpTexture( source, texture );
|
|
|
+ }
|
|
|
+ catch( Exception e )
|
|
|
+ {
|
|
|
+ Logger.Current.Error( e, "An error occurred while dumping texture." );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ TranslateTexture( source, texture, isPrefixHooked, false );
|
|
|
+ }
|
|
|
+ catch( Exception e )
|
|
|
+ {
|
|
|
+ Logger.Current.Error( e, "An error occurred while translating texture." );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void TranslateTexture( object ui, bool forceReload )
|
|
|
+ {
|
|
|
+ if( ui is Texture2D texture2d )
|
|
|
+ {
|
|
|
+ TranslateTexture( null, texture2d, false, forceReload );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TranslateTexture( ui, null, false, forceReload );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void TranslateTexture( object source, Texture2D texture, bool isPrefixHooked, bool forceReload )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _imageHooksEnabled = false;
|
|
|
+
|
|
|
+ texture = texture ?? source.GetTexture();
|
|
|
+ if( texture == null ) return;
|
|
|
+
|
|
|
+ var tti = texture.GetTextureTranslationInfo();
|
|
|
+ var iti = source.GetImageTranslationInfo();
|
|
|
+ var key = tti.GetKey( texture );
|
|
|
+ if( string.IsNullOrEmpty( key ) ) return;
|
|
|
+
|
|
|
+ if( TryGetTranslatedImage( key, out var newData ) )
|
|
|
+ {
|
|
|
+ if( _isInTranslatedMode )
|
|
|
+ {
|
|
|
+ // handle texture
|
|
|
+ if( !tti.IsTranslated || forceReload )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ texture.LoadImageEx( newData, tti.IsNonReadable( texture ) );
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ tti.IsTranslated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle containing component
|
|
|
+ if( iti != null )
|
|
|
+ {
|
|
|
+ if( !iti.IsTranslated || forceReload )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if( !isPrefixHooked )
|
|
|
+ {
|
|
|
+ source.SetAllDirtyEx();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ iti.IsTranslated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // if we cannot find the texture, and the texture is considered translated... hmmm someone has removed a file
|
|
|
+
|
|
|
+ // handle texture
|
|
|
+ var originalData = tti.GetOriginalData( texture );
|
|
|
+ if( originalData != null )
|
|
|
+ {
|
|
|
+ if( tti.IsTranslated )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ texture.LoadImageEx( originalData, tti.IsNonReadable( texture ) );
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ tti.IsTranslated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle containing component
|
|
|
+ if( iti != null )
|
|
|
+ {
|
|
|
+ if( iti.IsTranslated )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if( !isPrefixHooked )
|
|
|
+ {
|
|
|
+ source.SetAllDirtyEx();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ iti.IsTranslated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if( !_isInTranslatedMode )
|
|
|
+ {
|
|
|
+ var originalData = tti.GetOriginalData( texture );
|
|
|
+ if( originalData != null )
|
|
|
+ {
|
|
|
+ // handle texture
|
|
|
+ if( tti.IsTranslated )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ texture.LoadImageEx( originalData, tti.IsNonReadable( texture ) );
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ tti.IsTranslated = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // handle containing component
|
|
|
+ if( iti != null )
|
|
|
+ {
|
|
|
+ if( iti.IsTranslated )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if( !isPrefixHooked )
|
|
|
+ {
|
|
|
+ source.SetAllDirtyEx();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ iti.IsTranslated = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ _imageHooksEnabled = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void DumpTexture( object source, Texture2D texture )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _imageHooksEnabled = false;
|
|
|
+
|
|
|
+ texture = texture ?? source.GetTexture();
|
|
|
+ if( texture == null ) return;
|
|
|
+
|
|
|
+ var info = texture.GetTextureTranslationInfo();
|
|
|
+ if( info.HasDumpedAlternativeTexture ) return;
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if( ShouldTranslate( texture ) )
|
|
|
+ {
|
|
|
+ var key = info.GetKey( texture );
|
|
|
+ if( string.IsNullOrEmpty( key ) ) return;
|
|
|
+
|
|
|
+ if( !IsImageRegistered( key ) )
|
|
|
+ {
|
|
|
+ var name = texture.GetTextureName();
|
|
|
+ //var format = "[" + texture.format.ToString() + "] ";
|
|
|
+
|
|
|
+ var originalData = info.GetOrCreateOriginalData( texture );
|
|
|
+ RegisterImageFromData( name, key, originalData );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ info.HasDumpedAlternativeTexture = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ _imageHooksEnabled = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool ShouldTranslate( Texture2D texture )
|
|
|
+ {
|
|
|
+ // convert to int so engine versions that does not have specific enums still work
|
|
|
+ var format = (int)texture.format;
|
|
|
+
|
|
|
+ // 1 = Alpha8
|
|
|
+ // 9 = R16
|
|
|
+ // 63 = R8
|
|
|
+ return format != 1
|
|
|
+ && format != 9
|
|
|
+ && format != 63;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string TranslateImmediate( object ui, string text, TextTranslationInfo info, bool ignoreComponentState )
|
|
|
{
|
|
|
// Get the trimmed text
|
|
|
text = ( text ?? ui.GetText() ).TrimIfConfigured();
|
|
|
|
|
|
- if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslate( ui, ignoreComponentState ) && !IsCurrentlySetting( info ) )
|
|
|
+ if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslateTextComponent( ui, ignoreComponentState ) && !IsCurrentlySetting( info ) )
|
|
|
{
|
|
|
info?.Reset( text );
|
|
|
|
|
@@ -895,22 +1330,23 @@ 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, bool ignoreComponentState, TranslationContext context = null )
|
|
|
+ private string TranslateOrQueueWebJobImmediate( object ui, string text, TextTranslationInfo info, bool supportsStabilization, bool ignoreComponentState, TranslationContext context = null )
|
|
|
{
|
|
|
+ text = text ?? ui.GetText();
|
|
|
+
|
|
|
// make sure text exists
|
|
|
var originalText = text;
|
|
|
- text = text ?? ui.GetText();
|
|
|
if( context == null )
|
|
|
{
|
|
|
// Get the trimmed text
|
|
|
text = text.TrimIfConfigured();
|
|
|
}
|
|
|
|
|
|
- //Logger.Current.Debug( ui.GetType().Name + ": " + text );
|
|
|
-
|
|
|
// Ensure that we actually want to translate this text and its owning UI element.
|
|
|
- if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslate( ui, ignoreComponentState ) && !IsCurrentlySetting( info ) )
|
|
|
+ if( !string.IsNullOrEmpty( text ) && IsTranslatable( text ) && ShouldTranslateTextComponent( ui, ignoreComponentState ) && !IsCurrentlySetting( info ) )
|
|
|
{
|
|
|
+ //Logger.Current.Debug( "START: " + ui.GetType().Name + ": " + text );
|
|
|
+
|
|
|
info?.Reset( originalText );
|
|
|
var isSpammer = ui.IsSpammingComponent();
|
|
|
var textKey = new TranslationKey( ui, text, isSpammer, context != null );
|
|
@@ -986,11 +1422,11 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
{
|
|
|
_ongoingOperations.Remove( ui );
|
|
|
|
|
|
+ originalText = stabilizedText;
|
|
|
+ stabilizedText = stabilizedText.TrimIfConfigured();
|
|
|
+
|
|
|
if( !string.IsNullOrEmpty( stabilizedText ) && IsTranslatable( stabilizedText ) )
|
|
|
{
|
|
|
- originalText = stabilizedText;
|
|
|
- stabilizedText = stabilizedText.TrimIfConfigured();
|
|
|
-
|
|
|
var stabilizedTextKey = new TranslationKey( ui, stabilizedText, false );
|
|
|
|
|
|
QueueNewUntranslatedForClipboard( stabilizedTextKey );
|
|
@@ -1158,6 +1594,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
yield return new WaitForSeconds( delay );
|
|
|
var afterText = ui.GetText();
|
|
|
|
|
|
+ //Logger.Current.Debug( "WAITING: " + ui.GetType().Name + ": " + afterText );
|
|
|
+
|
|
|
if( beforeText == afterText )
|
|
|
{
|
|
|
onTextStabilized( afterText );
|
|
@@ -1228,7 +1666,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
onContinue();
|
|
|
}
|
|
|
|
|
|
- public void Start()
|
|
|
+ public void Awake()
|
|
|
{
|
|
|
if( !_initialized )
|
|
|
{
|
|
@@ -1246,6 +1684,18 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void Start()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ HooksSetup.InstallOverrideTextHooks();
|
|
|
+ }
|
|
|
+ catch( Exception e )
|
|
|
+ {
|
|
|
+ Logger.Current.Error( e, "An unexpected error occurred during plugin start." );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public void Update()
|
|
|
{
|
|
|
try
|
|
@@ -1529,7 +1979,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
var text = component.GetText().TrimIfConfigured();
|
|
|
if( text == job.Key.OriginalText )
|
|
|
{
|
|
|
- var info = component.GetTranslationInfo();
|
|
|
+ var info = component.GetTextTranslationInfo();
|
|
|
SetTranslatedText( component, job.TranslatedText, info );
|
|
|
}
|
|
|
}
|
|
@@ -1565,7 +2015,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
{
|
|
|
if( translatedText != null )
|
|
|
{
|
|
|
- var info = context.Component.GetTranslationInfo();
|
|
|
+ var info = context.Component.GetTextTranslationInfo();
|
|
|
SetTranslatedText( context.Component, translatedText, info );
|
|
|
}
|
|
|
}
|
|
@@ -1580,8 +2030,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
|
|
|
// Utage support
|
|
|
- if( Constants.Types.AdvEngine != null
|
|
|
- && job.OriginalSources.Any( x => Constants.Types.AdvCommand.IsAssignableFrom( x.GetType() ) ) )
|
|
|
+ if( ClrTypes.AdvEngine != null
|
|
|
+ && job.OriginalSources.Any( x => ClrTypes.AdvCommand.IsAssignableFrom( x.GetType() ) ) )
|
|
|
{
|
|
|
_nextAdvUpdate = Time.time + 0.5f;
|
|
|
}
|
|
@@ -1593,12 +2043,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
{
|
|
|
if( _advEngine == null )
|
|
|
{
|
|
|
- _advEngine = GameObject.FindObjectOfType( Constants.Types.AdvEngine );
|
|
|
+ _advEngine = GameObject.FindObjectOfType( Constants.ClrTypes.AdvEngine );
|
|
|
}
|
|
|
|
|
|
if( _advEngine != null )
|
|
|
{
|
|
|
- AccessTools.Method( Constants.Types.AdvEngine, "ChangeLanguage" )?.Invoke( _advEngine, new object[ 0 ] );
|
|
|
+ AccessTools.Method( Constants.ClrTypes.AdvEngine, "ChangeLanguage" )?.Invoke( _advEngine, new object[ 0 ] );
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1608,15 +2058,35 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
foreach( var kvp in ObjectExtensions.GetAllRegisteredObjects() )
|
|
|
{
|
|
|
- var info = kvp.Value as TranslationInfo;
|
|
|
- if( info != null && !string.IsNullOrEmpty( info.OriginalText ) )
|
|
|
+ var ui = kvp.Key;
|
|
|
+ try
|
|
|
{
|
|
|
- var key = new TranslationKey( kvp.Key, info.OriginalText, false );
|
|
|
- if( TryGetTranslation( key, out string translatedText ) && !string.IsNullOrEmpty( translatedText ) )
|
|
|
+ if( ui is Component component )
|
|
|
{
|
|
|
- SetTranslatedText( kvp.Key, translatedText, info ); // no need to untemplatize the translated text
|
|
|
+ if( component.gameObject?.activeSelf ?? false )
|
|
|
+ {
|
|
|
+ var tti = kvp.Value as TextTranslationInfo;
|
|
|
+ if( tti != null && !string.IsNullOrEmpty( tti.OriginalText ) )
|
|
|
+ {
|
|
|
+ var key = new TranslationKey( kvp.Key, tti.OriginalText, false );
|
|
|
+ if( TryGetTranslation( key, out string translatedText ) && !string.IsNullOrEmpty( translatedText ) )
|
|
|
+ {
|
|
|
+ SetTranslatedText( kvp.Key, translatedText, tti ); // no need to untemplatize the translated text
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation )
|
|
|
+ {
|
|
|
+ TranslateTexture( ui, true );
|
|
|
}
|
|
|
}
|
|
|
+ catch( Exception )
|
|
|
+ {
|
|
|
+ // not super pretty, no...
|
|
|
+ ObjectExtensions.Remove( ui );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1666,19 +2136,22 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
// make sure we use the translated version of all texts
|
|
|
foreach( var kvp in objects )
|
|
|
{
|
|
|
- var ui = kvp.Key;
|
|
|
- try
|
|
|
+ var tti = kvp.Value as TextTranslationInfo;
|
|
|
+ if( tti != null )
|
|
|
{
|
|
|
- if( ( ui as Component )?.gameObject?.activeSelf ?? false )
|
|
|
+ var ui = kvp.Key;
|
|
|
+ try
|
|
|
{
|
|
|
- var info = (TranslationInfo)kvp.Value;
|
|
|
- info?.ChangeFont( ui );
|
|
|
+ if( ( ui as Component )?.gameObject?.activeSelf ?? false )
|
|
|
+ {
|
|
|
+ tti?.ChangeFont( ui );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch( Exception )
|
|
|
+ {
|
|
|
+ // not super pretty, no...
|
|
|
+ ObjectExtensions.Remove( ui );
|
|
|
}
|
|
|
- }
|
|
|
- catch( Exception )
|
|
|
- {
|
|
|
- // not super pretty, no...
|
|
|
- ObjectExtensions.Remove( ui );
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1687,13 +2160,13 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
// make sure we use the original version of all texts
|
|
|
foreach( var kvp in objects )
|
|
|
{
|
|
|
+ var tti = kvp.Value as TextTranslationInfo;
|
|
|
var ui = kvp.Key;
|
|
|
try
|
|
|
{
|
|
|
if( ( ui as Component )?.gameObject?.activeSelf ?? false )
|
|
|
{
|
|
|
- var info = (TranslationInfo)kvp.Value;
|
|
|
- info?.UnchangeFont( ui );
|
|
|
+ tti?.UnchangeFont( ui );
|
|
|
}
|
|
|
}
|
|
|
catch( Exception )
|
|
@@ -1713,6 +2186,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
|
|
|
Logger.Current.Info( $"Toggling translations of {objects.Count} objects." );
|
|
|
|
|
|
+ // FIXME: Translate TEXTURES first??? Problem if texture is not related to a component!
|
|
|
+
|
|
|
if( _isInTranslatedMode )
|
|
|
{
|
|
|
// make sure we use the translated version of all texts
|
|
@@ -1721,15 +2196,22 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
var ui = kvp.Key;
|
|
|
try
|
|
|
{
|
|
|
- if( ( ui as Component )?.gameObject?.activeSelf ?? false )
|
|
|
+ if( ui is Component component )
|
|
|
{
|
|
|
- var info = (TranslationInfo)kvp.Value;
|
|
|
-
|
|
|
- if( info != null && info.IsTranslated )
|
|
|
+ if( component.gameObject?.activeSelf ?? false )
|
|
|
{
|
|
|
- SetText( ui, info.TranslatedText, true, info );
|
|
|
+ var tti = kvp.Value as TextTranslationInfo;
|
|
|
+ if( tti != null && tti.IsTranslated )
|
|
|
+ {
|
|
|
+ SetText( ui, tti.TranslatedText, true, tti );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation && Settings.EnableTextureToggling )
|
|
|
+ {
|
|
|
+ TranslateTexture( ui, false );
|
|
|
+ }
|
|
|
}
|
|
|
catch( Exception )
|
|
|
{
|
|
@@ -1746,15 +2228,22 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
var ui = kvp.Key;
|
|
|
try
|
|
|
{
|
|
|
- if( ( ui as Component )?.gameObject?.activeSelf ?? false )
|
|
|
+ if( ui is Component component )
|
|
|
{
|
|
|
- var info = (TranslationInfo)kvp.Value;
|
|
|
-
|
|
|
- if( info != null && info.IsTranslated )
|
|
|
+ if( component.gameObject?.activeSelf ?? false )
|
|
|
{
|
|
|
- SetText( ui, info.OriginalText, true, info );
|
|
|
+ var tti = kvp.Value as TextTranslationInfo;
|
|
|
+ if( tti != null && tti.IsTranslated )
|
|
|
+ {
|
|
|
+ SetText( ui, tti.OriginalText, true, tti );
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation && Settings.EnableTextureToggling )
|
|
|
+ {
|
|
|
+ TranslateTexture( ui, false );
|
|
|
+ }
|
|
|
}
|
|
|
catch( Exception )
|
|
|
{
|
|
@@ -1815,6 +2304,12 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
|
|
|
private void ManualHook()
|
|
|
+ {
|
|
|
+ ManualHookForComponents();
|
|
|
+ ManualHookForTextures();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ManualHookForComponents()
|
|
|
{
|
|
|
foreach( var root in GetAllRoots() )
|
|
|
{
|
|
@@ -1822,6 +2317,26 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void ManualHookForTextures()
|
|
|
+ {
|
|
|
+ if( Settings.EnableTextureScanOnSceneLoad && ( Settings.EnableTextureTranslation || Settings.EnableTextureDumping ) )
|
|
|
+ {
|
|
|
+ // scan all textures and update
|
|
|
+ var textures = Resources.FindObjectsOfTypeAll<Texture2D>();
|
|
|
+ foreach( var texture in textures )
|
|
|
+ {
|
|
|
+ Hook_ImageChanged( texture );
|
|
|
+ }
|
|
|
+
|
|
|
+ //// scan all components and set dirty
|
|
|
+ //var components = GameObject.FindObjectsOfType<Component>();
|
|
|
+ //foreach( var component in components )
|
|
|
+ //{
|
|
|
+ // component.SetAllDirtyEx();
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private IEnumerable<GameObject> GetAllRoots()
|
|
|
{
|
|
|
var objects = GameObject.FindObjectsOfType<GameObject>();
|
|
@@ -1864,10 +2379,18 @@ namespace XUnity.AutoTranslator.Plugin.Core
|
|
|
var components = obj.GetComponents<Component>();
|
|
|
foreach( var component in components )
|
|
|
{
|
|
|
- if( component.IsKnownType() )
|
|
|
+ if( component.IsKnownTextType() )
|
|
|
{
|
|
|
Hook_TextChanged( component );
|
|
|
}
|
|
|
+
|
|
|
+ if( Settings.EnableTextureTranslation || Settings.EnableTextureDumping )
|
|
|
+ {
|
|
|
+ if( component.IsKnownImageType() )
|
|
|
+ {
|
|
|
+ Hook_ImageChangedOnComponent( component );
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if( obj.transform != null )
|