|
6 жил өмнө | |
---|---|---|
libs | 6 жил өмнө | |
src | 6 жил өмнө | |
.editorconfig | 6 жил өмнө | |
.gitattributes | 7 жил өмнө | |
.gitignore | 7 жил өмнө | |
CHANGELOG.md | 6 жил өмнө | |
LICENSE | 7 жил өмнө | |
README.md | 6 жил өмнө | |
XUnity.AutoTranslator.sln | 6 жил өмнө |
# XUnity Auto Translator
This is a plugin that is capable of using various online translators to provide on-the-fly translations for various Unity-based games.
It does (obviously) go to the internet, in order to provide the translation, so if you are not comfortable with that, don't use it.
Oh, and it is also capable of doing some basic image loading/dumping. Go to the Texture Translation section to find out more.
If you intend on redistributing this plugin as part of a translation suite for a game, please read this section.
The supported online translators are:
Do note that if you use any of the online translators that does not require some form of authentication, that this plugin may break at any time.
Since 3.0.0, you can also implement your own translators. To do so, follow the instruction here.
If you decide to use an authenticated service do not ever share your key or secret. If you do so by accident, you should revoke it immediately. Most, if not all services provides an option for this.
Also, make sure you monitor the service's request usage/quotas, especially when it is being used with unknown games. This plugin makes no guarantees about how many translation requests will be sent out, although it will attempt to keep the number to a minimum. It does so by using the spam prevention mechanisms discussed below.
The plugin employs the following spam prevention mechanisms:
The following text frameworks are supported.
The mod can be installed into the following Plugin Managers:
Installation instructions for all methods can be found below.
Additionally it can be installed without a dependency on a plugin manager through ReiPatcher. However, this approach is not recommended if you use one of the above mentioned Plugin Managers!
The default configuration file, looks as such (2.6.0+):
[Service]
Endpoint=GoogleTranslate ;Endpoint to use. Can be ["GoogleTranslate", "GoogleTranslateLegitimate", "BingTranslateLegitimate", "BaiduTranslate", "YandexTranslate", "WatsonTranslate", "ExciteTranslate", "*any custom http endpoint*", ""]. If empty, it simply means: Only use cached translations
[General]
Language=en ;The language to translate into
FromLanguage=ja ;The original language of the game
[Files]
Directory=Translation ;Directory to search for cached translation files
OutputFile=Translation\_AutoGeneratedTranslations.{lang}.txt ;File to insert generated translations into
[TextFrameworks]
EnableUGUI=True ;Enable or disable UGUI translation
EnableNGUI=True ;Enable or disable NGUI translation
EnableTextMeshPro=True ;Enable or disable TextMeshPro translation
EnableIMGUI=False ;Enable or disable IMGUI translation
EnableUtage=True ;Enable or disable Utage-specific translation
AllowPluginHookOverride=True ;Allow other text translation plugins to override this plugin's hooks
[Behaviour]
Delay=0 ;Delay to wait before attempting to translate a text in seconds
MaxCharactersPerTranslation=200 ;Max characters per text to translate. Max 500.
IgnoreWhitespaceInDialogue=True ;Whether or not to ignore whitespace, including newlines, in dialogue keys
IgnoreWhitespaceInNGUI=True ;Whether or not to ignore whitespace, including newlines, in NGUI
MinDialogueChars=20 ;The length of the text for it to be considered a dialogue
ForceSplitTextAfterCharacters=0 ;Split text into multiple lines once the translated text exceeds this number of characters
CopyToClipboard=False ;Whether or not to copy hooked texts to clipboard
MaxClipboardCopyCharacters=450 ;Max number of characters to hook to clipboard at a time
EnableUIResizing=True ;Whether or not the plugin should provide a "best attempt" at resizing UI components upon translation. Only work for NGUI
EnableBatching=True ;Indicates whether batching of translations should be enabled for supported endpoints
TrimAllText=True ;Indicates whether spaces in front and behind translation candidates should be removed before translation
UseStaticTranslations=True ;Indicates whether or not to use translations from the included static translation cache
OverrideFont= ;Overrides the fonts used for texts when updating text components. NOTE: Only works for UGUI
WhitespaceRemovalStrategy=TrimPerNewline ;Indicates how whitespace/newline removal should be handled before attempting translation. Can be ["TrimPerNewline", "AllOccurrences"]
ResizeUILineSpacingScale= ;A decimal value that the default line spacing should be scaled by during UI resizing, for example: 0.80. NOTE: Only works for UGUI
ForceUIResizing=True ;Indicates whether the UI resize behavior should be applied to all UI components regardless of them being translated.
IgnoreTextStartingWith=\u180e; ;Indicates that the plugin should ignore any strings starting with certain characters. This is a list seperated by ';'.
TextGetterCompatibilityMode=False ;Indicates whether or not to enable "Text Getter Compatibility Mode". Should only be enabled if required by the game.
[Texture]
TextureDirectory=Translation\Texture ;Directory to dump textures to, and root of directories to load images from
EnableTextureTranslation=False ;Indicates whether the plugin will attempt to replace in-game images with those from the TextureDirectory directory
EnableTextureDumping=False ;Indicates whether the plugin will dump texture it is capable of replacing to the TextureDirectory. Has significant performance impact
EnableTextureToggling=False ;Indicates whether or not toggling the translation with the ALT+T hotkey will also affect textures. Not guaranteed to work for all textures. Has significant performance impact
EnableTextureScanOnSceneLoad=False ;Indicates whether or not the plugin should scan for textures on scene load. This enables the plugin to find and (possibly) replace more texture
EnableSpriteRendererHooking=False ;Indicates whether or not the plugin should attempt to hook SpriteRenderer. This is a seperate option because SpriteRenderer can't actually be hooked properly and the implemented workaround could have a theoretical impact on performance in certain situations
LoadUnmodifiedTextures=False ;Indicates whether or not unmodified textures should be loaded. Modifications are determined based on the hash in the file name. Only enable this for debugging purposes as it is likely to cause oddities
TextureHashGenerationStrategy=FromImageName ;Indicates how the mod identifies pictures through hashes. Can be ["FromImageName", "FromImageData", "FromImageNameAndScene"]
[Http]
UserAgent= ;Override the user agent used by APIs requiring a user agent
[GoogleLegitimate]
GoogleAPIKey= ;OPTIONAL, needed if GoogleTranslateLegitimate is configured
[BingLegitimate]
OcpApimSubscriptionKey= ;OPTIONAL, needed if BingTranslateLegitimate is configured
[Baidu]
BaiduAppId= ;OPTIONAL, needed if BaiduTranslate is configured
BaiduAppSecret= ;OPTIONAL, needed if BaiduTranslate is configured
[Yandex]
YandexAPIKey= ;OPTIONAL, needed if YandexTranslate is configured
[Watson]
WatsonAPIUrl= ;OPTIONAL, needed if WatsonTranslate is configured
WatsonAPIUsername= ;OPTIONAL, needed if WatsonTranslate is configured
WatsonAPIPassword= ;OPTIONAL, needed if WatsonTranslate is configured
[Debug]
EnablePrintHierarchy=False ;Used for debugging
EnableConsole=False ;Enables the console. Do not enable if other plugins (managers) handles this
EnableLog=False ;Enables extra logging for debugging purposes
[Migrations]
Enable=True ;Used to enable automatic migrations of this configuration file
Tag=2.9.0 ;Tag representing the last version this plugin was executed under. Do not edit
When it comes to automated translations, proper whitespace handling can really make or break the translation. The parameters that control whitespace handling are:
IgnoreWhitespaceInDialogue
IgnoreWhitespaceInNGUI
MinDialogueChars
ForceSplitTextAfterCharacters
TrimAllText
WhitespaceRemovalStrategy
The first thing the plugin does when it discovers a new text is trim any whitespace, if TrimAllText
is configured. This does not include newlines or "special" whitespace such as japanese whitespace.
After this initial trimming, the plugin determines whether or not it should perform a special whitespace removal operation. How it removes the whitespace is based on the parameter WhitespaceRemomvalStrategy
. The default value of this parameter is recommended. The other value (AllOccurrences) is only kept for legacy reasons.
It determine whether or not to perform this operation based on the parameters IgnoreWhitespaceInDialogue
, IgnoreWhitespaceInNGUI
and MinDialogueChars
:
IgnoreWhitespaceInDialogue
: If the text is longer than MinDialogueChars
, whitespace is removed.IgnoreWhitespaceInNGUI
: If the text comes from an NGUI component, whitespace is removed.After the text has been translated by the configured service, ForceSplitTextAfterCharacters
is used to determine if the plugin should force the result into multiple lines after a certain number of characters.
The main reason that this type of handling can make or break a translation really comes down to whether or not whitespace is removed from the source text before sending it to the endpoint. Most endpoints (such as GoogleTranslate) consider text on multiple lines seperately, which can often result in terrible translation if an unnecessary newline is included.
Often when performing a translation on a text component, the resulting text is larger than the original. This often means that there is not enough room in the text component for the result. This section describes ways to remedy that by changing important parameters of the text components.
The important parameters in relation to this are EnableUIResizing
, ResizeUILineSpacingScale
, ForceUIResizing
and OverrideFont
.
EnableUIResizing
: Resizes the components when a translation is performed.ForceUIResizing
: Resizes all components at all times, period.ResizeUILineSpacingScale
: Changes the line spacing of resized components. UGUI only.OverrideFont
: Changes the font of all text components regardless of EnableUIResizing
and ForceUIResizing
. UGUI only.Resizing of a UI component does not refer to changing of it's dimensions, but rather how the component handles overflow. The plugin changes the overflow parameters such that text is more likely to be displayed.
The following aims at reducing the number of requests send to the translation endpoint:
EnableBatching
: Batches several translation requests into a single with supported endpoints (Only GoogleTranslate and GoogleTranslateLegitimate at the moment)UseStaticTranslations
: Enables usage of internal lookup dictionary of various english-to-japanese terms.MaxCharactersPerTranslation
: Specifies the maximum length of a text to translate. Any texts longer than this is ignored by the plugin. Cannot be greater than 500.TextGetterCompatibilityMode
: This mode fools the game into thinking that the text displayed is not translated. This is required if the game uses text displayed to the user to determine what logic to execute. You can easily determine if this is required if you can see the functionality works fine if you toggle the translation off (hotkey: ALT+T).IgnoreTextStartingWith
: Disable translation for any texts starting with values in this ';-separated' setting. The default value is an invisible character that takes up no space.CopyToClipboard
: Copy text to translate to the clipboard to support tools such as Translation Aggregator.Delay
: Required delay from a text appears until a translation request is queued in seconds. IMGUI not supported.The following key inputs are mapped:
The plugin can be installed in following ways:
REQUIRES: BepInEx plugin manager (follow its installation instructions first!).
The file structure should like like this:
{GameDirectory}/BepInEx/XUnity.AutoTranslator.Plugin.Core.dll
{GameDirectory}/BepInEx/XUnity.AutoTranslator.Plugin.Core.BepInEx.dll
{GameDirectory}/BepInEx/ExIni.dll
{GameDirectory}/BepInEx/Translation/AnyTranslationFile.txt (these files will be auto generated by plugin!)
REQUIRES: IPA plugin manager (follow its installation instructions first!).
The file structure should like like this
{GameDirectory}/Plugins/XUnity.AutoTranslator.Plugin.Core.dll
{GameDirectory}/Plugins/XUnity.AutoTranslator.Plugin.Core.IPA.dll
{GameDirectory}/Plugins/0Harmony.dll
{GameDirectory}/Plugins/ExIni.dll
{GameDirectory}/Plugins/Translation/AnyTranslationFile.txt (these files will be auto generated by plugin!)
REQUIRES: UnityInjector (follow its installation instructions first!).
The file structure should like like this
{GameDirectory}/UnityInjector/XUnity.AutoTranslator.Plugin.Core.dll
{GameDirectory}/UnityInjector/XUnity.AutoTranslator.Plugin.Core.UnityInjector.dll
{GameDirectory}/UnityInjector/0Harmony.dll
{GameDirectory}/UnityInjector/ExIni.dll
{GameDirectory}/UnityInjector/Translation/AnyTranslationFile.txt (these files will be auto generated by plugin!)
REQUIRES: Nothing, ReiPatcher is provided by this download.
The file structure should like like this
{GameDirectory}/ReiPatcher/Patches/XUnity.AutoTranslator.Patcher.dll
{GameDirectory}/ReiPatcher/ExIni.dll
{GameDirectory}/ReiPatcher/Mono.Cecil.dll
{GameDirectory}/ReiPatcher/Mono.Cecil.Inject.dll
{GameDirectory}/ReiPatcher/Mono.Cecil.Mdb.dll
{GameDirectory}/ReiPatcher/Mono.Cecil.Pdb.dll
{GameDirectory}/ReiPatcher/Mono.Cecil.Rocks.dll
{GameDirectory}/ReiPatcher/ReiPatcher.exe
{GameDirectory}/{GameExeName}_Data/Managed/ReiPatcher.exe
{GameDirectory}/{GameExeName}_Data/Managed/XUnity.AutoTranslator.Plugin.Core.dll
{GameDirectory}/{GameExeName}_Data/Managed/0Harmony.dll
{GameDirectory}/{GameExeName}_Data/Managed/ExIni.dll
{GameDirectory}/AutoTranslator/AnyTranslationFile.txt (these files will be auto generated by plugin!)
Often other mods UI are implemented through IMGUI. As you can see above, this is disabled by default. By changing the "EnableIMGUI" value to "True", it will start translating IMGUI as well, which likely means that other mods UI will be translated.
When you use this plugin, you can always go to the file Translation\_AutoGeneratedTranslations.{lang}.txt
(OutputFile) to edit any auto generated translations and they will show up the next time you run the game. Or you can press (ALT+R) to reload the translation immediately.
It is also worth noting that this plugin will read all text files (*.txt) in the Translation
(Directory), so if you want to provide a manual translation, you can simply cut out texts from the Translation\_AutoGeneratedTranslations.{lang}.txt
(OutputFile) and place them in new text files in order to replace them with a manual translation.
In this context, the Translation\_AutoGeneratedTranslations.{lang}.txt
(OutputFile) will always have the lowest priority when reading translations. So if the same translation is present in two places, it will not be the one from the (OutputFile) that is used.
Redistributing this plugin for various games is absolutely encouraged. However, if you do so, please keep the following in mind:
From version 2.16.0+ this mod provides basic capabilities to replace images. It is a feature that is disabled by default. There is no automatic translation of these images though.
This feature is primarily meant for games with little to no mod support to enable full translations without needing to modify resource files.
It is controlled by the following configuration:
[Texture]
TextureDirectory=Translation\Texture
EnableTextureTranslation=False
EnableTextureDumping=False
EnableTextureToggling=False
EnableTextureScanOnSceneLoad=False
EnableSpriteRendererHooking=False
LoadUnmodifiedTextures=False
TextureHashGenerationStrategy=FromImageName
TextureDirectory
specifies the directory where textures are dumped to and loaded from. Loading will happen from all subdirectories of the specified directory as well, so you can move dumped images to whatever folder structure you desire.
EnableTextureTranslation
enables texture translation. This basically means that textures will be loaded from the TextureDirectory
and it's subsdirectories. These images will replace the in-game images used by the game.
EnableTextureDumping
enables texture dumping. This means that the mod will dump any images it has not already dumped to the TextureDirectory
. When dumping textures, it may also be worth enabling EnableTextureScanOnSceneLoad
to more quickly find all textures that require translating. NEVER REDISTRIBUTE THIS MOD WITH THIS ENABLED.
EnableTextureScanOnSceneLoad
allows the plugin to scan for texture objects on the sceneLoad event. This enables the plugin to find more texture at a tiny performance cost during scene load (which is often during loading screens, etc.). However, because of the way Unity works not all of these are guaranteed to be replacable. If you find an image that is dumped but cannot be translated, please report it. However, please recognize this mod is primarily intended for replacing UI textures, not textures for 3D meshes.
EnableSpriteRendererHooking
allows the plugin to attempt to hook SpriteRenderer. This is a seperate option because SpriteRenderer can't actually be hooked properly and the implemented workaround could have a theoretical impact on performance in certain situations.
LoadUnmodifiedTextures
enables whether or not the plugin should load textures that has not been modified. This is only useful for debugging, and likely to cause various visual glitches, especially if EnableTextureScanOnSceneLoad
is also enabled. NEVER REDISTRIBUTE THIS MOD WITH THIS ENABLED.
EnableTextureToggling
enables whether the ALT+T hotkey will also toggle textures. This is by no means guaranteed to work, especially if EnableTextureScanOnSceneLoad
is also enabled. NEVER REDISTRIBUTE THIS MOD WITH THIS ENABLED.
TextureHashGenerationStrategy
specifies how images are identified. When images are stored, the game will need some way of associating them with the image that it has to replace.
This is done through a hash-value that is stored in square brackets in each image file name, like this: file_name [0223B639A2-6E698E9272].png
. This configuration specifies how these hash-values are generated:
FromImageName
means that the hash is generated from the internal resource name that the game uses for the image, which may not exist for all images or even be unique. However, it is generally fairly reliable. If an image has no resource name, it will not be dumped.FromImageData
means that the hash is generated from the data stored in the image, which is guaranteed to exist for all images. However, generating the hash comes at a performance cost, that will also be incurred by the end-users.FromImageNameAndScene
means that it should use the name and scene to generate a hash. The name is still required for this to work. When using this option, there is a chance the same texture could be dumped with different hashes, which is undesirable, but it could be required for some games, if the name itself is not unique and the FromImageData
option causes performance issues.There's an important catch you need to be aware when dealing with these options and that is if ANY of these options exists: EnableTextureDumping=True
, EnableTextureToggling=True
, TextureHashGenerationStrategy=FromImageData
, then the game will need to read the raw data from all images it finds in game in order to replace the image and this is an expensive operation.
It is therefore recommended to use TextureHashGenerationStrategy=FromImageName
. Most likely, images without a resource name won't be interesting to translate anyway.
If you redistribute this mod with translated images, it is recommended you delete all images you either have no intention of translating or are not translated at all.
You can also change the file name to whatever you desire, as long as you keep the hash appended to the end of the file name.
If you take anything away from this section, it should be these two points:
EnableTextureDumping=True
, EnableTextureToggling=True
OR LoadUnmodifiedTextures=True
TextureHashGenerationStrategy=FromImageData
ENABLED IF ABSOLUTELY REQUIRED BY THE GAME.There are actually two hashes in the generated file name, separated by a dash (-):
TextureHashGenerationStrategy
used. If FromImageName
is specified, then it is based on the UTF8 (without BOM) representation.LoadUnmodifiedTextures
is specified.If TextureHashGenerationStrategy=FromImageData
is specified, only a single hash will appear in each file name, as that single hash can be used both to identify the image and to determine whether or not it has been edited.
As a mod author implementing a translation plugin, you are able to, if you cannot find a translation to a string, simply delegate it to this mod, and you can do it without taking any references to this plugin.
Here's how it works, and what is required:
As a mod author, you might not want the Auto Translator to interfere with your mods UI. If this is the case there's two ways to tell Auto Translator not to perform any translation:
If your UI is based on IMGUI, the above approach is not possible, because there are no GameObject. In that case you can do the following instead:
public class MyPlugin : XPluginBase
{
private GameObject _xua;
private bool _lookedForXua;
public void OnGUI()
{
// make sure we only do this lookup once, as it otherwise may be detrimental to performance!
// also: do not attempt to do this in the Awake method or similar of your plugin, as your plugin may be instantiated before the auto translator!
if(!_lookedForXua)
{
_lookedForXua = true;
_xua = GameObject.Find( "___XUnityAutoTranslator" );
}
// try-finally block is important to make sure you re-enable the plugin
try
{
_xua?.SendMessage("DisableAutoTranslator");
// do your GUI things here
GUILayout.Button( "こんにちは!" );
}
finally
{
_xua?.SendMessage("EnableAutoTranslator");
}
}
}
This approach requires version 2.15.0 or later!
Since version 3.0.0, you can now also implement your own translators.
Whenever you implement a translator based on an online service, it is important to not use it in an abusive way. For example by:
With that in mind, consider the following:
WWW
class in Unity establishes a new TCP connection on each request you make, making it extremely poor at this kind of job. Especially if SSL (https) is involved because it has to do the entire handshake procedure each time.UnityWebRequest
class in Unity does not exist in most games, because they use an old engine, so it is not a good choice either.WebClient
class from .NET is capable of using persistent connections (it does so by default), but has its own problems with SSL. The version of Mono used in most Unity games rejects all certificates by default making all HTTPS connections fail. This, however, can be remedied during the initialization phase of the translator (see examples below). Another shortcoming of this API is the fact that the runtime will never release the TCP connections it has used until the process ends. The API also integrates terribly with Unity because callbacks return on a background thread.None of these are therefore an ideal solution.
To remedy this, I have made a class XUnityWebClient
, which is based on Mono's version of WebClient. However, it adds the following features:
I recommend using this class, or in case that cannot be used, falling back to the .NET 'WebClient'.
Follow these steps:
ITranslateEndpoint
interfaceHttpEndpoint
classHere's an example that simply reverses the text:
public class ReverseTranslator : ITranslateEndpoint
{
public string Id => "Reverser";
public string FriendlyName => "Reverser";
public int MaxConcurrency => 50;
public void Initialize( InitializationContext context )
{
}
public IEnumerator Translate( string untranslatedText, string from, string to, Action<string> success, Action<string, Exception> failure )
{
success( new string( untranslatedText.Reverse().ToArray() ) );
return null;
}
}
Here's a more real example of one of the existing endpoints based on the HttpEndpoint:
...
As you can see, the XUnityWebClient
class is not even used. We simply return a request object that the HttpEndpoint
will use internally to perform the request.
After implementing the class, simply build the project and place the generated DLL file in the "Translators" directory (you may have to create it) of the plugin folder. That's it.