├── .gitignore ├── UUIT.sln ├── UnityEngine.UI.Translation ├── AssemblyInfo.cs ├── ColorUtility.cs ├── DXTLoader.cs ├── Global.cs ├── PSDLoader.cs ├── System │ └── IniFile.cs ├── TGALoader.cs ├── UnityEngine.UI.Translation.csproj └── UnityEngine │ ├── AudioSourceOverride.cs │ ├── BaseTypeOfAttribute.cs │ ├── ReplaceMethodAttribute.cs │ └── UI │ └── Translation │ ├── AudioSourceSubtitle.cs │ ├── CursorOverride.cs │ ├── FontBorderChangedEventArgs.cs │ ├── FontColorChangedEventArgs.cs │ ├── FontMarginChangedEventArgs.cs │ ├── FontNameChangedEventArgs.cs │ ├── FontShadowChangedEventArgs.cs │ ├── FontSizeChangedEventArgs.cs │ ├── FontStyleChangedEventArgs.cs │ ├── ISubtitle.cs │ ├── ISubtitleBorder.cs │ ├── ISubtitleShadow.cs │ ├── ISubtitleUserInterface.cs │ ├── IniSettings.cs │ ├── InputFieldOverride.cs │ ├── JsonConfig.cs │ ├── KeyTranslationData.cs │ ├── MaskableGraphicRawImage.cs │ ├── MaskableGraphicText.cs │ ├── MaterialOverride.cs │ ├── RegexTranslationData.cs │ ├── SpriteOverride.cs │ ├── Subtitle.cs │ ├── SubtitleCanvas.cs │ ├── SubtitleData.cs │ ├── SubtitleDataBase.cs │ ├── SubtitleLine.cs │ ├── SubtitleSettings.cs │ ├── SubtitleTranslator.cs │ ├── SubtitleUserInterfaceBase.cs │ ├── TextPosition.cs │ ├── TextPositionExtension.cs │ ├── TextTranslator.cs │ ├── Texture2DCacheData.cs │ ├── Texture2DData.cs │ ├── Texture2DDumpData.cs │ ├── Texture2DOverride.cs │ ├── Texture2DOverrideData.cs │ ├── TranslationData.cs │ └── TranslationDataBase.cs ├── readme.md ├── ref ├── UnityEngine.UI.ref.dll └── UnityEngine.ref.dll └── screenshot ├── UIT-en-1.png ├── UIT-jp-1.png └── UIT-zh-1.png /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | ## Ignore Visual Studio temporary files, build results, and 3 | ## files generated by popular Visual Studio add-ons. 4 | 5 | # User-specific files 6 | *.suo 7 | *.user 8 | *.userosscache 9 | *.sln.docstates 10 | 11 | # Build results 12 | [Dd]ebug/ 13 | [Dd]ebugPublic/ 14 | [Rr]elease/ 15 | [Rr]eleases/ 16 | x64/ 17 | x86/ 18 | build/ 19 | bld/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | 23 | # Roslyn cache directories 24 | *.ide/ 25 | 26 | # MSTest test Results 27 | [Tt]est[Rr]esult*/ 28 | [Bb]uild[Ll]og.* 29 | 30 | #NUNIT 31 | *.VisualState.xml 32 | TestResult.xml 33 | 34 | # Build Results of an ATL Project 35 | [Dd]ebugPS/ 36 | [Rr]eleasePS/ 37 | dlldata.c 38 | 39 | *_i.c 40 | *_p.c 41 | *_i.h 42 | *.ilk 43 | *.meta 44 | *.obj 45 | *.pch 46 | *.pdb 47 | *.pgc 48 | *.pgd 49 | *.rsp 50 | *.sbr 51 | *.tlb 52 | *.tli 53 | *.tlh 54 | *.tmp 55 | *.tmp_proj 56 | *.log 57 | *.vspscc 58 | *.vssscc 59 | .builds 60 | *.pidb 61 | *.svclog 62 | *.scc 63 | 64 | # Chutzpah Test files 65 | _Chutzpah* 66 | 67 | # Visual C++ cache files 68 | ipch/ 69 | *.aps 70 | *.ncb 71 | *.opensdf 72 | *.sdf 73 | *.cachefile 74 | 75 | # Visual Studio profiler 76 | *.psess 77 | *.vsp 78 | *.vspx 79 | 80 | # TFS 2012 Local Workspace 81 | $tf/ 82 | 83 | # Guidance Automation Toolkit 84 | *.gpState 85 | 86 | # ReSharper is a .NET coding add-in 87 | _ReSharper*/ 88 | *.[Rr]e[Ss]harper 89 | *.DotSettings.user 90 | 91 | # JustCode is a .NET coding addin-in 92 | .JustCode 93 | 94 | # TeamCity is a build add-in 95 | _TeamCity* 96 | 97 | # DotCover is a Code Coverage Tool 98 | *.dotCover 99 | 100 | # NCrunch 101 | _NCrunch_* 102 | .*crunch*.local.xml 103 | 104 | # MightyMoose 105 | *.mm.* 106 | AutoTest.Net/ 107 | 108 | # Web workbench (sass) 109 | .sass-cache/ 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.[Pp]ublish.xml 129 | *.azurePubxml 130 | # TODO: Comment the next line if you want to checkin your web deploy settings 131 | # but database connection strings (with potential passwords) will be unencrypted 132 | *.pubxml 133 | *.publishproj 134 | 135 | # NuGet Packages 136 | *.nupkg 137 | # The packages folder can be ignored because of Package Restore 138 | **/packages/* 139 | # except build/, which is used as an MSBuild target. 140 | !**/packages/build/ 141 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 142 | #!**/packages/repositories.config 143 | 144 | # Windows Azure Build Output 145 | csx/ 146 | *.build.csdef 147 | 148 | # Windows Store app package directory 149 | AppPackages/ 150 | 151 | # Others 152 | sql/ 153 | *.Cache 154 | ClientBin/ 155 | [Ss]tyle[Cc]op.* 156 | ~$* 157 | *~ 158 | *.dbmdl 159 | *.dbproj.schemaview 160 | *.pfx 161 | *.publishsettings 162 | node_modules/ 163 | 164 | # RIA/Silverlight projects 165 | Generated_Code/ 166 | 167 | # Backup & report files from converting an old project file 168 | # to a newer Visual Studio version. Backup files are not needed, 169 | # because we have git ;-) 170 | _UpgradeReport_Files/ 171 | Backup*/ 172 | UpgradeLog*.XML 173 | UpgradeLog*.htm 174 | 175 | # SQL Server files 176 | *.mdf 177 | *.ldf 178 | 179 | # Business Intelligence projects 180 | *.rdl.data 181 | *.bim.layout 182 | *.bim_*.settings 183 | 184 | # Microsoft Fakes 185 | FakesAssemblies/ 186 | 187 | # ========================= 188 | # Operating System Files 189 | # ========================= 190 | 191 | # OSX 192 | # ========================= 193 | 194 | .DS_Store 195 | .AppleDouble 196 | .LSOverride 197 | 198 | # Thumbnails 199 | ._* 200 | 201 | # Files that might appear on external disk 202 | .Spotlight-V100 203 | .Trashes 204 | 205 | # Directories potentially created on remote AFP share 206 | .AppleDB 207 | .AppleDesktop 208 | Network Trash Folder 209 | Temporary Items 210 | .apdisk 211 | 212 | # Windows 213 | # ========================= 214 | 215 | # Windows image file caches 216 | Thumbs.db 217 | ehthumbs.db 218 | 219 | # Folder config file 220 | Desktop.ini 221 | 222 | # Recycle Bin used on file shares 223 | $RECYCLE.BIN/ 224 | 225 | # Windows Installer files 226 | *.cab 227 | *.msi 228 | *.msm 229 | *.msp 230 | 231 | # Windows shortcuts 232 | *.lnk 233 | /UInjector 234 | -------------------------------------------------------------------------------- /UUIT.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityEngine.UI.Translation", "UnityEngine.UI.Translation\UnityEngine.UI.Translation.csproj", "{DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{56B6E00F-BB36-44CF-BC9D-1B17419D28E3}" 9 | ProjectSection(SolutionItems) = preProject 10 | readme.md = readme.md 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UInjector", "UInjector\UInjector.csproj", "{DB6CE76B-98E5-4ACE-8879-C711C69B94BB}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x86 = Release|x86 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Debug|Any CPU.ActiveCfg = Debug|x86 24 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Debug|x86.ActiveCfg = Debug|x86 25 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Debug|x86.Build.0 = Debug|x86 26 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Release|Any CPU.ActiveCfg = Release|x86 27 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Release|x86.ActiveCfg = Release|x86 28 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5}.Release|x86.Build.0 = Release|x86 29 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Debug|x86.ActiveCfg = Debug|Any CPU 32 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Debug|x86.Build.0 = Debug|Any CPU 33 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Release|x86.ActiveCfg = Release|Any CPU 36 | {DB6CE76B-98E5-4ACE-8879-C711C69B94BB}.Release|x86.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | // Assembly UnityEngine.UI.Translation, Version 1.0.0.0 3 | 4 | //[assembly: System.Runtime.CompilerServices.Extension] 5 | [assembly: System.Runtime.CompilerServices.CompilationRelaxations(8)] 6 | [assembly: System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)] 7 | [assembly: System.Diagnostics.Debuggable(System.Diagnostics.DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] 8 | [assembly: System.Reflection.AssemblyTitle("UnityEngine.UI.Translation")] 9 | [assembly: System.Reflection.AssemblyDescription("A Localization solution for UGUI.")] 10 | [assembly: System.Reflection.AssemblyConfiguration("")] 11 | [assembly: System.Reflection.AssemblyCompany("")] 12 | [assembly: System.Reflection.AssemblyProduct("UnityEngine.UI.Translation")] 13 | [assembly: System.Reflection.AssemblyCopyright("Copyright \x00a9 akyryz 2015")] 14 | [assembly: System.Reflection.AssemblyTrademark("")] 15 | [assembly: System.Runtime.InteropServices.ComVisible(false)] 16 | [assembly: System.Runtime.InteropServices.Guid("3044bf3c-aaee-431a-b7e1-975e065343bb")] 17 | [assembly: System.Reflection.AssemblyFileVersion("0.16.0.0")] 18 | [assembly: AssemblyVersion("1.0.0.0")] 19 | 20 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/ColorUtility.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/DXTLoader.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.IO; 4 | using Texture2D = U::UnityEngine.Texture2D; 5 | using TextureFormat = U::UnityEngine.TextureFormat; 6 | 7 | internal static class DXTLoader 8 | { 9 | public static bool LoadDXT(string fileName, out U::UnityEngine.Texture2D texture) 10 | { 11 | try 12 | { 13 | return LoadDXT(File.ReadAllBytes(fileName), out texture); 14 | } 15 | catch 16 | { 17 | texture = null; 18 | return false; 19 | } 20 | } 21 | 22 | public static bool LoadDXT(byte[] ddsBytes, out Texture2D texture) 23 | { 24 | try 25 | { 26 | if (ddsBytes[4] != 0x7c) 27 | { 28 | throw new Exception("Invalid DDS DXTn texture. Unable to read"); 29 | } 30 | TextureFormat format = (TextureFormat) 0; 31 | if (((ddsBytes[0x54] == 0x44) && (ddsBytes[0x55] == 0x58)) && (ddsBytes[0x56] == 0x54)) 32 | { 33 | if (ddsBytes[0x57] == 0x31) 34 | { 35 | format = TextureFormat.DXT1; 36 | } 37 | else if (ddsBytes[0x57] == 0x35) 38 | { 39 | format = TextureFormat.DXT5; 40 | } 41 | } 42 | if ((format != TextureFormat.DXT1) && (format != TextureFormat.DXT5)) 43 | { 44 | throw new Exception("Invalid TextureFormat. Only DXT1 and DXT5 formats are supported by this method."); 45 | } 46 | int height = (ddsBytes[13] * 0x100) + ddsBytes[12]; 47 | int width = (ddsBytes[0x11] * 0x100) + ddsBytes[0x10]; 48 | byte[] dst = new byte[ddsBytes.Length - 0x80]; 49 | Buffer.BlockCopy(ddsBytes, 0x80, dst, 0, ddsBytes.Length - 0x80); 50 | texture = new Texture2D(width, height, format, false); 51 | texture.LoadRawTextureData(dst); 52 | texture.Apply(); 53 | return true; 54 | } 55 | catch 56 | { 57 | texture = null; 58 | return false; 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/Global.cs: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/PSDLoader.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.IO; 4 | using System.Text; 5 | using Color32 = U::UnityEngine.Color32; 6 | using Texture2D = U::UnityEngine.Texture2D; 7 | using TextureFormat = U::UnityEngine.TextureFormat; 8 | 9 | internal static class PSDLoader 10 | { 11 | public static bool LoadPSD(string fileName, out U::UnityEngine.Texture2D texture) 12 | { 13 | try 14 | { 15 | return LoadPSD(File.ReadAllBytes(fileName), out texture); 16 | } 17 | catch 18 | { 19 | texture = null; 20 | return false; 21 | } 22 | } 23 | 24 | public static bool LoadPSD(byte[] psdBytes, out Texture2D texture) 25 | { 26 | bool flag; 27 | try 28 | { 29 | byte[] buffer; 30 | int index = 0; 31 | if (psdBytes == null) 32 | { 33 | throw new ArgumentNullException("psdBytes"); 34 | } 35 | byte[] bytes = Encoding.UTF8.GetBytes("8BPS"); 36 | if (psdBytes.Length < bytes.Length) 37 | { 38 | throw new ArgumentOutOfRangeException(); 39 | } 40 | for (int i = 0; i < bytes.Length; i++) 41 | { 42 | if (psdBytes[i] != bytes[i]) 43 | { 44 | throw new FormatException(); 45 | } 46 | } 47 | index = Read(psdBytes, bytes.Length, 2, out buffer, true); 48 | if (BitConverter.ToInt16(buffer, 0) != 1) 49 | { 50 | throw new FormatException(); 51 | } 52 | index += 6; 53 | index = Read(psdBytes, index, 2, out buffer, true); 54 | short num2 = BitConverter.ToInt16(buffer, 0); 55 | if ((num2 != 3) && (num2 != 4)) 56 | { 57 | throw new NotSupportedException(); 58 | } 59 | index = Read(psdBytes, index, 4, out buffer, true); 60 | int height = BitConverter.ToInt32(buffer, 0); 61 | index = Read(psdBytes, index, 4, out buffer, true); 62 | int width = BitConverter.ToInt32(buffer, 0); 63 | index = Read(psdBytes, index, 2, out buffer, true); 64 | if (BitConverter.ToInt16(buffer, 0) != 8) 65 | { 66 | throw new NotSupportedException(); 67 | } 68 | index = Read(psdBytes, index, 2, out buffer, true); 69 | short num5 = BitConverter.ToInt16(buffer, 0); 70 | index = Read(psdBytes, index, 4, out buffer, true); 71 | int num6 = BitConverter.ToInt32(buffer, 0); 72 | index += num6; 73 | index = Read(psdBytes, index, 4, out buffer, true); 74 | int num7 = BitConverter.ToInt32(buffer, 0); 75 | index += num7; 76 | index = Read(psdBytes, index, 4, out buffer, true); 77 | int num8 = BitConverter.ToInt32(buffer, 0); 78 | index += num8; 79 | index = Read(psdBytes, index, 2, out buffer, true); 80 | short num9 = BitConverter.ToInt16(buffer, 0); 81 | TextureFormat format = (TextureFormat) 0; 82 | switch (num5) 83 | { 84 | case 0: 85 | throw new NotSupportedException(); 86 | 87 | case 1: 88 | throw new NotSupportedException(); 89 | 90 | case 2: 91 | throw new NotSupportedException(); 92 | 93 | case 3: 94 | format = TextureFormat.RGBA32; 95 | break; 96 | 97 | case 4: 98 | throw new NotSupportedException(); 99 | 100 | case 7: 101 | throw new NotSupportedException(); 102 | 103 | case 8: 104 | throw new NotSupportedException(); 105 | 106 | case 9: 107 | throw new NotSupportedException(); 108 | 109 | default: 110 | throw new NotSupportedException(); 111 | } 112 | switch (num9) 113 | { 114 | case 0: 115 | throw new NotSupportedException(); 116 | 117 | case 1: 118 | { 119 | short[] numArray = new short[num2 * height]; 120 | for (int j = 0; j < numArray.Length; j++) 121 | { 122 | index = Read(psdBytes, index, 2, out buffer, true); 123 | numArray[j] = BitConverter.ToInt16(buffer, 0); 124 | } 125 | int num11 = 0; 126 | int num12 = 0; 127 | Color32[] colors = new Color32[width * height]; 128 | for (int k = 0; k < numArray.Length; k++) 129 | { 130 | if (num11 == 4) 131 | { 132 | throw new NotSupportedException(); 133 | } 134 | index = Read(psdBytes, index, numArray[k], out buffer, false); 135 | for (int m = 0; m < buffer.Length; m++) 136 | { 137 | sbyte num16 = (sbyte) buffer[m]; 138 | if (num16 != -128) 139 | { 140 | if (num16 < 0) 141 | { 142 | m++; 143 | int num17 = 1 - num16; 144 | for (int n = 0; n < num17; n++) 145 | { 146 | Color32 color = colors[num12]; 147 | switch (num11) 148 | { 149 | case 0: 150 | color.a = 0xff; 151 | color.r = buffer[m]; 152 | break; 153 | 154 | case 1: 155 | color.g = buffer[m]; 156 | break; 157 | 158 | case 2: 159 | color.b = buffer[m]; 160 | break; 161 | 162 | case 3: 163 | color.a = buffer[m]; 164 | break; 165 | } 166 | colors[num12++] = color; 167 | } 168 | } 169 | else 170 | { 171 | int num19 = 1 + num16; 172 | for (int num20 = 0; num20 < num19; num20++) 173 | { 174 | Color32 color2 = colors[num12]; 175 | switch (num11) 176 | { 177 | case 0: 178 | color2.a = 0xff; 179 | color2.r = buffer[++m]; 180 | break; 181 | 182 | case 1: 183 | color2.g = buffer[++m]; 184 | break; 185 | 186 | case 2: 187 | color2.b = buffer[++m]; 188 | break; 189 | 190 | case 3: 191 | color2.a = buffer[++m]; 192 | break; 193 | } 194 | colors[num12++] = color2; 195 | } 196 | } 197 | } 198 | } 199 | if (num12 == colors.Length) 200 | { 201 | num11++; 202 | num12 = 0; 203 | } 204 | } 205 | texture = new Texture2D(width, height, format, false); 206 | texture.SetPixels32(colors); 207 | texture.Apply(); 208 | return true; 209 | } 210 | case 2: 211 | throw new NotSupportedException(); 212 | 213 | case 3: 214 | throw new NotSupportedException(); 215 | } 216 | throw new NotSupportedException(); 217 | } 218 | catch 219 | { 220 | texture = null; 221 | flag = false; 222 | } 223 | return flag; 224 | } 225 | 226 | private static int Read(byte[] data, int index, int count, out byte[] buffer, bool reverse = true) 227 | { 228 | if ((index < 0) || (data.Length < (index + count))) 229 | { 230 | throw new IndexOutOfRangeException(); 231 | } 232 | buffer = new byte[count]; 233 | Array.Copy(data, index, buffer, 0, count); 234 | if (reverse) 235 | { 236 | Array.Reverse(buffer); 237 | } 238 | index += count; 239 | return index; 240 | } 241 | } 242 | 243 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/System/IniFile.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace System 4 | { 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.IO; 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | 11 | public class IniFile 12 | { 13 | private Dictionary> ini; 14 | private readonly string name = Process.GetCurrentProcess().ProcessName; 15 | private readonly string path; 16 | 17 | public IniFile(string path = null) 18 | { 19 | if (string.IsNullOrEmpty(path)) 20 | { 21 | this.path = this.name + ".ini"; 22 | } 23 | this.path = Path.GetFullPath(path); 24 | this.Load(); 25 | } 26 | 27 | public string[] GetKeysInSection(string section = null) 28 | { 29 | Dictionary dictionary; 30 | if (string.IsNullOrEmpty(section)) 31 | { 32 | section = this.name; 33 | } 34 | if (this.ini.TryGetValue(section, out dictionary)) 35 | { 36 | string[] array = new string[dictionary.Keys.Count]; 37 | dictionary.Keys.CopyTo(array, 0); 38 | return array; 39 | } 40 | return new string[0]; 41 | } 42 | 43 | public string[] GetSections() 44 | { 45 | string[] array = new string[this.ini.Keys.Count]; 46 | this.ini.Keys.CopyTo(array, 0); 47 | return array; 48 | } 49 | 50 | public string GetValue(string section = null, string key = null, object @default = null) 51 | { 52 | Dictionary dictionary; 53 | string str; 54 | if (string.IsNullOrEmpty(section)) 55 | { 56 | section = this.name; 57 | } 58 | if (string.IsNullOrEmpty(key)) 59 | { 60 | key = this.name; 61 | } 62 | if (this.ini.TryGetValue(section, out dictionary) && dictionary.TryGetValue(key, out str)) 63 | { 64 | return str; 65 | } 66 | if (@default != null) 67 | { 68 | return @default.ToString(); 69 | } 70 | return null; 71 | } 72 | 73 | private void Load() 74 | { 75 | this.ini = new Dictionary>(); 76 | this.ini.Add(this.name, new Dictionary()); 77 | if (File.Exists(this.path)) 78 | { 79 | try 80 | { 81 | using (StreamReader reader = new StreamReader(this.path, Encoding.UTF8)) 82 | { 83 | string name = this.name; 84 | while (!reader.EndOfStream) 85 | { 86 | string str = reader.ReadLine().Trim(); 87 | if (str.Length != 0) 88 | { 89 | if (str.StartsWith("[") && str.EndsWith("]")) 90 | { 91 | name = str.Substring(1, str.Length - 2); 92 | if (name.Length == 0) 93 | { 94 | name = this.name; 95 | } 96 | if (!this.ini.ContainsKey(name)) 97 | { 98 | this.ini.Add(name, new Dictionary()); 99 | } 100 | } 101 | else if (!str.StartsWith(";")) 102 | { 103 | Dictionary dictionary; 104 | char[] separator = new char[] { '=' }; 105 | string[] strArray = str.Split(separator, 2); 106 | strArray[0] = strArray[0].Trim(); 107 | if (!string.IsNullOrEmpty(strArray[0]) && this.ini.TryGetValue(name, out dictionary)) 108 | { 109 | dictionary.Remove(strArray[0]); 110 | if (strArray.Length == 2) 111 | { 112 | char[] chArray2 = new char[] { ';' }; 113 | string[] strArray2 = strArray[1].Split(chArray2, 2); 114 | strArray2[0] = strArray2[0].Trim(); 115 | dictionary.Add(strArray[0], strArray2[0]); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | catch (Exception exception1) 124 | { 125 | throw exception1; 126 | } 127 | } 128 | } 129 | 130 | public void WriteValue(string section = null, string key = null, object value = null) 131 | { 132 | Dictionary dictionary; 133 | if (string.IsNullOrEmpty(section)) 134 | { 135 | section = this.name; 136 | } 137 | if (string.IsNullOrEmpty(key)) 138 | { 139 | key = this.name; 140 | } 141 | string str = (value == null) ? string.Empty : value.ToString(); 142 | if (!NativeMethods.WritePrivateProfileString(section, key, str, this.path)) 143 | { 144 | throw new Win32Exception(Marshal.GetLastWin32Error()); 145 | } 146 | if (this.ini.TryGetValue(section, out dictionary)) 147 | { 148 | dictionary.Remove(key); 149 | dictionary.Add(key, str); 150 | } 151 | else 152 | { 153 | dictionary = new Dictionary { 154 | { 155 | key, 156 | str 157 | } 158 | }; 159 | this.ini.Add(section, dictionary); 160 | } 161 | } 162 | 163 | private class NativeMethods 164 | { 165 | [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] 166 | internal static extern int GetPrivateProfileString(string Section, string Key, string Default, string Result, int Size, string FilePath); 167 | [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] 168 | internal static extern bool WritePrivateProfileString(string Section, string Key, string Value, string FilePath); 169 | } 170 | } 171 | } 172 | 173 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/TGALoader.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.IO; 4 | using Color32 = U::UnityEngine.Color32; 5 | using Texture2D = U::UnityEngine.Texture2D; 6 | using TextureFormat = U::UnityEngine.TextureFormat; 7 | 8 | internal static class TGALoader 9 | { 10 | public static bool LoadTGA(Stream TGAStream, out U::UnityEngine.Texture2D texture) 11 | { 12 | bool flag; 13 | try 14 | { 15 | using (BinaryReader reader = new BinaryReader(TGAStream)) 16 | { 17 | Texture2D textured; 18 | reader.BaseStream.Seek(12L, SeekOrigin.Begin); 19 | short width = reader.ReadInt16(); 20 | short height = reader.ReadInt16(); 21 | int num3 = reader.ReadByte(); 22 | reader.BaseStream.Seek(1L, SeekOrigin.Current); 23 | Color32[] colors = new Color32[width * height]; 24 | if (num3 == 0x20) 25 | { 26 | textured = new Texture2D(width, height, TextureFormat.RGBA32, false); 27 | for (int i = 0; i < (width * height); i++) 28 | { 29 | byte b = reader.ReadByte(); 30 | byte g = reader.ReadByte(); 31 | byte r = reader.ReadByte(); 32 | byte a = reader.ReadByte(); 33 | colors[i] = new Color32(r, g, b, a); 34 | } 35 | } 36 | else 37 | { 38 | if (num3 != 0x18) 39 | { 40 | throw new Exception("TGA texture had non 32/24 bit depth."); 41 | } 42 | textured = new Texture2D(width, height, TextureFormat.RGB24, false); 43 | for (int j = 0; j < (width * height); j++) 44 | { 45 | byte num10 = reader.ReadByte(); 46 | byte num11 = reader.ReadByte(); 47 | byte num12 = reader.ReadByte(); 48 | colors[j] = new Color32(num12, num11, num10, 0xff); 49 | } 50 | } 51 | textured.SetPixels32(colors); 52 | textured.Apply(); 53 | texture = textured; 54 | flag = true; 55 | } 56 | } 57 | catch 58 | { 59 | texture = null; 60 | flag = false; 61 | } 62 | return flag; 63 | } 64 | 65 | public static bool LoadTGA(string fileName, out Texture2D texture) 66 | { 67 | bool flag; 68 | try 69 | { 70 | using (FileStream stream = File.OpenRead(fileName)) 71 | { 72 | flag = LoadTGA(stream, out texture); 73 | } 74 | } 75 | catch 76 | { 77 | texture = null; 78 | flag = false; 79 | } 80 | return flag; 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine.UI.Translation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | local 5 | 7.10.377 6 | 2.0 7 | {DFD96B31-8FDE-408C-A086-4B9BB5E41CE5} 8 | Debug 9 | UnityEngine.UI.Translation 10 | Library 11 | v3.5 12 | Client 13 | 14 | 15 | x86 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | TRACE;DEBUG;UNITY4 21 | prompt 22 | 4 23 | 24 | 25 | x86 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | ..\ref\UnityEngine.ref.dll 89 | U 90 | 91 | 92 | ..\ref\UnityEngine.UI.ref.dll 93 | global 94 | 95 | 96 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/AudioSourceOverride.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System.Runtime.CompilerServices; 3 | using U::UnityEngine.Internal; 4 | using UnityEngine.UI.Translation; 5 | using EngineAudioSource = U::UnityEngine.AudioSource; 6 | namespace UnityEngine 7 | { 8 | [BaseTypeOf("UnityEngine.AudioSource", "UnityEngine.dll")] 9 | public class AudioSource : U::UnityEngine.Behaviour 10 | { 11 | protected void DoPlay(ulong delay = 0L) 12 | { 13 | this.SetSubtitle(); 14 | this.Play(delay); 15 | } 16 | 17 | protected void DoPlayDelayed(float delay) 18 | { 19 | this.SetSubtitle(); 20 | this.PlayDelayed(delay); 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.InternalCall)] 24 | private extern void Play([DefaultValue("0")] ulong delay); 25 | [MethodImpl(MethodImplOptions.InternalCall)] 26 | private extern void PlayDelayed(float delay); 27 | private void SetSubtitle() 28 | { 29 | if (base.GetType() == typeof(EngineAudioSource)) 30 | { 31 | EngineAudioSource source = this as EngineAudioSource; 32 | AudioSourceSubtitle.Instance.Add(source); 33 | } 34 | } 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/BaseTypeOfAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace UnityEngine 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 6 | public class BaseTypeOfAttribute : Attribute 7 | { 8 | private string AssemblyName { get; set; } 9 | private string TypeFullName { get; set; } 10 | public BaseTypeOfAttribute(string typeFullName,string assemblyName) 11 | { 12 | TypeFullName = typeFullName; 13 | AssemblyName = assemblyName; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/ReplaceMethodAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace UnityEngine 7 | { 8 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor, AllowMultiple = false)] 9 | class ReplaceMethodAttribute : Attribute 10 | { 11 | private string MethodName { get; set; } 12 | private string AssemblyName { get; set; } 13 | private string TypeFullName { get; set; } 14 | public bool IsProperty { get; set; } 15 | public string MethodFullName { get; set; } 16 | public ReplaceMethodAttribute(string methodName, string assemblyName, string typeFullName) 17 | { 18 | MethodName = methodName; 19 | AssemblyName = assemblyName; 20 | TypeFullName = typeFullName; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/AudioSourceSubtitle.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.Specialized; 5 | using System.Text; 6 | using Object = U::UnityEngine.Object; 7 | namespace UnityEngine.UI.Translation 8 | { 9 | internal class AudioSourceSubtitle : U::UnityEngine.MonoBehaviour 10 | { 11 | private static AudioSourceSubtitle _Instance; 12 | 13 | private bool reloadsubtitles; 14 | 15 | private OrderedDictionary subtitles; 16 | 17 | private Dictionary content; 18 | 19 | public static AudioSourceSubtitle Instance 20 | { 21 | get 22 | { 23 | if (AudioSourceSubtitle._Instance == null) 24 | { 25 | AudioSourceSubtitle._Instance = U::UnityEngine.Object.FindObjectOfType(); 26 | if (AudioSourceSubtitle._Instance == null) 27 | { 28 | U::UnityEngine.GameObject gameObject = new U::UnityEngine.GameObject("AudioSourceSubtitle"); 29 | AudioSourceSubtitle._Instance = gameObject.AddComponent(); 30 | U::UnityEngine.Object.DontDestroyOnLoad(gameObject); 31 | } 32 | } 33 | return AudioSourceSubtitle._Instance; 34 | } 35 | } 36 | 37 | static AudioSourceSubtitle() 38 | { 39 | SubtitleSettings.FontNameChanged += new Action((string value) => SubtitleUserInterfaceBase.Instance.FontName = value); 40 | SubtitleSettings.FontSizeChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.FontSize = value); 41 | SubtitleSettings.FontColorChanged += value => SubtitleUserInterfaceBase.Instance.FontColor = value; 42 | SubtitleSettings.BoldChanged += new Action((bool value) => SubtitleUserInterfaceBase.Instance.Bold = value); 43 | SubtitleSettings.ItalicChanged += new Action((bool value) => SubtitleUserInterfaceBase.Instance.Italic = value); 44 | SubtitleSettings.BorderWidthChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.BorderWidth = value); 45 | SubtitleSettings.ShadowOffsetChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.ShadowOffset = value); 46 | SubtitleSettings.MarginLeftChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.MarginLeft = (float)value); 47 | SubtitleSettings.MarginTopChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.MarginTop = (float)value); 48 | SubtitleSettings.MarginRightChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.MarginRight = (float)value); 49 | SubtitleSettings.MarginBottomChanged += new Action((int value) => SubtitleUserInterfaceBase.Instance.MarginBottom = (float)value); 50 | } 51 | 52 | public AudioSourceSubtitle() 53 | { 54 | this.subtitles = new OrderedDictionary(); 55 | this.content = new Dictionary(); 56 | } 57 | 58 | public void Add(U::UnityEngine.AudioSource source) 59 | { 60 | try 61 | { 62 | this.subtitles.Remove(source); 63 | this.subtitles.Insert(0, source, new Subtitle(SubtitleUserInterfaceBase.Instance.Anchors, source)); 64 | } 65 | catch (Exception exception) 66 | { 67 | IniSettings.Error(string.Concat("AudioSourceSubtitle::Load:\n", exception.ToString())); 68 | } 69 | } 70 | 71 | private void Awake() 72 | { 73 | if (this != AudioSourceSubtitle.Instance) 74 | { 75 | Object.DestroyImmediate(this); 76 | } 77 | foreach (TextPosition anchor in SubtitleUserInterfaceBase.Instance.Anchors) 78 | { 79 | this.content.Add(anchor, new StringBuilder(512)); 80 | } 81 | SubtitleUserInterfaceBase.Instance.FontName = SubtitleSettings.FontName; 82 | SubtitleUserInterfaceBase.Instance.FontSize = SubtitleSettings.FontSize; 83 | SubtitleUserInterfaceBase.Instance.FontColor = SubtitleSettings.FontColor; 84 | SubtitleUserInterfaceBase.Instance.Bold = SubtitleSettings.Bold; 85 | SubtitleUserInterfaceBase.Instance.Italic = SubtitleSettings.Italic; 86 | SubtitleUserInterfaceBase.Instance.BorderWidth = SubtitleSettings.BorderWidth; 87 | SubtitleUserInterfaceBase.Instance.ShadowOffset = SubtitleSettings.ShadowOffset; 88 | SubtitleUserInterfaceBase.Instance.MarginLeft = (float)SubtitleSettings.MarginLeft; 89 | SubtitleUserInterfaceBase.Instance.MarginTop = (float)SubtitleSettings.MarginTop; 90 | SubtitleUserInterfaceBase.Instance.MarginRight = (float)SubtitleSettings.MarginRight; 91 | SubtitleUserInterfaceBase.Instance.MarginBottom = (float)SubtitleSettings.MarginBottom; 92 | } 93 | 94 | private void LateUpdate() 95 | { 96 | try 97 | { 98 | if (this.subtitles.Count != 0) 99 | { 100 | foreach (KeyValuePair keyValuePair in this.content) 101 | { 102 | if (keyValuePair.Value.Length <= 0) 103 | { 104 | continue; 105 | } 106 | keyValuePair.Value.Length = 0; 107 | } 108 | for (int i = this.subtitles.Count - 1; i >= 0; i--) 109 | { 110 | Subtitle item = this.subtitles[i] as Subtitle; 111 | if (item == null) 112 | { 113 | this.subtitles.RemoveAt(i); 114 | } 115 | else if (item.Source != null) 116 | { 117 | if (this.reloadsubtitles) 118 | { 119 | item.Reload(); 120 | } 121 | item.LateUpdate(); 122 | foreach (TextPosition anchor in SubtitleUserInterfaceBase.Instance.Anchors) 123 | { 124 | string str = item[anchor]; 125 | if (str.Length <= 0) 126 | { 127 | continue; 128 | } 129 | if (this.content[anchor].Length > 0) 130 | { 131 | this.content[anchor].Append('\n'); 132 | } 133 | this.content[anchor].Append(str); 134 | } 135 | } 136 | else 137 | { 138 | this.subtitles.RemoveAt(i); 139 | } 140 | } 141 | this.reloadsubtitles = false; 142 | foreach (TextPosition textPosition in SubtitleUserInterfaceBase.Instance.Anchors) 143 | { 144 | SubtitleUserInterfaceBase.Instance[textPosition] = this.content[textPosition].ToString(); 145 | } 146 | } 147 | } 148 | catch (Exception exception) 149 | { 150 | IniSettings.Error(string.Concat("AudioSourceSubtitle::LateUpdate:\n", exception.ToString())); 151 | } 152 | } 153 | 154 | public void Reload() 155 | { 156 | if (this.subtitles.Count > 0) 157 | { 158 | this.reloadsubtitles = true; 159 | } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/CursorOverride.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using Texture2D = U::UnityEngine.Texture2D; 4 | 5 | namespace UnityEngine.UI.Translation 6 | { 7 | [BaseTypeOf("UnityEngine.Cursor", "UnityEngine.dll")] 8 | public class CursorOverride 9 | { 10 | private static Texture2DOverrideData overrideData; 11 | 12 | protected CursorOverride() 13 | { 14 | } 15 | 16 | protected static void Swap(ref Texture2D texture) 17 | { 18 | try 19 | { 20 | if (texture == null) 21 | { 22 | if (overrideData.OriginalTexture2D != null) 23 | { 24 | Texture2DOverride.UnloadTexture2D(ref overrideData); 25 | } 26 | } 27 | else 28 | { 29 | if (overrideData.OriginalTexture2D != null) 30 | { 31 | int instanceID = texture.GetInstanceID(); 32 | if (overrideData.InstanceID == instanceID) 33 | { 34 | texture = overrideData.OverrideTextureCache; 35 | return; 36 | } 37 | Texture2DOverride.UnloadTexture2D(ref overrideData); 38 | } 39 | Texture2DOverride.LoadTexture2D(texture.name, texture, out overrideData); 40 | if (overrideData.OverrideTexture2D != null) 41 | { 42 | if ((texture.width != overrideData.OverrideTexture2D.width) || (texture.height != overrideData.OverrideTexture2D.height)) 43 | { 44 | texture.Resize(overrideData.OverrideTexture2D.width, overrideData.OverrideTexture2D.height); 45 | } 46 | texture.SetPixels32(overrideData.OverrideTexture2D.GetPixels32()); 47 | texture.Apply(); 48 | overrideData.OverrideTextureCache = texture; 49 | } 50 | } 51 | } 52 | catch (Exception exception) 53 | { 54 | IniSettings.Error("CursorOverride:\n" + exception.ToString()); 55 | } 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontBorderChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontBorderChangedEventArgs : EventArgs 6 | { 7 | private readonly int _BorderWidth; 8 | 9 | public FontBorderChangedEventArgs(int borderWidth) 10 | { 11 | this._BorderWidth = borderWidth; 12 | } 13 | 14 | public int BorderWidth 15 | { 16 | get 17 | { 18 | return this._BorderWidth; 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontColorChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | namespace UnityEngine.UI.Translation 3 | { 4 | using System; 5 | 6 | internal class FontColorChangedEventArgs : EventArgs 7 | { 8 | private readonly U::UnityEngine.Color _FontColor; 9 | 10 | public FontColorChangedEventArgs(U::UnityEngine.Color color) 11 | { 12 | this._FontColor = color; 13 | } 14 | 15 | public U::UnityEngine.Color FontColor 16 | { 17 | get 18 | { 19 | return this._FontColor; 20 | } 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontMarginChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontMarginChangedEventArgs : EventArgs 6 | { 7 | private readonly float _MarginBottom; 8 | private readonly float _MarginLeft; 9 | private readonly float _MarginRight; 10 | private readonly float _MarginTop; 11 | 12 | public FontMarginChangedEventArgs(float left, float top, float right, float bottom) 13 | { 14 | this._MarginLeft = left; 15 | this._MarginTop = top; 16 | this._MarginRight = right; 17 | this._MarginBottom = bottom; 18 | } 19 | 20 | public float MarginBottom 21 | { 22 | get 23 | { 24 | return this._MarginBottom; 25 | } 26 | } 27 | 28 | public float MarginLeft 29 | { 30 | get 31 | { 32 | return this._MarginLeft; 33 | } 34 | } 35 | 36 | public float MarginRight 37 | { 38 | get 39 | { 40 | return this._MarginRight; 41 | } 42 | } 43 | 44 | public float MarginTop 45 | { 46 | get 47 | { 48 | return this._MarginTop; 49 | } 50 | } 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontNameChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontNameChangedEventArgs : EventArgs 6 | { 7 | private readonly string _FontName; 8 | 9 | public FontNameChangedEventArgs(string name) 10 | { 11 | this._FontName = name; 12 | } 13 | 14 | public string FontName 15 | { 16 | get 17 | { 18 | return this._FontName; 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontShadowChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontShadowChangedEventArgs : EventArgs 6 | { 7 | private readonly int _ShadowOffset; 8 | 9 | public FontShadowChangedEventArgs(int shadowOffset) 10 | { 11 | this._ShadowOffset = shadowOffset; 12 | } 13 | 14 | public int ShadowOffset 15 | { 16 | get 17 | { 18 | return this._ShadowOffset; 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontSizeChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontSizeChangedEventArgs : EventArgs 6 | { 7 | private readonly int _FontSize; 8 | 9 | public FontSizeChangedEventArgs(int size) 10 | { 11 | this._FontSize = size; 12 | } 13 | 14 | public int FontSize 15 | { 16 | get 17 | { 18 | return this._FontSize; 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/FontStyleChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class FontStyleChangedEventArgs : EventArgs 6 | { 7 | private readonly bool _Bold; 8 | private readonly bool _Italic; 9 | 10 | public FontStyleChangedEventArgs(bool bold, bool italic) 11 | { 12 | this._Bold = bold; 13 | this._Italic = italic; 14 | } 15 | 16 | public bool Bold 17 | { 18 | get 19 | { 20 | return this._Bold; 21 | } 22 | } 23 | 24 | public bool Italic 25 | { 26 | get 27 | { 28 | return this._Italic; 29 | } 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/ISubtitle.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal interface ISubtitle 4 | { 5 | string this[TextPosition anchor] { get; } 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/ISubtitleBorder.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal interface ISubtitleBorder 4 | { 5 | int BorderWidth { get; set; } 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/ISubtitleShadow.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal interface ISubtitleShadow 4 | { 5 | int ShadowOffset { get; set; } 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/ISubtitleUserInterface.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | namespace UnityEngine.UI.Translation 3 | { 4 | using System.Collections.Generic; 5 | 6 | internal interface ISubtitleUserInterface 7 | { 8 | IEnumerable Anchors { get; } 9 | 10 | bool Bold { get; set; } 11 | 12 | U::UnityEngine.Color FontColor { get; set; } 13 | 14 | string FontName { get; set; } 15 | 16 | int FontSize { get; set; } 17 | 18 | bool Italic { get; set; } 19 | 20 | string this[TextPosition anchor] { get; set; } 21 | 22 | float MarginBottom { get; set; } 23 | 24 | float MarginLeft { get; set; } 25 | 26 | float MarginRight { get; set; } 27 | 28 | float MarginTop { get; set; } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/InputFieldOverride.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.UI; 2 | 3 | namespace UnityEngine.UI.Translation 4 | { 5 | [BaseTypeOf("UnityEngine.UI.InputField","UnityEngine.UI.dll")] 6 | public class InputFieldOverride : Selectable 7 | { 8 | public void SetPlaceholder(Graphic value) 9 | { 10 | if (base.GetType() == typeof(InputField)) 11 | { 12 | Text text = value as Text; 13 | if (text != null) 14 | { 15 | text.Translate = false; 16 | } 17 | } 18 | } 19 | 20 | public void SetTextComponent(Text value) 21 | { 22 | if ((base.GetType() == typeof(InputField)) && (value != null)) 23 | { 24 | value.Translate = false; 25 | } 26 | } 27 | 28 | protected override void Start() 29 | { 30 | base.Start(); 31 | if (base.GetType() == typeof(InputField)) 32 | { 33 | InputField field1 = this as InputField; 34 | field1.placeholder = field1.placeholder; 35 | field1.textComponent = field1.textComponent; 36 | } 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/JsonConfig.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | //Sadly, Unity 4.x doesn't support JsonUtility. 8 | 9 | namespace UnityEngine.UI.Translation 10 | { 11 | 12 | 13 | public class SubtitleConfig 14 | { 15 | public int Anchor { get; set; } = 2; 16 | public string FontName { get; set; } 17 | public int FontSize { get; set; } = 16; 18 | public string FontColor { get; set; } 19 | public bool Bold { get; set; } = true; 20 | public bool Italic { get; set; } = false; 21 | public int BorderWidth { get; set; } = 2; 22 | public int ShadowOffset { get; set; } = 3; 23 | public int MarginLeft { get; set; } = 20; 24 | public int MarginTop { get; set; } = 20; 25 | public int MarginRight { get; set; } = 20; 26 | public int MarginBottom { get; set; } = 20; 27 | } 28 | 29 | public class TranslationConfig 30 | { 31 | public bool DebugMode { get; set; } = false; 32 | public string Language { get; set; } 33 | public bool FindImage { get; set; } = false; 34 | public bool FindAudio { get; set; } = false; 35 | public bool DumpAudioByLevel { get; set; } = false; 36 | public bool FindText { get; set; } = false; 37 | public bool DumpTextByLevel { get; set; } = false; 38 | public bool UseRegEx { get; set; } = false; 39 | public bool UseTextPrediction { get; set; } = false; 40 | public bool UseCopy2Clipboard { get; set; } = false; 41 | public int Copy2ClipboardTimeMs { get; set; } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/KeyTranslationData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal class KeyTranslationData : TranslationDataBase 6 | { 7 | public KeyTranslationData() 8 | { 9 | } 10 | 11 | public KeyTranslationData(string key, TranslationDataBase data) 12 | { 13 | if (data == null) 14 | { 15 | throw new ArgumentNullException("data"); 16 | } 17 | base.Path = data.Path; 18 | this.Key = key; 19 | base.Value = data.Value; 20 | } 21 | 22 | public KeyTranslationData(string path, string key, string value) : base(path, value) 23 | { 24 | this.Key = key; 25 | } 26 | 27 | public override string ToString() 28 | { 29 | return string.Format("{0} {{ \"{1}\", \"{2}\" }}", base.Path, this.Key, base.Value); 30 | } 31 | 32 | public string Key { get; private set; } 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/MaskableGraphicRawImage.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Threading; 4 | using UnityEngine.UI; 5 | namespace UnityEngine.UI.Translation 6 | { 7 | [BaseTypeOf("UnityEngine.UI.RawImage", "UnityEngine.UI.dll")] 8 | public class MaskableGraphicRawImage : MaskableGraphic 9 | { 10 | protected Texture2DOverrideData overrideData; 11 | 12 | protected MaskableGraphicRawImage() 13 | { 14 | } 15 | 16 | protected override void Awake() 17 | { 18 | base.Awake(); 19 | this.Swap(); 20 | } 21 | 22 | protected override void OnDestroy() 23 | { 24 | if (base.GetType() == typeof(RawImage)) 25 | { 26 | ThreadPool.QueueUserWorkItem(delegate (object x) { 27 | if (this.overrideData.OriginalTexture2D != null) 28 | { 29 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 30 | } 31 | }); 32 | } 33 | base.OnDestroy(); 34 | } 35 | 36 | private void SetOurOverrideTexture(ref U::UnityEngine.Texture value) 37 | { 38 | if (base.GetType() == typeof(RawImage)) 39 | { 40 | try 41 | { 42 | if (value == null) 43 | { 44 | if (this.overrideData.OriginalTexture2D != null) 45 | { 46 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 47 | } 48 | } 49 | else 50 | { 51 | U::UnityEngine.Texture2D textured = value as U::UnityEngine.Texture2D; 52 | if (textured != null) 53 | { 54 | if (this.overrideData.OriginalTexture2D != null) 55 | { 56 | int instanceID = textured.GetInstanceID(); 57 | if ((this.overrideData.InstanceID == instanceID) || (this.overrideData.OverrideID == instanceID)) 58 | { 59 | value = this.overrideData.OverrideTexture2D; 60 | return; 61 | } 62 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 63 | } 64 | Texture2DOverride.LoadTexture2D(((RawImage) this).name, textured, out this.overrideData); 65 | if (this.overrideData.OverrideTexture2D != null) 66 | { 67 | value = this.overrideData.OverrideTexture2D; 68 | } 69 | } 70 | } 71 | } 72 | catch (Exception exception) 73 | { 74 | IniSettings.Error("RawImageOverride:\n" + exception.ToString()); 75 | } 76 | } 77 | } 78 | 79 | protected void SetTexture(ref U::UnityEngine.Texture value) 80 | { 81 | if (base.GetType() == typeof(RawImage)) 82 | { 83 | this.SetOurOverrideTexture(ref value); 84 | } 85 | } 86 | 87 | protected override void Start() 88 | { 89 | base.Start(); 90 | this.Swap(); 91 | } 92 | 93 | protected void Swap() 94 | { 95 | if (base.GetType() == typeof(RawImage)) 96 | { 97 | ((RawImage) this).texture = ((RawImage) this).texture; 98 | } 99 | } 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/MaskableGraphicText.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Runtime.InteropServices; 5 | using Font = U::UnityEngine.Font; 6 | namespace UnityEngine.UI.Translation 7 | { 8 | [BaseTypeOf("UnityEngine.UI.Text", "UnityEngine.UI.dll")] 9 | public class MaskableGraphicText : MaskableGraphic 10 | { 11 | private bool textchanged; 12 | 13 | private string textcached; 14 | 15 | private string text2translate; 16 | 17 | private string text4translatetag1; 18 | 19 | private string text4translatetag2; 20 | 21 | private string _text4translate; 22 | 23 | private string texttranslated; 24 | 25 | private bool firstprediction; 26 | 27 | private bool predictionsfailed; 28 | 29 | private KeyTranslationData[] txtpredictions; 30 | 31 | private static List cpy2clip; 32 | 33 | private const float IDLECLIPTIME = 3f; 34 | 35 | private static float idlecliptime; 36 | 37 | private static float cliptime; 38 | 39 | private bool retranslatetext; 40 | 41 | private string text4translate 42 | { 43 | get 44 | { 45 | return this._text4translate; 46 | } 47 | set 48 | { 49 | this.text4translatetag1 = null; 50 | this._text4translate = value; 51 | this.text4translatetag2 = null; 52 | if (!string.IsNullOrEmpty(value)) 53 | { 54 | this._text4translate = this._text4translate.TrimStart(new char[0]); 55 | this.text4translatetag1 = value.Substring(0, value.Length - this._text4translate.Length); 56 | this._text4translate = this._text4translate.TrimEnd(new char[0]); 57 | this.text4translatetag2 = value.Remove(0, this.text4translatetag1.Length + this._text4translate.Length); 58 | this.text4translatetag2 = this.text4translatetag2.TrimEnd(new char[] { '\r', '\n' }); 59 | } 60 | } 61 | } 62 | 63 | public bool Translate 64 | { 65 | get; 66 | set; 67 | } 68 | 69 | static MaskableGraphicText() 70 | { 71 | IniSettings.FindTextChanged += new Action((bool value) => MaskableGraphicText.Retranslate()); 72 | MaskableGraphicText.cpy2clip = new List(); 73 | } 74 | 75 | protected MaskableGraphicText() 76 | { 77 | this.Translate = true; 78 | MaskableGraphicText.retranslate += new Action(this.RetranslateText); 79 | } 80 | 81 | private bool CanUseCache(string value) 82 | { 83 | if (value[0] != this.textcached[0] || value.Length <= this.textcached.Length) 84 | { 85 | return false; 86 | } 87 | bool flag = false; 88 | int num = 1; 89 | int num1 = 1; 90 | while (num1 < this.textcached.Length) 91 | { 92 | if (!flag) 93 | { 94 | if (value[num] != this.textcached[num1]) 95 | { 96 | if (value[num] != '\n') 97 | { 98 | return false; 99 | } 100 | flag = true; 101 | } 102 | else 103 | { 104 | num1++; 105 | } 106 | } 107 | else if (!char.IsWhiteSpace(value[num])) 108 | { 109 | if (value[num] != this.textcached[num1]) 110 | { 111 | return false; 112 | } 113 | flag = false; 114 | num1++; 115 | } 116 | else if (value[num] == this.textcached[num1]) 117 | { 118 | num1++; 119 | } 120 | num++; 121 | } 122 | while (num < value.Length) 123 | { 124 | if (!flag) 125 | { 126 | if (value[num] != '\n') 127 | { 128 | return false; 129 | } 130 | flag = true; 131 | } 132 | else if (!char.IsWhiteSpace(value[num])) 133 | { 134 | return false; 135 | } 136 | num++; 137 | } 138 | return true; 139 | } 140 | 141 | 142 | ~MaskableGraphicText() 143 | { 144 | retranslate -= new Action(this.RetranslateText); 145 | } 146 | 147 | private string InitialPrediction() 148 | { 149 | return this.text4translate; 150 | } 151 | 152 | private void LateUpdate() 153 | { 154 | TimeSpan timeSpan; 155 | if (!TextTranslator.Initialized) 156 | { 157 | return; 158 | } 159 | if (base.GetType() == typeof(Text)) 160 | { 161 | try 162 | { 163 | if (MaskableGraphicText.cpy2clip.Count > 0 && (U::UnityEngine.Time.time >= MaskableGraphicText.cliptime || U::UnityEngine.Time.time >= MaskableGraphicText.idlecliptime)) 164 | { 165 | if (MaskableGraphicText.NativeMethods.OpenClipboard(IntPtr.Zero)) 166 | { 167 | if (MaskableGraphicText.NativeMethods.EmptyClipboard()) 168 | { 169 | string empty = string.Empty; 170 | foreach (Text text in MaskableGraphicText.cpy2clip) 171 | { 172 | if (string.IsNullOrEmpty(text.text4translate)) 173 | { 174 | continue; 175 | } 176 | empty = string.Concat(empty, text.text4translate, Environment.NewLine); 177 | } 178 | uint length = (uint)((empty.Length + 1) * 2); 179 | IntPtr intPtr = MaskableGraphicText.NativeMethods.GlobalAlloc(66, new UIntPtr(length)); 180 | if (intPtr != IntPtr.Zero) 181 | { 182 | IntPtr hGlobalUni = Marshal.StringToHGlobalUni(empty); 183 | IntPtr intPtr1 = MaskableGraphicText.NativeMethods.GlobalLock(intPtr); 184 | if (intPtr1 != IntPtr.Zero) 185 | { 186 | MaskableGraphicText.NativeMethods.CopyMemory(intPtr1, hGlobalUni, length); 187 | MaskableGraphicText.NativeMethods.GlobalUnlock(intPtr1); 188 | MaskableGraphicText.NativeMethods.SetClipboardData(13, intPtr); 189 | } 190 | Marshal.FreeHGlobal(hGlobalUni); 191 | MaskableGraphicText.NativeMethods.GlobalFree(intPtr); 192 | } 193 | } 194 | MaskableGraphicText.NativeMethods.CloseClipboard(); 195 | } 196 | MaskableGraphicText.idlecliptime = 0f; 197 | MaskableGraphicText.cliptime = 0f; 198 | MaskableGraphicText.cpy2clip.Clear(); 199 | } 200 | } 201 | catch (Exception exception1) 202 | { 203 | Exception exception = exception1; 204 | MaskableGraphicText.idlecliptime = 0f; 205 | MaskableGraphicText.cliptime = 0f; 206 | MaskableGraphicText.cpy2clip.Clear(); 207 | IniSettings.Error(string.Concat("MaskableGraphicText::LateUpdate::Copy2Clipboard:\n", exception.ToString())); 208 | } 209 | try 210 | { 211 | if (this.textchanged) 212 | { 213 | this.textchanged = false; 214 | this.textcached = null; 215 | if (!TextTranslator.IsNotValidString(this.text4translate)) 216 | { 217 | if (IniSettings.UseCopy2Clipboard) 218 | { 219 | timeSpan = (IniSettings.Copy2ClipboardTime >= 1 ? TimeSpan.FromMilliseconds((double)IniSettings.Copy2ClipboardTime) : TimeSpan.FromMilliseconds(1)); 220 | float single = U::UnityEngine.Time.time + Convert.ToSingle(timeSpan.TotalSeconds); 221 | MaskableGraphicText.cliptime = single; 222 | if (MaskableGraphicText.idlecliptime == 0f) 223 | { 224 | MaskableGraphicText.idlecliptime = single + 3f; 225 | } 226 | if (!MaskableGraphicText.cpy2clip.Contains((Text)this)) 227 | { 228 | MaskableGraphicText.cpy2clip.Add((Text)this); 229 | } 230 | } 231 | string value = this.text4translate; 232 | if (this.txtpredictions != null || this.firstprediction) 233 | { 234 | if (this.firstprediction) 235 | { 236 | this.firstprediction = false; 237 | this.txtpredictions = TextTranslator.FindPredictions(this.text4translate, null); 238 | } 239 | else if ((int)this.txtpredictions.Length > 1) 240 | { 241 | this.txtpredictions = TextTranslator.FindPredictions(this.text4translate, this.txtpredictions); 242 | } 243 | if (this.txtpredictions.Length == 0) 244 | { 245 | this.predictionsfailed = true; 246 | this.txtpredictions = null; 247 | TextTranslator.Translate(ref value); 248 | } 249 | else if ((int)this.txtpredictions.Length != 1) 250 | { 251 | value = this.InitialPrediction(); 252 | } 253 | else if (this.txtpredictions[0].Key.Length > this.text4translate.Length && this.txtpredictions[0].Key.StartsWith(this.text4translate)) 254 | { 255 | if (!string.IsNullOrEmpty(this.txtpredictions[0].Value)) 256 | { 257 | float length1 = (float)this.text4translate.Length / (float)this.txtpredictions[0].Key.Length; 258 | int num = Convert.ToInt32((float)this.txtpredictions[0].Value.Length * length1); 259 | value = this.txtpredictions[0].Value.Substring(0, num); 260 | Text text1 = this as Text; 261 | TextTranslator.ApplyFontSettings(text1); 262 | U::UnityEngine.TextGenerationSettings generationSettings = text1.GetGenerationSettings(text1.rectTransform.rect.size); 263 | U::UnityEngine.TextGenerator textGenerator = new U::UnityEngine.TextGenerator(); 264 | textGenerator.Populate(this.txtpredictions[0].Value, generationSettings); 265 | if (textGenerator.lineCount > 1) 266 | { 267 | int num1 = textGenerator.lineCount - 1; 268 | while (num1 >= 1) 269 | { 270 | U::UnityEngine.UILineInfo item = textGenerator.lines[num1]; 271 | if (value.Length < item.startCharIdx) 272 | { 273 | num1--; 274 | } 275 | else 276 | { 277 | if (value.Length == item.startCharIdx || value == this.txtpredictions[0].Value || value[item.startCharIdx - 1] == '\n') 278 | { 279 | goto Label1; 280 | } 281 | value = value.Insert(item.startCharIdx, "\n"); 282 | goto Label1; 283 | } 284 | } 285 | } 286 | } 287 | } 288 | else if (this.txtpredictions[0].Key != this.text4translate) 289 | { 290 | this.predictionsfailed = true; 291 | this.txtpredictions = null; 292 | } 293 | else 294 | { 295 | if (!string.IsNullOrEmpty(this.txtpredictions[0].Value)) 296 | { 297 | value = this.txtpredictions[0].Value; 298 | } 299 | this.txtpredictions = null; 300 | } 301 | } 302 | else if (!TextTranslator.Translate(ref value) && IniSettings.UseTextPrediction && !this.predictionsfailed) 303 | { 304 | this.firstprediction = true; 305 | } 306 | Label1: 307 | if (value != this.text4translate) 308 | { 309 | value = string.Concat(this.text4translatetag1, value, this.text4translatetag2); 310 | this.texttranslated = value; 311 | ((Text)this).text = value; 312 | TextTranslator.ApplyFontSettings((Text)this); 313 | } 314 | } 315 | else 316 | { 317 | return; 318 | } 319 | } 320 | else if (this.retranslatetext) 321 | { 322 | this.retranslatetext = false; 323 | if (!string.IsNullOrEmpty(this.text4translate)) 324 | { 325 | string str = this.text4translate; 326 | string str1 = this.text2translate; 327 | this.ResetTextPredictions(); 328 | this.text2translate = null; 329 | this.text4translate = null; 330 | this.texttranslated = null; 331 | ((Text)this).text = str; 332 | ((Text)this).text = str1; 333 | this.LateUpdate(); 334 | } 335 | } 336 | } 337 | catch (Exception exception3) 338 | { 339 | Exception exception2 = exception3; 340 | this.textchanged = false; 341 | this.textcached = null; 342 | IniSettings.Error(string.Concat("MaskableGraphicText::LateUpdate:\n", exception2.ToString())); 343 | } 344 | } 345 | } 346 | 347 | private void ResetTextPredictions() 348 | { 349 | this.firstprediction = false; 350 | this.predictionsfailed = false; 351 | this.txtpredictions = null; 352 | } 353 | 354 | public static void Retranslate() 355 | { 356 | Action action = MaskableGraphicText.retranslate; 357 | if (action != null) 358 | { 359 | action(); 360 | } 361 | } 362 | 363 | private void RetranslateText() 364 | { 365 | this.retranslatetext = true; 366 | } 367 | 368 | protected void SetText(ref string value) 369 | { 370 | if (!TextTranslator.Initialized || !this.Translate) 371 | { 372 | return; 373 | } 374 | if (base.GetType() == typeof(Text)) 375 | { 376 | if (value == this.texttranslated) 377 | { 378 | return; 379 | } 380 | if (value == this.text2translate) 381 | { 382 | value = this.texttranslated; 383 | return; 384 | } 385 | if (string.IsNullOrEmpty(value)) 386 | { 387 | this.textchanged = false; 388 | this.textcached = null; 389 | this.ResetTextPredictions(); 390 | this.text2translate = value; 391 | this.text4translate = value; 392 | this.texttranslated = value; 393 | return; 394 | } 395 | if (this.textcached == null) 396 | { 397 | this.textchanged = true; 398 | this.textcached = value; 399 | if (!string.IsNullOrEmpty(this.text4translate) && !value.StartsWith(this.text4translate)) 400 | { 401 | this.ResetTextPredictions(); 402 | } 403 | this.text2translate = value; 404 | this.text4translate = value; 405 | this.texttranslated = value; 406 | return; 407 | } 408 | if (this.CanUseCache(value)) 409 | { 410 | this.text2translate = value; 411 | this.text4translate = this.textcached; 412 | this.texttranslated = value; 413 | return; 414 | } 415 | this.text2translate = value; 416 | this.text4translate = value; 417 | this.texttranslated = value; 418 | } 419 | } 420 | 421 | protected override void Start() 422 | { 423 | base.Start(); 424 | this.TranslateText(); 425 | } 426 | 427 | private void TranslateText() 428 | { 429 | if (base.GetType() == typeof(Text)) 430 | { 431 | this.retranslatetext = false; 432 | ((Text)this).text = ((Text)this).text; 433 | } 434 | } 435 | 436 | private static event Action retranslate; 437 | 438 | private class NativeMethods 439 | { 440 | public NativeMethods() 441 | { 442 | } 443 | 444 | [DllImport("user32.dll", CharSet=CharSet.None, ExactSpelling=false)] 445 | internal static extern bool CloseClipboard(); 446 | 447 | [DllImport("msvcrt.dll", CharSet=CharSet.None, EntryPoint="memcpy", ExactSpelling=false)] 448 | internal static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); 449 | 450 | [DllImport("user32.dll", CharSet=CharSet.None, ExactSpelling=false)] 451 | internal static extern bool EmptyClipboard(); 452 | 453 | [DllImport("kernel32.dll", CharSet=CharSet.None, ExactSpelling=false)] 454 | internal static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes); 455 | 456 | [DllImport("kernel32.dll", CharSet=CharSet.None, ExactSpelling=false)] 457 | internal static extern IntPtr GlobalFree(IntPtr hMem); 458 | 459 | [DllImport("kernel32.dll", CharSet=CharSet.None, ExactSpelling=false)] 460 | internal static extern IntPtr GlobalLock(IntPtr hMem); 461 | 462 | [DllImport("kernel32.dll", CharSet=CharSet.None, ExactSpelling=false)] 463 | internal static extern bool GlobalUnlock(IntPtr hMem); 464 | 465 | [DllImport("user32.dll", CharSet=CharSet.None, ExactSpelling=false)] 466 | internal static extern bool OpenClipboard(IntPtr hWndNewOwner); 467 | 468 | [DllImport("user32.dll", CharSet=CharSet.None, ExactSpelling=false)] 469 | internal static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem); 470 | } 471 | } 472 | } -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/MaterialOverride.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Threading; 4 | using Texture2D = U::UnityEngine.Texture2D; 5 | using Material = U::UnityEngine.Material; 6 | using Texture = U::UnityEngine.Texture; 7 | namespace UnityEngine.UI.Translation 8 | { 9 | [BaseTypeOf("UnityEngine.Material", "UnityEngine.dll")] 10 | public class MaterialOverride : U::UnityEngine.Object 11 | { 12 | private Texture2DOverrideData overrideData; 13 | 14 | protected MaterialOverride() 15 | { 16 | } 17 | 18 | ~MaterialOverride() 19 | { 20 | if (base.GetType() == typeof(Material)) 21 | { 22 | ThreadPool.QueueUserWorkItem(delegate (object x) 23 | { 24 | if (this.overrideData.OriginalTexture2D != null) 25 | { 26 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 27 | } 28 | }); 29 | } 30 | } 31 | 32 | protected void Swap(ref Texture value) 33 | { 34 | if (base.GetType() == typeof(Material)) 35 | { 36 | try 37 | { 38 | if (value == null) 39 | { 40 | if (this.overrideData.OriginalTexture2D != null) 41 | { 42 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 43 | } 44 | } 45 | else 46 | { 47 | Texture2D textured = value as Texture2D; 48 | if (textured != null) 49 | { 50 | if (this.overrideData.OriginalTexture2D != null) 51 | { 52 | int instanceID = textured.GetInstanceID(); 53 | if ((this.overrideData.InstanceID == instanceID) || (this.overrideData.OverrideID == instanceID)) 54 | { 55 | value = this.overrideData.OverrideTexture2D; 56 | return; 57 | } 58 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 59 | } 60 | Texture2DOverride.LoadTexture2D(((Material)this).name, textured, out this.overrideData); 61 | if (this.overrideData.OverrideTexture2D != null) 62 | { 63 | value = this.overrideData.OverrideTexture2D; 64 | } 65 | } 66 | } 67 | } 68 | catch (Exception exception) 69 | { 70 | IniSettings.Error("MaterialOverride:\n" + exception.ToString()); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/RegexTranslationData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal class RegexTranslationData : TranslationData 4 | { 5 | public RegexTranslationData() 6 | { 7 | } 8 | 9 | public RegexTranslationData(string path, string key, string value) : base(path, key, value) 10 | { 11 | } 12 | 13 | public override string ToString() 14 | { 15 | return string.Format("{0} {{ \"{1}\", \"{2}\" }}", base.Path, base.Key, base.Value); 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SpriteOverride.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Threading; 4 | using Sprite = U::UnityEngine.Sprite; 5 | using Texture2D = U::UnityEngine.Texture2D; 6 | namespace UnityEngine.UI.Translation 7 | { 8 | [BaseTypeOf("UnityEngine.Sprite", "UnityEngine.dll")] 9 | public class SpriteOverride : U::UnityEngine.Object 10 | { 11 | private Texture2DOverrideData overrideData; 12 | 13 | protected SpriteOverride() 14 | { 15 | } 16 | 17 | ~SpriteOverride() 18 | { 19 | if (base.GetType() == typeof(Sprite)) 20 | { 21 | ThreadPool.QueueUserWorkItem(delegate (object x) { 22 | if (this.overrideData.OriginalTexture2D != null) 23 | { 24 | Texture2DOverride.UnloadTexture2D(ref this.overrideData); 25 | } 26 | }); 27 | } 28 | } 29 | 30 | protected Texture2D GetTexture() 31 | { 32 | if (base.GetType() != typeof(Sprite)) 33 | { 34 | return null; 35 | } 36 | Texture2D textured = ((Sprite) this)._get_texture(); 37 | try 38 | { 39 | if (textured == null) 40 | { 41 | return textured; 42 | } 43 | if (this.overrideData.OriginalTexture2D != null) 44 | { 45 | return this.overrideData.OverrideTexture2D; 46 | } 47 | Texture2DOverride.LoadTexture2D(((Sprite) this).name, textured, out this.overrideData); 48 | if (this.overrideData.OverrideTexture2D != null) 49 | { 50 | textured = this.overrideData.OverrideTexture2D; 51 | } 52 | } 53 | catch (Exception exception) 54 | { 55 | IniSettings.Error("SpriteOverride:\n" + exception.ToString()); 56 | } 57 | return textured; 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Subtitle.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace UnityEngine.UI.Translation 7 | { 8 | internal class Subtitle : ISubtitle 9 | { 10 | private IEnumerable anchors; 11 | private Dictionary content; 12 | private Dictionary> display; 13 | private bool invalid; 14 | private bool loaded; 15 | private LineData[] subtitles; 16 | 17 | public Subtitle(IEnumerable anchors, U::UnityEngine.AudioSource source) 18 | { 19 | this.anchors = anchors; 20 | this.content = new Dictionary(); 21 | this.display = new Dictionary>(); 22 | foreach (TextPosition position in this.anchors) 23 | { 24 | this.content.Add(position, new StringBuilder(0x200)); 25 | this.display.Add(position, new HashSet()); 26 | } 27 | this.Source = source; 28 | this.Load(); 29 | } 30 | 31 | private StringBuilder ClearContent(StringBuilder sb) 32 | { 33 | if (sb.Length > 0) 34 | { 35 | sb.Length = 0; 36 | } 37 | return sb; 38 | } 39 | 40 | public void LateUpdate() 41 | { 42 | try 43 | { 44 | if (((this.Source != null) && (this.Clip != null)) && (this.Source.clip == this.Clip)) 45 | { 46 | int num = (this.Clip.frequency == 0) ? 0xac44 : this.Clip.frequency; 47 | float num2 = this.Source.timeSamples * (1f / ((float) num)); 48 | foreach (LineData data in this.subtitles) 49 | { 50 | if (data != null) 51 | { 52 | if ((this.Source.isPlaying && ((data.Line.EndTime == 0f) || (num2 < data.Line.EndTime))) && (num2 >= data.Line.StartTime)) 53 | { 54 | this.invalid |= data.Show(); 55 | } 56 | else 57 | { 58 | this.invalid |= data.Hide(); 59 | } 60 | } 61 | } 62 | if (this.invalid) 63 | { 64 | foreach (KeyValuePair> pair in this.display) 65 | { 66 | StringBuilder builder = this.ClearContent(this.content[pair.Key]); 67 | foreach (SubtitleLine line2 in pair.Value) 68 | { 69 | if (builder.Length > 0) 70 | { 71 | builder.Append('\n'); 72 | } 73 | builder.Append(line2.Text); 74 | } 75 | } 76 | this.invalid = false; 77 | } 78 | } 79 | else if (this.loaded) 80 | { 81 | this.Unload(); 82 | } 83 | } 84 | catch (Exception exception) 85 | { 86 | IniSettings.Error("Subtitle::LateUpdate:\n" + exception.ToString()); 87 | } 88 | } 89 | 90 | private void Load() 91 | { 92 | if ((this.Source != null) && (this.Source.clip != null)) 93 | { 94 | this.Clip = this.Source.clip; 95 | this.LoadSubtitles(); 96 | this.invalid = true; 97 | this.loaded = true; 98 | } 99 | } 100 | 101 | private void LoadSubtitles() 102 | { 103 | if ((this.Clip == null) || string.IsNullOrEmpty(this.Clip.name)) 104 | { 105 | this.subtitles = new LineData[0]; 106 | } 107 | else 108 | { 109 | SubtitleLine[] lineArray; 110 | foreach (TextPosition position in this.anchors) 111 | { 112 | this.display[position].Clear(); 113 | this.ClearContent(this.content[position]); 114 | } 115 | if (SubtitleTranslator.Translate(this.Clip.name, out lineArray)) 116 | { 117 | this.subtitles = new LineData[lineArray.Length]; 118 | for (int i = 0; i < this.subtitles.Length; i++) 119 | { 120 | HashSet set; 121 | if (this.display.TryGetValue(lineArray[i].Position, out set)) 122 | { 123 | this.subtitles[i] = new LineData(lineArray[i], set); 124 | } 125 | } 126 | } 127 | else 128 | { 129 | this.subtitles = new LineData[0]; 130 | } 131 | } 132 | } 133 | 134 | public void Reload() 135 | { 136 | this.LoadSubtitles(); 137 | } 138 | 139 | private void Unload() 140 | { 141 | this.Clip = null; 142 | this.Source = null; 143 | this.subtitles = null; 144 | foreach (TextPosition position in this.display.Keys) 145 | { 146 | this.display[position].Clear(); 147 | this.ClearContent(this.content[position]); 148 | } 149 | this.invalid = false; 150 | this.loaded = false; 151 | } 152 | 153 | public U::UnityEngine.AudioClip Clip { get; private set; } 154 | 155 | public string this[TextPosition anchor] 156 | { 157 | get 158 | { 159 | return this.content[anchor].ToString(); 160 | } 161 | } 162 | 163 | public U::UnityEngine.AudioSource Source { get; private set; } 164 | 165 | private class LineData 166 | { 167 | private readonly HashSet anchor; 168 | 169 | public LineData(SubtitleLine line, HashSet anchor) 170 | { 171 | this.Line = line; 172 | this.Visible = false; 173 | this.anchor = anchor; 174 | } 175 | 176 | public bool Hide() 177 | { 178 | bool flag = false; 179 | if (this.Visible) 180 | { 181 | flag = this.anchor.Remove(this.Line); 182 | this.Visible = !flag; 183 | } 184 | return flag; 185 | } 186 | 187 | public bool Show() 188 | { 189 | bool flag = false; 190 | if (!this.Visible) 191 | { 192 | flag = this.anchor.Add(this.Line); 193 | this.Visible = flag; 194 | } 195 | return flag; 196 | } 197 | 198 | public SubtitleLine Line { get; private set; } 199 | 200 | public bool Visible { get; private set; } 201 | } 202 | } 203 | } 204 | 205 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleCanvas.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | using Canvas = U::UnityEngine.Canvas; 7 | using Font = U::UnityEngine.Font; 8 | using RenderMode = U::UnityEngine.RenderMode; 9 | using GameObject = U::UnityEngine.GameObject; 10 | using TextAnchor = U::UnityEngine.TextAnchor; 11 | using Vector2 = U::UnityEngine.Vector2; 12 | using Color = U::UnityEngine.Color; 13 | using FontStyle = U::UnityEngine.FontStyle; 14 | using Screen = U::UnityEngine.Screen; 15 | using Mathf = U::UnityEngine.Mathf; 16 | 17 | namespace UnityEngine.UI.Translation 18 | { 19 | internal class SubtitleCanvas : SubtitleUserInterfaceBase, ISubtitleBorder, ISubtitleShadow 20 | { 21 | private int _BorderWidth = 1; 22 | private int _ShadowOffset = 1; 23 | private Dictionary anchors = new Dictionary(); 24 | private Canvas canvas; 25 | private static Func CreateDynamicFontFromOSFont; 26 | private const int DEFAULT_BORDER_WIDTH = 1; 27 | private float dpi; 28 | 29 | static SubtitleCanvas() 30 | { 31 | System.Type[] types = new System.Type[] { typeof(string), typeof(int) }; 32 | MethodInfo method = typeof(Font).GetMethod("CreateDynamicFontFromOSFont", BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, types, null); 33 | if (method != null) 34 | { 35 | CreateDynamicFontFromOSFont = (Func) Delegate.CreateDelegate(typeof(Func), method); 36 | } 37 | } 38 | 39 | protected override void Awake() 40 | { 41 | this.canvas = base.gameObject.AddComponent(); 42 | this.canvas.renderMode = RenderMode.ScreenSpaceOverlay; 43 | this.canvas.sortingOrder = 0x7fff; 44 | HashSet set = new HashSet(); 45 | foreach (TextPosition position in (TextPosition[]) Enum.GetValues(typeof(TextPosition))) 46 | { 47 | if (!set.Contains(position)) 48 | { 49 | set.Add(position); 50 | GameObject obj1 = new GameObject("Subtitle" + position.ToString()); 51 | obj1.transform.SetParent(base.transform, false); 52 | Text text = obj1.AddComponent(); 53 | text.Translate = false; 54 | this.SetTextFont(text, base.FontName); 55 | this.SetTextSize(text, base.FontSize); 56 | this.SetTextColor(text, base.FontColor); 57 | this.SetTextStyle(text, false, false); 58 | this.SetTextAlignment(text, position); 59 | this.SetTextMargin(text, 0f, 0f, 0f, 0f); 60 | Outline border = obj1.AddComponent(); 61 | this.SetTextBorder(border, this.BorderWidth); 62 | Shadow shadow = obj1.AddComponent(); 63 | this.SetTextShadow(shadow, this.ShadowOffset); 64 | this.anchors.Add(position, new TextData(text, border, shadow)); 65 | } 66 | } 67 | } 68 | 69 | private void ChangeTextSettings(Action action) 70 | { 71 | if (action != null) 72 | { 73 | foreach (KeyValuePair pair in this.anchors) 74 | { 75 | action(pair.Key, pair.Value); 76 | } 77 | } 78 | } 79 | 80 | public void Clear() 81 | { 82 | foreach (KeyValuePair pair in this.anchors) 83 | { 84 | pair.Value.Text.text = string.Empty; 85 | } 86 | } 87 | 88 | private void LateUpdate() 89 | { 90 | this.UpdateCanvasScaleFactor(); 91 | } 92 | 93 | protected virtual void OnFontBorderChanged(object sender, FontBorderChangedEventArgs e) 94 | { 95 | this.ChangeTextSettings((position, data) => this.SetTextBorder(data.Border, e.BorderWidth)); 96 | } 97 | 98 | protected override void OnFontColorChanged(object sender, FontColorChangedEventArgs e) 99 | { 100 | this.ChangeTextSettings((position, data) => this.SetTextColor(data.Text, e.FontColor)); 101 | } 102 | 103 | protected override void OnFontMarginChanged(object sender, FontMarginChangedEventArgs e) 104 | { 105 | this.ChangeTextSettings((position, data) => this.SetTextMargin(data.Text, e.MarginLeft, e.MarginTop, e.MarginRight, e.MarginBottom)); 106 | } 107 | 108 | protected override void OnFontNameChanged(object sender, FontNameChangedEventArgs e) 109 | { 110 | this.ChangeTextSettings((position, data) => this.SetTextFont(data.Text, e.FontName)); 111 | } 112 | 113 | protected virtual void OnFontShadowChanged(object sender, FontShadowChangedEventArgs e) 114 | { 115 | this.ChangeTextSettings((position, data) => this.SetTextShadow(data.Shadow, e.ShadowOffset)); 116 | } 117 | 118 | protected override void OnFontSizeChanged(object sender, FontSizeChangedEventArgs e) 119 | { 120 | this.ChangeTextSettings((position, data) => this.SetTextSize(data.Text, e.FontSize)); 121 | } 122 | 123 | protected override void OnFontStyleChanged(object sender, FontStyleChangedEventArgs e) 124 | { 125 | this.ChangeTextSettings((position, data) => this.SetTextStyle(data.Text, e.Bold, e.Italic)); 126 | } 127 | 128 | private void SetTextAlignment(Text text, TextPosition position) 129 | { 130 | switch (position) 131 | { 132 | case TextPosition.LowerLeft: 133 | text.alignment = TextAnchor.LowerLeft; 134 | return; 135 | 136 | case TextPosition.LowerCenter: 137 | text.alignment = TextAnchor.LowerCenter; 138 | return; 139 | 140 | case TextPosition.LowerRight: 141 | text.alignment = TextAnchor.LowerRight; 142 | return; 143 | 144 | case TextPosition.MiddleLeft: 145 | text.alignment = TextAnchor.MiddleLeft; 146 | return; 147 | 148 | case TextPosition.MiddleCenter: 149 | text.alignment = TextAnchor.MiddleCenter; 150 | return; 151 | 152 | case TextPosition.MiddleRight: 153 | text.alignment = TextAnchor.MiddleRight; 154 | return; 155 | 156 | case TextPosition.UpperLeft: 157 | text.alignment = TextAnchor.UpperLeft; 158 | return; 159 | 160 | case TextPosition.UpperCenter: 161 | text.alignment = TextAnchor.UpperCenter; 162 | return; 163 | 164 | case TextPosition.UpperRight: 165 | text.alignment = TextAnchor.UpperRight; 166 | return; 167 | } 168 | text.alignment = TextAnchor.LowerCenter; 169 | } 170 | 171 | private void SetTextBorder(Outline border, int distance) 172 | { 173 | border.enabled = distance > 0; 174 | border.effectDistance = new Vector2((float) distance, (float) -distance); 175 | } 176 | 177 | private void SetTextColor(Text text, Color color) 178 | { 179 | text.color = color; 180 | } 181 | 182 | private void SetTextFont(Text text, string name) 183 | { 184 | if (CreateDynamicFontFromOSFont != null) 185 | { 186 | text.font = CreateDynamicFontFromOSFont(name, text.fontSize); 187 | } 188 | else 189 | { 190 | text.font = U::UnityEngine.Resources.GetBuiltinResource("Arial.ttf"); 191 | } 192 | } 193 | 194 | private void SetTextMargin(Text text, float left, float top, float right, float bottom) 195 | { 196 | text.rectTransform.anchorMin = Vector2.zero; 197 | text.rectTransform.offsetMin = new Vector2(left, bottom); 198 | text.rectTransform.anchorMax = Vector2.one; 199 | text.rectTransform.offsetMax = new Vector2(-right, -top); 200 | } 201 | 202 | private void SetTextShadow(Shadow shadow, int distance) 203 | { 204 | shadow.enabled = distance > 0; 205 | shadow.effectDistance = new Vector2((float) distance, (float) -distance); 206 | } 207 | 208 | private void SetTextSize(Text text, int size) 209 | { 210 | text.fontSize = size; 211 | } 212 | 213 | private void SetTextStyle(Text text, bool bold, bool italic) 214 | { 215 | if (bold) 216 | { 217 | if (italic) 218 | { 219 | text.fontStyle = FontStyle.BoldAndItalic; 220 | } 221 | else 222 | { 223 | text.fontStyle = FontStyle.Bold; 224 | } 225 | } 226 | else if (italic) 227 | { 228 | text.fontStyle = FontStyle.Italic; 229 | } 230 | else 231 | { 232 | text.fontStyle = FontStyle.Normal; 233 | } 234 | } 235 | 236 | private void UpdateCanvasScaleFactor() 237 | { 238 | float dpi = Screen.dpi; 239 | if (this.dpi != dpi) 240 | { 241 | this.dpi = dpi; 242 | dpi = (this.dpi == 0f) ? 72f : this.dpi; 243 | this.canvas.scaleFactor = dpi / 72f; 244 | } 245 | } 246 | 247 | public override IEnumerable Anchors 248 | { 249 | get 250 | { 251 | return this.anchors.Keys; 252 | } 253 | } 254 | 255 | public int BorderWidth 256 | { 257 | get 258 | { 259 | return this._BorderWidth; 260 | } 261 | set 262 | { 263 | value = Mathf.Min(Mathf.Max(value, 0), 1); 264 | if (value != this._BorderWidth) 265 | { 266 | this._BorderWidth = value; 267 | this.OnFontBorderChanged(this, new FontBorderChangedEventArgs(value)); 268 | } 269 | } 270 | } 271 | 272 | public override string this[TextPosition anchor] 273 | { 274 | get 275 | { 276 | TextData data; 277 | if (!this.anchors.TryGetValue(anchor, out data)) 278 | { 279 | throw new ArgumentOutOfRangeException("anchor"); 280 | } 281 | return data.Text.text; 282 | } 283 | set 284 | { 285 | TextData data; 286 | if (!this.anchors.TryGetValue(anchor, out data)) 287 | { 288 | throw new ArgumentOutOfRangeException("anchor"); 289 | } 290 | if (value == null) 291 | { 292 | value = string.Empty; 293 | } 294 | if (data.Text.text != value) 295 | { 296 | data.Text.text = value; 297 | } 298 | } 299 | } 300 | 301 | public int ShadowOffset 302 | { 303 | get 304 | { 305 | return this._ShadowOffset; 306 | } 307 | set 308 | { 309 | value = Mathf.Min(Mathf.Max(value, 0), 1); 310 | if (value != this._ShadowOffset) 311 | { 312 | this._ShadowOffset = value; 313 | this.OnFontShadowChanged(this, new FontShadowChangedEventArgs(value)); 314 | } 315 | } 316 | } 317 | 318 | [StructLayout(LayoutKind.Sequential)] 319 | private struct TextData 320 | { 321 | private UnityEngine.UI.Text _Text; 322 | private Outline _Border; 323 | private UnityEngine.UI.Shadow _Shadow; 324 | public UnityEngine.UI.Text Text 325 | { 326 | get 327 | { 328 | return this._Text; 329 | } 330 | } 331 | public Outline Border 332 | { 333 | get 334 | { 335 | return this._Border; 336 | } 337 | } 338 | public UnityEngine.UI.Shadow Shadow 339 | { 340 | get 341 | { 342 | return this._Shadow; 343 | } 344 | } 345 | public TextData(UnityEngine.UI.Text text, Outline border, UnityEngine.UI.Shadow shadow) 346 | { 347 | this._Text = text; 348 | this._Border = border; 349 | this._Shadow = shadow; 350 | } 351 | } 352 | } 353 | } 354 | 355 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System.Collections.Generic; 4 | 5 | internal class SubtitleData : SubtitleDataBase 6 | { 7 | public SubtitleData() 8 | { 9 | } 10 | 11 | public SubtitleData(string path) : base(path) 12 | { 13 | } 14 | 15 | public SubtitleData(string path, List value) : base(path, value) 16 | { 17 | } 18 | 19 | public SubtitleData(string path, string key, List value) : base(path, value) 20 | { 21 | this.Key = key; 22 | } 23 | 24 | public override string ToString() 25 | { 26 | return string.Format("{0} {{ \"{1}\" ({2}) }}", base.Path, this.Key, base.Value.Count); 27 | } 28 | 29 | public string Key { get; protected set; } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleDataBase.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System.Collections.Generic; 4 | 5 | internal class SubtitleDataBase 6 | { 7 | public SubtitleDataBase() 8 | { 9 | } 10 | 11 | public SubtitleDataBase(string path) : this(path, new List()) 12 | { 13 | } 14 | 15 | public SubtitleDataBase(string path, List value) 16 | { 17 | this.Path = path; 18 | this.Value = value; 19 | } 20 | 21 | public override string ToString() 22 | { 23 | return string.Format("{0} {{ \"{1}\" }}", this.Path, this.Value); 24 | } 25 | 26 | public string Path { get; protected set; } 27 | 28 | public List Value { get; protected set; } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleLine.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System.Runtime.InteropServices; 4 | 5 | [StructLayout(LayoutKind.Sequential)] 6 | internal struct SubtitleLine 7 | { 8 | public TextPosition Position { get; set; } 9 | public float StartTime { get; set; } 10 | public float EndTime { get; set; } 11 | public string Text { get; set; } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleSettings.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Globalization; 4 | using System.IO; 5 | using Color32 = U::UnityEngine.Color32; 6 | using Color = U::UnityEngine.Color; 7 | using JsonUtility = U::UnityEngine.JsonUtility; 8 | 9 | namespace UnityEngine.UI.Translation 10 | { 11 | internal static class ColorUtility 12 | { 13 | public static Color32 ToColor(string hex) 14 | { 15 | if ((string.IsNullOrEmpty(hex) || !hex.StartsWith("#")) || (hex.Length != 7)) 16 | { 17 | return Color.white; 18 | } 19 | byte g = byte.Parse(hex.Substring(3, 2), NumberStyles.HexNumber); 20 | return new Color32(byte.Parse(hex.Substring(1, 2), NumberStyles.HexNumber), g, byte.Parse(hex.Substring(5, 2), NumberStyles.HexNumber), 0xff); 21 | } 22 | 23 | public static string ToHex(Color32 color) 24 | { 25 | return (("#" + color.r.ToString("X2")) + color.g.ToString("X2") + color.b.ToString("X2")); 26 | } 27 | } 28 | 29 | internal static class SubtitleSettings 30 | { 31 | internal static string SettingsFileName => "Subtitle.json";//"Translation.ini"; 32 | 33 | internal static string SettingsFilePath => string.Concat(IniSettings.SettingsFileDir, SettingsFileName); 34 | 35 | private const string SECTION = "Subtitles"; 36 | 37 | private const string ANCHORKEY = "iAnchor"; 38 | 39 | private const string FONTNAMEKEY = "sFontName"; 40 | 41 | private const string FONTSIZEKEY = "iFontSize"; 42 | 43 | private const string FONTCOLORKEY = "sFontColor"; 44 | 45 | private const string BOLDKEY = "bBold"; 46 | 47 | private const string ITALICKEY = "bItalic"; 48 | 49 | private const string BORDERWIDTHKEY = "iBorderWidth"; 50 | 51 | private const string SHADOWOFFSETKEY = "iShadowOffset"; 52 | 53 | private const string MARGINLEFTKEY = "iMarginLeft"; 54 | 55 | private const string MARGINTOPKEY = "iMarginTop"; 56 | 57 | private const string MARGINRIGHTKEY = "iMarginRight"; 58 | 59 | private const string MARGINBOTTOMKEY = "iMarginBottom"; 60 | 61 | private static TextPosition _Anchor; 62 | 63 | private static string _FontName; 64 | 65 | private static int _FontSize; 66 | 67 | private static Color _FontColor; 68 | 69 | private static bool _Bold; 70 | 71 | private static bool _Italic; 72 | 73 | private static int _BorderWidth; 74 | 75 | private static int _ShadowOffset; 76 | 77 | private static int _MarginLeft; 78 | 79 | private static int _MarginTop; 80 | 81 | private static int _MarginRight; 82 | 83 | private static int _MarginBottom; 84 | 85 | private static bool initialized; 86 | 87 | internal static TextPosition Anchor 88 | { 89 | get 90 | { 91 | return SubtitleSettings._Anchor; 92 | } 93 | private set 94 | { 95 | if (value != SubtitleSettings._Anchor) 96 | { 97 | SubtitleSettings._Anchor = value; 98 | Action action = SubtitleSettings.AnchorChanged; 99 | if (action != null && SubtitleSettings.initialized) 100 | { 101 | action(value); 102 | } 103 | } 104 | } 105 | } 106 | 107 | internal static bool Bold 108 | { 109 | get 110 | { 111 | return SubtitleSettings._Bold; 112 | } 113 | private set 114 | { 115 | if (value != SubtitleSettings._Bold) 116 | { 117 | SubtitleSettings._Bold = value; 118 | Action action = SubtitleSettings.BoldChanged; 119 | if (action != null && SubtitleSettings.initialized) 120 | { 121 | action(value); 122 | } 123 | } 124 | } 125 | } 126 | 127 | internal static int BorderWidth 128 | { 129 | get 130 | { 131 | return SubtitleSettings._BorderWidth; 132 | } 133 | private set 134 | { 135 | if (value != SubtitleSettings._BorderWidth) 136 | { 137 | SubtitleSettings._BorderWidth = value; 138 | Action action = SubtitleSettings.BorderWidthChanged; 139 | if (action != null && SubtitleSettings.initialized) 140 | { 141 | action(value); 142 | } 143 | } 144 | } 145 | } 146 | 147 | internal static Color FontColor 148 | { 149 | get 150 | { 151 | return SubtitleSettings._FontColor; 152 | } 153 | private set 154 | { 155 | if (value != SubtitleSettings._FontColor) 156 | { 157 | SubtitleSettings._FontColor = value; 158 | Action action = SubtitleSettings.FontColorChanged; 159 | if (action != null && SubtitleSettings.initialized) 160 | { 161 | action(value); 162 | } 163 | } 164 | } 165 | } 166 | 167 | internal static string FontName 168 | { 169 | get 170 | { 171 | if (string.IsNullOrEmpty(SubtitleSettings._FontName)) 172 | { 173 | SubtitleSettings._FontName = "Arial"; 174 | } 175 | return SubtitleSettings._FontName; 176 | } 177 | private set 178 | { 179 | if (string.IsNullOrEmpty(value)) 180 | { 181 | value = "Arial"; 182 | } 183 | if (value != SubtitleSettings._FontName) 184 | { 185 | SubtitleSettings._FontName = value; 186 | Action action = SubtitleSettings.FontNameChanged; 187 | if (action != null && SubtitleSettings.initialized) 188 | { 189 | action(value); 190 | } 191 | } 192 | } 193 | } 194 | 195 | internal static int FontSize 196 | { 197 | get 198 | { 199 | return SubtitleSettings._FontSize; 200 | } 201 | private set 202 | { 203 | if (value != SubtitleSettings._FontSize) 204 | { 205 | SubtitleSettings._FontSize = value; 206 | Action action = SubtitleSettings.FontSizeChanged; 207 | if (action != null && SubtitleSettings.initialized) 208 | { 209 | action(value); 210 | } 211 | } 212 | } 213 | } 214 | 215 | internal static bool Italic 216 | { 217 | get 218 | { 219 | return SubtitleSettings._Italic; 220 | } 221 | private set 222 | { 223 | if (value != SubtitleSettings._Italic) 224 | { 225 | SubtitleSettings._Italic = value; 226 | Action action = SubtitleSettings.ItalicChanged; 227 | if (action != null && SubtitleSettings.initialized) 228 | { 229 | action(value); 230 | } 231 | } 232 | } 233 | } 234 | 235 | internal static int MarginBottom 236 | { 237 | get 238 | { 239 | return SubtitleSettings._MarginBottom; 240 | } 241 | private set 242 | { 243 | if (value != SubtitleSettings._MarginBottom) 244 | { 245 | SubtitleSettings._MarginBottom = value; 246 | Action action = SubtitleSettings.MarginBottomChanged; 247 | if (action != null && SubtitleSettings.initialized) 248 | { 249 | action(value); 250 | } 251 | } 252 | } 253 | } 254 | 255 | internal static int MarginLeft 256 | { 257 | get 258 | { 259 | return SubtitleSettings._MarginLeft; 260 | } 261 | private set 262 | { 263 | if (value != SubtitleSettings._MarginLeft) 264 | { 265 | SubtitleSettings._MarginLeft = value; 266 | Action action = SubtitleSettings.MarginLeftChanged; 267 | if (action != null && SubtitleSettings.initialized) 268 | { 269 | action(value); 270 | } 271 | } 272 | } 273 | } 274 | 275 | internal static int MarginRight 276 | { 277 | get 278 | { 279 | return SubtitleSettings._MarginRight; 280 | } 281 | private set 282 | { 283 | if (value != SubtitleSettings._MarginRight) 284 | { 285 | SubtitleSettings._MarginRight = value; 286 | Action action = SubtitleSettings.MarginRightChanged; 287 | if (action != null && SubtitleSettings.initialized) 288 | { 289 | action(value); 290 | } 291 | } 292 | } 293 | } 294 | 295 | internal static int MarginTop 296 | { 297 | get 298 | { 299 | return SubtitleSettings._MarginTop; 300 | } 301 | private set 302 | { 303 | if (value != SubtitleSettings._MarginTop) 304 | { 305 | SubtitleSettings._MarginTop = value; 306 | Action action = SubtitleSettings.MarginTopChanged; 307 | if (action != null && SubtitleSettings.initialized) 308 | { 309 | action(value); 310 | } 311 | } 312 | } 313 | } 314 | 315 | internal static int ShadowOffset 316 | { 317 | get 318 | { 319 | return SubtitleSettings._ShadowOffset; 320 | } 321 | private set 322 | { 323 | if (value != SubtitleSettings._ShadowOffset) 324 | { 325 | SubtitleSettings._ShadowOffset = value; 326 | Action action = SubtitleSettings.ShadowOffsetChanged; 327 | if (action != null && SubtitleSettings.initialized) 328 | { 329 | action(value); 330 | } 331 | } 332 | } 333 | } 334 | 335 | static SubtitleSettings() 336 | { 337 | #if UNITY4 338 | IniSettings.LoadSettings += new Action(SubtitleSettings.LoadIni); 339 | IniSettings.LoadIni(); 340 | #else 341 | Load(); 342 | #endif 343 | } 344 | private static void Load() 345 | { 346 | var config = JsonUtility.FromJson(SettingsFilePath); 347 | if (config == null) 348 | { 349 | config = new SubtitleConfig(); 350 | File.WriteAllText(SettingsFilePath, JsonUtility.ToJson(config, true)); 351 | } 352 | Anchor = Anchor.Parse(config.Anchor.ToString(), SubtitleSettings.Anchor); 353 | FontName = config.FontName; 354 | FontSize = config.FontSize; 355 | FontColor = ColorUtility.ToColor(config.FontColor); 356 | Bold = config.Bold; 357 | Italic = config.Italic; 358 | BorderWidth = config.BorderWidth; 359 | ShadowOffset = config.ShadowOffset; 360 | MarginLeft = config.MarginLeft; 361 | MarginTop = config.MarginTop; 362 | MarginRight = config.MarginRight; 363 | MarginBottom = config.MarginBottom; 364 | SubtitleSettings.initialized = true; 365 | } 366 | 367 | private static void LoadIni(IniFile ini) 368 | { 369 | int num; 370 | bool flag; 371 | string str = "iAnchor"; 372 | string value = ini.GetValue("Subtitles", str, null); 373 | if (value == null || !int.TryParse(value, out num)) 374 | { 375 | num = 2; 376 | ini.WriteValue("Subtitles", str, num); 377 | } 378 | SubtitleSettings.Anchor = SubtitleSettings.Anchor.Parse(num.ToString(), SubtitleSettings.Anchor); 379 | str = "sFontName"; 380 | value = ini.GetValue("Subtitles", str, null); 381 | SubtitleSettings.FontName = value; 382 | if (value != SubtitleSettings.FontName) 383 | { 384 | ini.WriteValue("Subtitles", str, SubtitleSettings.FontName); 385 | } 386 | str = "iFontSize"; 387 | value = ini.GetValue("Subtitles", str, null); 388 | if (value == null || !int.TryParse(value, out num)) 389 | { 390 | num = 16; 391 | ini.WriteValue("Subtitles", str, num); 392 | } 393 | SubtitleSettings.FontSize = num; 394 | str = "sFontColor"; 395 | value = ini.GetValue("Subtitles", str, null); 396 | SubtitleSettings.FontColor = ColorUtility.ToColor(value); 397 | string hex = ColorUtility.ToHex(SubtitleSettings.FontColor); 398 | if (value != hex) 399 | { 400 | ini.WriteValue("Subtitles", str, hex); 401 | } 402 | str = "bBold"; 403 | value = ini.GetValue("Subtitles", str, null); 404 | if (value == null || !bool.TryParse(value, out flag)) 405 | { 406 | flag = true; 407 | ini.WriteValue("Subtitles", str, flag); 408 | } 409 | SubtitleSettings.Bold = flag; 410 | str = "bItalic"; 411 | value = ini.GetValue("Subtitles", str, null); 412 | if (value == null || !bool.TryParse(value, out flag)) 413 | { 414 | flag = false; 415 | ini.WriteValue("Subtitles", str, flag); 416 | } 417 | SubtitleSettings.Italic = flag; 418 | str = "iBorderWidth"; 419 | value = ini.GetValue("Subtitles", str, null); 420 | if (value == null || !int.TryParse(value, out num)) 421 | { 422 | num = 2; 423 | ini.WriteValue("Subtitles", str, num); 424 | } 425 | SubtitleSettings.BorderWidth = num; 426 | str = "iShadowOffset"; 427 | value = ini.GetValue("Subtitles", str, null); 428 | if (value == null || !int.TryParse(value, out num)) 429 | { 430 | num = 3; 431 | ini.WriteValue("Subtitles", str, num); 432 | } 433 | SubtitleSettings.ShadowOffset = num; 434 | str = "iMarginLeft"; 435 | value = ini.GetValue("Subtitles", str, null); 436 | if (value == null || !int.TryParse(value, out num)) 437 | { 438 | num = 20; 439 | ini.WriteValue("Subtitles", str, num); 440 | } 441 | SubtitleSettings.MarginLeft = num; 442 | str = "iMarginTop"; 443 | value = ini.GetValue("Subtitles", str, null); 444 | if (value == null || !int.TryParse(value, out num)) 445 | { 446 | num = 20; 447 | ini.WriteValue("Subtitles", str, num); 448 | } 449 | SubtitleSettings.MarginTop = num; 450 | str = "iMarginRight"; 451 | value = ini.GetValue("Subtitles", str, null); 452 | if (value == null || !int.TryParse(value, out num)) 453 | { 454 | num = 20; 455 | ini.WriteValue("Subtitles", str, num); 456 | } 457 | SubtitleSettings.MarginRight = num; 458 | str = "iMarginBottom"; 459 | value = ini.GetValue("Subtitles", str, null); 460 | if (value == null || !int.TryParse(value, out num)) 461 | { 462 | num = 20; 463 | ini.WriteValue("Subtitles", str, num); 464 | } 465 | SubtitleSettings.MarginBottom = num; 466 | SubtitleSettings.initialized = true; 467 | } 468 | 469 | internal static event Action AnchorChanged; 470 | 471 | internal static event Action BoldChanged; 472 | 473 | internal static event Action BorderWidthChanged; 474 | 475 | internal static event Action FontColorChanged; 476 | 477 | internal static event Action FontNameChanged; 478 | 479 | internal static event Action FontSizeChanged; 480 | 481 | internal static event Action ItalicChanged; 482 | 483 | internal static event Action MarginBottomChanged; 484 | 485 | internal static event Action MarginLeftChanged; 486 | 487 | internal static event Action MarginRightChanged; 488 | 489 | internal static event Action MarginTopChanged; 490 | 491 | internal static event Action ShadowOffsetChanged; 492 | } 493 | } -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleTranslator.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using Application = U::UnityEngine.Application; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Specialized; 6 | using System.Globalization; 7 | using System.IO; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading; 11 | using System.Timers; 12 | 13 | namespace UnityEngine.UI.Translation 14 | { 15 | internal static class SubtitleTranslator 16 | { 17 | private const string EXT = ".txt"; 18 | 19 | private const string FILENAME = "Subtitle"; 20 | 21 | private const string FILE = "{0}.txt"; 22 | 23 | private const string LVFILE = "{0}.{1}.txt"; 24 | 25 | private const string IGNORE = "."; 26 | 27 | private const string COMMENT = "//"; 28 | 29 | private readonly static object TranslationLock; 30 | 31 | private static Dictionary translationsLv; 32 | 33 | private static OrderedDictionary translations; 34 | 35 | private readonly static object NoticeLock; 36 | 37 | private static string lastraisedfile; 38 | 39 | private static DateTime lastraisedtime; 40 | 41 | private static FileSystemWatcher gfsw; 42 | 43 | private static FileSystemWatcher sfsw; 44 | 45 | private readonly static object WriterLock; 46 | 47 | private static Dictionary writerdata; 48 | 49 | private static System.Timers.Timer writertimer; 50 | 51 | internal static string FileDir 52 | { 53 | get 54 | { 55 | return SubtitleTranslator.SubtitleDir; 56 | } 57 | } 58 | 59 | internal static string FileName 60 | { 61 | get 62 | { 63 | return string.Format("{0}.txt", "Subtitle"); 64 | } 65 | } 66 | 67 | internal static string FilePath 68 | { 69 | get 70 | { 71 | return Path.Combine(SubtitleTranslator.FileDir, SubtitleTranslator.FileName); 72 | } 73 | } 74 | 75 | internal static string GlobalSubtitleDir 76 | { 77 | get 78 | { 79 | return string.Concat(IniSettings.MainDir, IniSettings.LanguageDir, "Audio\\"); 80 | } 81 | } 82 | 83 | internal static string GlobalSubtitleDirFiles 84 | { 85 | get 86 | { 87 | return string.Concat("*", ".txt"); 88 | } 89 | } 90 | 91 | internal static bool Initialized 92 | { 93 | get; 94 | private set; 95 | } 96 | 97 | internal static string LvFileDir 98 | { 99 | get 100 | { 101 | return SubtitleTranslator.SubtitleDir; 102 | } 103 | } 104 | 105 | internal static string LvFileName 106 | { 107 | get 108 | { 109 | string str = Application.loadedLevelName; 110 | if (string.IsNullOrEmpty(str)) 111 | { 112 | str = "Subtitle"; 113 | } 114 | return string.Format("{0}.{1}.txt", str, Application.loadedLevel); 115 | } 116 | } 117 | 118 | internal static string LvFilePath 119 | { 120 | get 121 | { 122 | return Path.Combine(SubtitleTranslator.LvFileDir, SubtitleTranslator.LvFileName); 123 | } 124 | } 125 | 126 | internal static string SubtitleDir 127 | { 128 | get 129 | { 130 | return string.Concat(IniSettings.MainDir, IniSettings.ProcessPathDir, IniSettings.LanguageDir, "Audio\\"); 131 | } 132 | } 133 | 134 | internal static string SubtitleDirFiles 135 | { 136 | get 137 | { 138 | return string.Concat("*", ".txt"); 139 | } 140 | } 141 | 142 | static SubtitleTranslator() 143 | { 144 | SubtitleTranslator.TranslationLock = new object(); 145 | SubtitleTranslator.translationsLv = new Dictionary(); 146 | SubtitleTranslator.translations = new OrderedDictionary(); 147 | SubtitleTranslator.NoticeLock = new object(); 148 | SubtitleTranslator.WriterLock = new object(); 149 | SubtitleTranslator.Initialize(); 150 | } 151 | 152 | private static void DumpSubtitle(string path, string audio) 153 | { 154 | StringBuilder stringBuilder; 155 | object writerLock = SubtitleTranslator.WriterLock; 156 | Monitor.Enter(writerLock); 157 | try 158 | { 159 | if (string.Concat(Path.GetDirectoryName(path), "\\") == SubtitleTranslator.SubtitleDir) 160 | { 161 | if (!SubtitleTranslator.writerdata.TryGetValue(path, out stringBuilder)) 162 | { 163 | stringBuilder = new StringBuilder(); 164 | SubtitleTranslator.writerdata.Add(path, stringBuilder); 165 | } 166 | stringBuilder.AppendLine(string.Format("#sub \"{0}\"", audio)); 167 | SubtitleTranslator.writertimer.Start(); 168 | } 169 | } 170 | finally 171 | { 172 | Monitor.Exit(writerLock); 173 | } 174 | } 175 | 176 | private static int GetFileLevel(string file) 177 | { 178 | int num; 179 | file = Path.GetFileName(file); 180 | if (!file.StartsWith(".")) 181 | { 182 | string str = null; 183 | if (file.EndsWith(".txt")) 184 | { 185 | str = file.Substring(0, file.Length - ".txt".Length); 186 | } 187 | if (!string.IsNullOrEmpty(str)) 188 | { 189 | string extension = Path.GetExtension(str); 190 | if (extension.StartsWith(".")) 191 | { 192 | extension = extension.Remove(0, 1); 193 | if (int.TryParse(extension, out num) && num > -1) 194 | { 195 | return num; 196 | } 197 | } 198 | } 199 | } 200 | return -1; 201 | } 202 | 203 | internal static void Initialize() 204 | { 205 | try 206 | { 207 | if (!SubtitleTranslator.Initialized) 208 | { 209 | double totalMilliseconds = TimeSpan.FromSeconds((double)IniSettings.LogWriterTime).TotalMilliseconds; 210 | SubtitleTranslator.writerdata = new Dictionary(); 211 | SubtitleTranslator.writertimer = new System.Timers.Timer(totalMilliseconds) 212 | { 213 | AutoReset = false 214 | }; 215 | SubtitleTranslator.writertimer.Elapsed += new ElapsedEventHandler(SubtitleTranslator.WriterTimerElapsed); 216 | SubtitleTranslator.Load(); 217 | SubtitleSettings.AnchorChanged += new Action((TextPosition value) => { 218 | SubtitleTranslator.Load(); 219 | AudioSourceSubtitle.Instance.Reload(); 220 | }); 221 | IniSettings.LanguageDirChanged += new Action((string value) => { 222 | SubtitleTranslator.Load(); 223 | AudioSourceSubtitle.Instance.Reload(); 224 | }); 225 | IniSettings.ProcessPathDirChanged += new Action((string value) => { 226 | SubtitleTranslator.Load(); 227 | AudioSourceSubtitle.Instance.Reload(); 228 | }); 229 | IniSettings.FindAudioChanged += new Action((bool value) => AudioSourceSubtitle.Instance.Reload()); 230 | SubtitleTranslator.Initialized = true; 231 | } 232 | } 233 | catch (Exception exception1) 234 | { 235 | Exception exception = exception1; 236 | SubtitleTranslator.Initialized = false; 237 | IniSettings.Error(string.Concat("SubtitleTranslator::Initialize:\n", exception.ToString())); 238 | } 239 | } 240 | 241 | private static void Load() 242 | { 243 | SubtitleTranslator.StopWatchSubtitleFiles(); 244 | SubtitleTranslator.translations.Clear(); 245 | SubtitleTranslator.translationsLv.Clear(); 246 | if (SubtitleTranslator.GlobalSubtitleDir != SubtitleTranslator.SubtitleDir) 247 | { 248 | SubtitleTranslator.LoadAllFromGlobalTranslationDir(); 249 | } 250 | SubtitleTranslator.LoadAllFromTranslationDir(); 251 | SubtitleTranslator.WatchSubtitleFiles(); 252 | if (IniSettings.DebugMode || IniSettings.FindAudio) 253 | { 254 | int count = 0; 255 | count = count + SubtitleTranslator.translations.Count; 256 | foreach (OrderedDictionary value in SubtitleTranslator.translationsLv.Values) 257 | { 258 | count = count + value.Count; 259 | } 260 | IniSettings.Log(string.Format("Subtitles Loaded: {0}", count)); 261 | } 262 | } 263 | 264 | private static void LoadAllFromGlobalTranslationDir() 265 | { 266 | if (!Directory.Exists(SubtitleTranslator.GlobalSubtitleDir)) 267 | { 268 | return; 269 | } 270 | SubtitleTranslator.LoadAllFromTranslationDir(Directory.GetFiles(SubtitleTranslator.GlobalSubtitleDir, SubtitleTranslator.GlobalSubtitleDirFiles)); 271 | } 272 | 273 | private static void LoadAllFromTranslationDir() 274 | { 275 | if (!Directory.Exists(SubtitleTranslator.SubtitleDir)) 276 | { 277 | return; 278 | } 279 | SubtitleTranslator.LoadAllFromTranslationDir(Directory.GetFiles(SubtitleTranslator.SubtitleDir, SubtitleTranslator.SubtitleDirFiles)); 280 | } 281 | 282 | private static void LoadAllFromTranslationDir(string[] files) 283 | { 284 | if (files == null || files.Length == 0) 285 | { 286 | return; 287 | } 288 | string[] strArrays = files; 289 | for (int i = 0; i < (int)strArrays.Length; i++) 290 | { 291 | SubtitleTranslator.LoadTranslations(strArrays[i], false); 292 | } 293 | } 294 | 295 | private static void LoadTranslations(string file, bool retranslate = false) 296 | { 297 | object translationLock = SubtitleTranslator.TranslationLock; 298 | Monitor.Enter(translationLock); 299 | try 300 | { 301 | try 302 | { 303 | if (Path.GetExtension(file).ToLower() == ".txt") 304 | { 305 | if (!Path.GetFileName(file).StartsWith(".")) 306 | { 307 | if (file.StartsWith(Environment.CurrentDirectory)) 308 | { 309 | file = file.Remove(0, Environment.CurrentDirectory.Length); 310 | if (!file.StartsWith("\\")) 311 | { 312 | file = string.Concat("\\", file); 313 | } 314 | file = string.Concat(".", file); 315 | } 316 | int fileLevel = SubtitleTranslator.GetFileLevel(file); 317 | bool flag = fileLevel > -1; 318 | OrderedDictionary orderedDictionaries = null; 319 | if (!flag) 320 | { 321 | SubtitleTranslator.RemoveAllTranslation(SubtitleTranslator.translations, file); 322 | } 323 | else 324 | { 325 | SubtitleTranslator.translationsLv.TryGetValue(fileLevel, out orderedDictionaries); 326 | if (orderedDictionaries != null) 327 | { 328 | SubtitleTranslator.RemoveAllTranslation(orderedDictionaries, file); 329 | } 330 | } 331 | using (StreamReader streamReader = new StreamReader(file, Encoding.UTF8)) 332 | { 333 | bool flag1 = false; 334 | bool flag2 = true; 335 | List subtitleLines = null; 336 | string empty = string.Empty; 337 | while (!streamReader.EndOfStream) 338 | { 339 | string str = streamReader.ReadLine(); 340 | if (str.StartsWith("//") || empty.Length == 0 && str.Length == 0) 341 | { 342 | continue; 343 | } 344 | Match match = Regex.Match(str.TrimEnd(new char[0]), "^#sub[ ]+\"(.+?)\"(?:[ ]+(?:{\\\\a([\\d]+)})?(.*))?$", RegexOptions.IgnoreCase); 345 | if (!match.Success) 346 | { 347 | if (empty.Length <= 0) 348 | { 349 | continue; 350 | } 351 | if (!flag1) 352 | { 353 | if (str.Length == 0) 354 | { 355 | continue; 356 | } 357 | Match match1 = Regex.Match(str, "^([\\d]*\\.?[\\d]+)[ ]+-->[ ]+([\\d]*\\.?[\\d]+)$", RegexOptions.None); 358 | if (!match1.Success) 359 | { 360 | flag1 = true; 361 | subtitleLines.Add(new SubtitleLine()); 362 | } 363 | else 364 | { 365 | if (streamReader.EndOfStream) 366 | { 367 | continue; 368 | } 369 | flag1 = true; 370 | SubtitleLine subtitleLine = new SubtitleLine() 371 | { 372 | StartTime = float.Parse(match1.Groups[1].Value, CultureInfo.InvariantCulture), 373 | EndTime = float.Parse(match1.Groups[2].Value, CultureInfo.InvariantCulture) 374 | }; 375 | subtitleLines.Add(subtitleLine); 376 | continue; 377 | } 378 | } 379 | if (flag2) 380 | { 381 | int count = subtitleLines.Count - 1; 382 | if (str.Length > 0) 383 | { 384 | Match match2 = Regex.Match(str, "^(?:{\\\\a([\\d]+)})?(.*)$", RegexOptions.None); 385 | if (match2.Success) 386 | { 387 | string str1 = match2.Groups[2].Value.Trim(); 388 | if (str1.Length != 0 || !streamReader.EndOfStream) 389 | { 390 | SubtitleLine item = subtitleLines[count]; 391 | item.Position = (match2.Groups[1].Success ? item.Position.Parse(match2.Groups[1].Value, SubtitleSettings.Anchor) : SubtitleSettings.Anchor); 392 | item.Text = str1; 393 | subtitleLines[count] = item; 394 | continue; 395 | } 396 | } 397 | } 398 | flag1 = false; 399 | flag2 = true; 400 | subtitleLines.RemoveAt(count); 401 | } 402 | else if (str.Length <= 0) 403 | { 404 | flag1 = false; 405 | flag2 = true; 406 | int num = subtitleLines.Count - 1; 407 | if (subtitleLines[num].Text.Length != 0) 408 | { 409 | continue; 410 | } 411 | subtitleLines.RemoveAt(num); 412 | } 413 | else 414 | { 415 | string str2 = str.Trim(); 416 | int count1 = subtitleLines.Count - 1; 417 | SubtitleLine item1 = subtitleLines[count1]; 418 | if (str2.Length <= 0) 419 | { 420 | if (!streamReader.EndOfStream || item1.Text.Length != 0) 421 | { 422 | continue; 423 | } 424 | subtitleLines.RemoveAt(count1); 425 | } 426 | else 427 | { 428 | if (item1.Text.Length > 0) 429 | { 430 | item1.Text = string.Concat(item1.Text, "\n"); 431 | } 432 | item1.Text = string.Concat(item1.Text, str2); 433 | subtitleLines[count1] = item1; 434 | } 435 | } 436 | } 437 | else 438 | { 439 | flag1 = false; 440 | flag2 = true; 441 | SubtitleDataBase subtitleDataBase = null; 442 | empty = match.Groups[1].Value; 443 | subtitleLines = new List(); 444 | if (match.Groups[3].Success) 445 | { 446 | string str3 = match.Groups[3].Value.Trim(); 447 | if (str3.Length > 0) 448 | { 449 | SubtitleLine subtitleLine1 = new SubtitleLine() 450 | { 451 | Text = str3 452 | }; 453 | subtitleLine1.Position = (match.Groups[2].Success 454 | ? subtitleLine1.Position.Parse(match.Groups[2].Value, SubtitleSettings.Anchor) 455 | : SubtitleSettings.Anchor); 456 | 457 | subtitleLines.Add(subtitleLine1); 458 | } 459 | } 460 | if (!flag) 461 | { 462 | subtitleDataBase = SubtitleTranslator.translations[empty] as SubtitleDataBase; 463 | } 464 | else if (orderedDictionaries != null) 465 | { 466 | subtitleDataBase = orderedDictionaries[empty] as SubtitleDataBase; 467 | } 468 | if (subtitleDataBase != null) 469 | { 470 | if (!flag) 471 | { 472 | SubtitleTranslator.translations.Remove(empty); 473 | } 474 | else 475 | { 476 | orderedDictionaries.Remove(empty); 477 | } 478 | } 479 | subtitleDataBase = new SubtitleDataBase(file, subtitleLines); 480 | if (!flag) 481 | { 482 | SubtitleTranslator.translations.Add(empty, subtitleDataBase); 483 | } 484 | else 485 | { 486 | if (orderedDictionaries == null) 487 | { 488 | orderedDictionaries = new OrderedDictionary(); 489 | SubtitleTranslator.translationsLv.Add(fileLevel, orderedDictionaries); 490 | } 491 | orderedDictionaries.Add(empty, subtitleDataBase); 492 | } 493 | } 494 | } 495 | } 496 | if (retranslate) 497 | { 498 | AudioSourceSubtitle.Instance.Reload(); 499 | } 500 | if (IniSettings.DebugMode || IniSettings.FindAudio) 501 | { 502 | IniSettings.Log(string.Concat("Loaded: ", file)); 503 | } 504 | } 505 | } 506 | } 507 | catch (Exception exception) 508 | { 509 | IniSettings.Error(string.Concat("LoadSubtitles:\n", exception.ToString())); 510 | } 511 | } 512 | finally 513 | { 514 | Monitor.Exit(translationLock); 515 | } 516 | } 517 | 518 | private static void RemoveAllTranslation(OrderedDictionary od, string fromfile) 519 | { 520 | for (int i = od.Count - 1; i >= 0; i--) 521 | { 522 | SubtitleDataBase item = od[i] as SubtitleDataBase; 523 | if (item != null && item.Path == fromfile) 524 | { 525 | od.RemoveAt(i); 526 | } 527 | } 528 | } 529 | 530 | private static void StopWatchSubtitleFiles() 531 | { 532 | if (SubtitleTranslator.gfsw != null) 533 | { 534 | SubtitleTranslator.gfsw.Dispose(); 535 | SubtitleTranslator.gfsw = null; 536 | } 537 | if (SubtitleTranslator.sfsw != null) 538 | { 539 | SubtitleTranslator.sfsw.Dispose(); 540 | SubtitleTranslator.sfsw = null; 541 | } 542 | } 543 | 544 | public static bool Translate(string audio, out SubtitleLine[] lines) 545 | { 546 | OrderedDictionary orderedDictionaries; 547 | OrderedDictionary orderedDictionaries1; 548 | bool count; 549 | object translationLock = SubtitleTranslator.TranslationLock; 550 | Monitor.Enter(translationLock); 551 | try 552 | { 553 | try 554 | { 555 | List value = null; 556 | if (SubtitleTranslator.translationsLv.TryGetValue(Application.loadedLevel, out orderedDictionaries)) 557 | { 558 | SubtitleDataBase item = orderedDictionaries[audio] as SubtitleDataBase; 559 | if (item == null) 560 | { 561 | goto Label2; 562 | } 563 | value = item.Value; 564 | goto Label1; 565 | } 566 | Label2: 567 | SubtitleDataBase subtitleDataBase = SubtitleTranslator.translations[audio] as SubtitleDataBase; 568 | if (subtitleDataBase != null) 569 | { 570 | value = subtitleDataBase.Value; 571 | } 572 | Label1: 573 | if (value == null) 574 | { 575 | value = new List(); 576 | if (IniSettings.FindAudio) 577 | { 578 | if (!IniSettings.DumpAudioByLevel) 579 | { 580 | string filePath = SubtitleTranslator.FilePath; 581 | SubtitleTranslator.translations.Add(audio, new SubtitleDataBase(filePath, value)); 582 | SubtitleTranslator.DumpSubtitle(filePath, audio); 583 | } 584 | else 585 | { 586 | if (!SubtitleTranslator.translationsLv.TryGetValue(Application.loadedLevel, out orderedDictionaries1)) 587 | { 588 | orderedDictionaries1 = new OrderedDictionary(); 589 | SubtitleTranslator.translationsLv.Add(Application.loadedLevel, orderedDictionaries1); 590 | } 591 | string lvFilePath = SubtitleTranslator.LvFilePath; 592 | orderedDictionaries1.Add(audio, new SubtitleDataBase(lvFilePath, value)); 593 | SubtitleTranslator.DumpSubtitle(lvFilePath, audio); 594 | } 595 | } 596 | } 597 | List subtitleLines = new List(); 598 | foreach (SubtitleLine subtitleLine in value) 599 | { 600 | if (string.IsNullOrEmpty(subtitleLine.Text)) 601 | { 602 | continue; 603 | } 604 | subtitleLines.Add(subtitleLine); 605 | } 606 | if (subtitleLines.Count == 0 && IniSettings.FindAudio) 607 | { 608 | SubtitleLine subtitleLine1 = new SubtitleLine() 609 | { 610 | Position = SubtitleSettings.Anchor, 611 | Text = audio 612 | }; 613 | subtitleLines.Add(subtitleLine1); 614 | } 615 | lines = subtitleLines.ToArray(); 616 | count = subtitleLines.Count > 0; 617 | return count; 618 | } 619 | catch (Exception exception) 620 | { 621 | IniSettings.Error(string.Concat("TextTranslator::Translate:\n", exception.ToString())); 622 | } 623 | lines = null; 624 | count = false; 625 | } 626 | finally 627 | { 628 | Monitor.Exit(translationLock); 629 | } 630 | return count; 631 | } 632 | 633 | private static void WatcherNotice(object sender, FileSystemEventArgs e) 634 | { 635 | object noticeLock = SubtitleTranslator.NoticeLock; 636 | Monitor.Enter(noticeLock); 637 | try 638 | { 639 | if (!(SubtitleTranslator.lastraisedfile == e.FullPath) || !(DateTime.Now < SubtitleTranslator.lastraisedtime)) 640 | { 641 | SubtitleTranslator.lastraisedfile = e.FullPath; 642 | SubtitleTranslator.lastraisedtime = DateTime.Now.AddSeconds(1); 643 | if (e.FullPath.EndsWith(".txt")) 644 | { 645 | SubtitleTranslator.LoadTranslations(e.FullPath, true); 646 | } 647 | SubtitleTranslator.WatchSubtitleFiles(); 648 | } 649 | } 650 | finally 651 | { 652 | Monitor.Exit(noticeLock); 653 | } 654 | } 655 | 656 | private static void WatchSubtitleFiles() 657 | { 658 | try 659 | { 660 | if (SubtitleTranslator.GlobalSubtitleDir != SubtitleTranslator.SubtitleDir && SubtitleTranslator.gfsw == null && Directory.Exists(SubtitleTranslator.GlobalSubtitleDir)) 661 | { 662 | SubtitleTranslator.gfsw = new FileSystemWatcher(SubtitleTranslator.GlobalSubtitleDir, SubtitleTranslator.GlobalSubtitleDirFiles) 663 | { 664 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime, 665 | IncludeSubdirectories = false 666 | }; 667 | SubtitleTranslator.gfsw.Changed += new FileSystemEventHandler(SubtitleTranslator.WatcherNotice); 668 | SubtitleTranslator.gfsw.Created += new FileSystemEventHandler(SubtitleTranslator.WatcherNotice); 669 | SubtitleTranslator.gfsw.Error += new ErrorEventHandler((object sender, ErrorEventArgs e) => IniSettings.Error(e.GetException().ToString())); 670 | SubtitleTranslator.gfsw.EnableRaisingEvents = true; 671 | } 672 | if (SubtitleTranslator.sfsw == null && Directory.Exists(SubtitleTranslator.SubtitleDir)) 673 | { 674 | SubtitleTranslator.sfsw = new FileSystemWatcher(SubtitleTranslator.SubtitleDir, SubtitleTranslator.SubtitleDirFiles) 675 | { 676 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime, 677 | IncludeSubdirectories = false 678 | }; 679 | SubtitleTranslator.sfsw.Changed += new FileSystemEventHandler(SubtitleTranslator.WatcherNotice); 680 | SubtitleTranslator.sfsw.Created += new FileSystemEventHandler(SubtitleTranslator.WatcherNotice); 681 | SubtitleTranslator.sfsw.Error += new ErrorEventHandler((object sender, ErrorEventArgs e) => IniSettings.Error(e.GetException().ToString())); 682 | SubtitleTranslator.sfsw.EnableRaisingEvents = true; 683 | } 684 | } 685 | catch (Exception exception) 686 | { 687 | IniSettings.Error(string.Concat("WatchSubtitleFiles:\n", exception.ToString())); 688 | } 689 | } 690 | 691 | private static void WriterTimerElapsed(object sender, ElapsedEventArgs e) 692 | { 693 | object writerLock = SubtitleTranslator.WriterLock; 694 | Monitor.Enter(writerLock); 695 | try 696 | { 697 | SubtitleTranslator.StopWatchSubtitleFiles(); 698 | try 699 | { 700 | foreach (KeyValuePair writerdatum in SubtitleTranslator.writerdata) 701 | { 702 | string key = writerdatum.Key; 703 | string directoryName = Path.GetDirectoryName(key); 704 | if (!Directory.Exists(directoryName)) 705 | { 706 | Directory.CreateDirectory(directoryName); 707 | } 708 | using (StreamWriter streamWriter = new StreamWriter(key, true, Encoding.UTF8)) 709 | { 710 | streamWriter.Write(writerdatum.Value.ToString()); 711 | } 712 | } 713 | } 714 | catch (Exception exception) 715 | { 716 | IniSettings.Error(string.Concat("SubtitleTranslator::DumpText:\n", exception.ToString())); 717 | } 718 | SubtitleTranslator.writerdata.Clear(); 719 | SubtitleTranslator.WatchSubtitleFiles(); 720 | } 721 | finally 722 | { 723 | Monitor.Exit(writerLock); 724 | } 725 | } 726 | } 727 | } -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/SubtitleUserInterfaceBase.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using Mathf = U::UnityEngine.Mathf; 3 | using GameObject = U::UnityEngine.GameObject; 4 | 5 | namespace UnityEngine.UI.Translation 6 | { 7 | using System.Collections.Generic; 8 | 9 | internal abstract class SubtitleUserInterfaceBase : U::UnityEngine.MonoBehaviour, ISubtitleUserInterface where T : U::UnityEngine.MonoBehaviour 10 | { 11 | private bool _Bold; 12 | private U::UnityEngine.Color _FontColor; 13 | private string _FontName; 14 | private int _FontSize; 15 | private static T _instance; 16 | private bool _Italic; 17 | private float _MarginBottom; 18 | private float _MarginLeft; 19 | private float _MarginRight; 20 | private float _MarginTop; 21 | private const string DEFAULT_FONT_NAME = "Arial"; 22 | private const int DEFAULT_FONT_SIZE = 16; 23 | public const int MAX_FONT_SIZE = 72; 24 | public const int MIN_FONT_SIZE = 8; 25 | public const float TARGET_DPI = 72f; 26 | 27 | public SubtitleUserInterfaceBase() 28 | { 29 | this._FontName = "Arial"; 30 | this._FontSize = 16; 31 | this._FontColor = U::UnityEngine.Color.white; 32 | } 33 | 34 | protected virtual void Awake() 35 | { 36 | if (this != SubtitleUserInterfaceBase.Instance) 37 | { 38 | U::UnityEngine.Object.DestroyImmediate(this); 39 | } 40 | } 41 | 42 | protected virtual void OnFontColorChanged(object sender, FontColorChangedEventArgs e) 43 | { 44 | } 45 | 46 | protected virtual void OnFontMarginChanged(object sender, FontMarginChangedEventArgs e) 47 | { 48 | } 49 | 50 | protected virtual void OnFontNameChanged(object sender, FontNameChangedEventArgs e) 51 | { 52 | } 53 | 54 | protected virtual void OnFontSizeChanged(object sender, FontSizeChangedEventArgs e) 55 | { 56 | } 57 | 58 | protected virtual void OnFontStyleChanged(object sender, FontStyleChangedEventArgs e) 59 | { 60 | } 61 | 62 | public abstract IEnumerable Anchors { get; } 63 | 64 | public bool Bold 65 | { 66 | get 67 | { 68 | return this._Bold; 69 | } 70 | set 71 | { 72 | if (value != this._Bold) 73 | { 74 | this._Bold = value; 75 | this.OnFontStyleChanged(this, new FontStyleChangedEventArgs(value, this.Italic)); 76 | } 77 | } 78 | } 79 | 80 | public U::UnityEngine.Color FontColor 81 | { 82 | get 83 | { 84 | return this._FontColor; 85 | } 86 | set 87 | { 88 | this._FontColor.a = 1f; 89 | if (value != this._FontColor) 90 | { 91 | this._FontColor = value; 92 | this.OnFontColorChanged(this, new FontColorChangedEventArgs(value)); 93 | } 94 | } 95 | } 96 | 97 | public string FontName 98 | { 99 | get 100 | { 101 | return this._FontName; 102 | } 103 | set 104 | { 105 | if (string.IsNullOrEmpty(value)) 106 | { 107 | value = "Arial"; 108 | } 109 | if (value != this._FontName) 110 | { 111 | this._FontName = value; 112 | this.OnFontNameChanged(this, new FontNameChangedEventArgs(value)); 113 | } 114 | } 115 | } 116 | 117 | public int FontSize 118 | { 119 | get 120 | { 121 | return this._FontSize; 122 | } 123 | set 124 | { 125 | value = Mathf.Min(Mathf.Max(value, 8), 0x48); 126 | if (value != this._FontSize) 127 | { 128 | this._FontSize = value; 129 | this.OnFontSizeChanged(this, new FontSizeChangedEventArgs(value)); 130 | } 131 | } 132 | } 133 | 134 | public static T Instance 135 | { 136 | get 137 | { 138 | if (SubtitleUserInterfaceBase._instance == null) 139 | { 140 | SubtitleUserInterfaceBase._instance = U::UnityEngine.Object.FindObjectOfType(); 141 | if (SubtitleUserInterfaceBase._instance == null) 142 | { 143 | GameObject target = new GameObject("SubtitleUserInterface"); 144 | SubtitleUserInterfaceBase._instance = target.AddComponent(); 145 | U::UnityEngine.Object.DontDestroyOnLoad(target); 146 | } 147 | } 148 | return SubtitleUserInterfaceBase._instance; 149 | } 150 | } 151 | 152 | public bool Italic 153 | { 154 | get 155 | { 156 | return this._Italic; 157 | } 158 | set 159 | { 160 | if (value != this._Italic) 161 | { 162 | this._Italic = value; 163 | this.OnFontStyleChanged(this, new FontStyleChangedEventArgs(this.Bold, value)); 164 | } 165 | } 166 | } 167 | 168 | public abstract string this[TextPosition anchor] { get; set; } 169 | 170 | public float MarginBottom 171 | { 172 | get 173 | { 174 | return this._MarginBottom; 175 | } 176 | set 177 | { 178 | if (value != this._MarginBottom) 179 | { 180 | this._MarginBottom = value; 181 | this.OnFontMarginChanged(this, new FontMarginChangedEventArgs(this.MarginLeft, this.MarginTop, this.MarginRight, value)); 182 | } 183 | } 184 | } 185 | 186 | public float MarginLeft 187 | { 188 | get 189 | { 190 | return this._MarginLeft; 191 | } 192 | set 193 | { 194 | if (value != this._MarginLeft) 195 | { 196 | this._MarginLeft = value; 197 | this.OnFontMarginChanged(this, new FontMarginChangedEventArgs(value, this.MarginTop, this.MarginRight, this.MarginBottom)); 198 | } 199 | } 200 | } 201 | 202 | public float MarginRight 203 | { 204 | get 205 | { 206 | return this._MarginRight; 207 | } 208 | set 209 | { 210 | if (value != this._MarginRight) 211 | { 212 | this._MarginRight = value; 213 | this.OnFontMarginChanged(this, new FontMarginChangedEventArgs(this.MarginLeft, this.MarginTop, value, this.MarginBottom)); 214 | } 215 | } 216 | } 217 | 218 | public float MarginTop 219 | { 220 | get 221 | { 222 | return this._MarginTop; 223 | } 224 | set 225 | { 226 | if (value != this._MarginTop) 227 | { 228 | this._MarginTop = value; 229 | this.OnFontMarginChanged(this, new FontMarginChangedEventArgs(this.MarginLeft, value, this.MarginRight, this.MarginBottom)); 230 | } 231 | } 232 | } 233 | } 234 | } 235 | 236 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/TextPosition.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal enum TextPosition 4 | { 5 | LowerCenter = 2, 6 | LowerLeft = 1, 7 | LowerRight = 3, 8 | MiddleCenter = 5, 9 | MiddleLeft = 4, 10 | MiddleRight = 6, 11 | UpperCenter = 8, 12 | UpperLeft = 7, 13 | UpperRight = 9 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/TextPositionExtension.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System; 4 | 5 | internal static class TextPositionExtension 6 | { 7 | public static TextPosition Parse(this TextPosition tp, string value, TextPosition defaultValue = TextPosition.LowerCenter) 8 | { 9 | TextPosition position = (TextPosition) 0; 10 | try 11 | { 12 | position = (TextPosition) Enum.Parse(typeof(TextPosition), value, true); 13 | } 14 | catch 15 | { 16 | } 17 | if (!Enum.IsDefined(typeof(TextPosition), position)) 18 | { 19 | position = defaultValue; 20 | } 21 | return position; 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Texture2DCacheData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal class Texture2DCacheData 4 | { 5 | private long count; 6 | private string objectname; 7 | private Texture2DOverrideData overrideData; 8 | 9 | public Texture2DCacheData(string objectname, Texture2DOverrideData overrideData) 10 | { 11 | this.objectname = objectname; 12 | this.count = 0L; 13 | this.overrideData = overrideData; 14 | } 15 | 16 | public void DecreaseAmount(long amount = 1L) 17 | { 18 | this.count -= amount; 19 | } 20 | 21 | public void IncreaseAmount(long amount = 1L) 22 | { 23 | this.count += amount; 24 | } 25 | 26 | public long Count 27 | { 28 | get 29 | { 30 | return this.count; 31 | } 32 | } 33 | 34 | public string ObjectName 35 | { 36 | get 37 | { 38 | return this.objectname; 39 | } 40 | } 41 | 42 | public Texture2DOverrideData OverrideData 43 | { 44 | get 45 | { 46 | return this.overrideData; 47 | } 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Texture2DData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.IO; 6 | using System.Runtime.InteropServices; 7 | 8 | [StructLayout(LayoutKind.Sequential)] 9 | internal struct Texture2DData 10 | { 11 | internal const bool DEFAULTDDSFLIPMODE = true; 12 | private static ReadOnlyCollection validexts; 13 | private bool exists; 14 | private string path; 15 | private bool flip; 16 | internal static ReadOnlyCollection ValidExtensions 17 | { 18 | get 19 | { 20 | return validexts; 21 | } 22 | } 23 | internal bool Exists 24 | { 25 | get 26 | { 27 | return this.exists; 28 | } 29 | } 30 | internal string Path 31 | { 32 | get 33 | { 34 | return this.path; 35 | } 36 | } 37 | internal bool Flip 38 | { 39 | get 40 | { 41 | return this.flip; 42 | } 43 | } 44 | static Texture2DData() 45 | { 46 | string[] collection = new string[] { ".dds", ".jpeg", ".jpg", ".png", ".psd", ".tga" }; 47 | List list = new List(collection); 48 | list.Sort(); 49 | validexts = new ReadOnlyCollection(list); 50 | } 51 | 52 | internal Texture2DData(string path, bool flip = false) 53 | { 54 | this.exists = false; 55 | this.path = path; 56 | this.flip = flip; 57 | this.exists = this.GetImagePath(ref this.path); 58 | System.IO.Path.GetExtension(this.path).ToLower(); 59 | } 60 | 61 | private bool GetImagePath(ref string file) 62 | { 63 | if (!string.IsNullOrEmpty(file)) 64 | { 65 | string path = Texture2DOverride.TranslationImageDir + file; 66 | if (File.Exists(path)) 67 | { 68 | return true; 69 | } 70 | foreach (string str2 in validexts) 71 | { 72 | if (File.Exists(path + str2)) 73 | { 74 | file = file + str2; 75 | return true; 76 | } 77 | } 78 | } 79 | return false; 80 | } 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Texture2DDumpData.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using TextureFormat = U::UnityEngine.TextureFormat; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace UnityEngine.UI.Translation 6 | { 7 | 8 | 9 | [StructLayout(LayoutKind.Sequential)] 10 | internal struct Texture2DDumpData 11 | { 12 | private string section; 13 | private string path; 14 | private TextureFormat format; 15 | public string Section 16 | { 17 | get 18 | { 19 | return this.section; 20 | } 21 | } 22 | public string Path 23 | { 24 | get 25 | { 26 | return this.path; 27 | } 28 | } 29 | public TextureFormat Format 30 | { 31 | get 32 | { 33 | return this.format; 34 | } 35 | } 36 | public Texture2DDumpData(string section, string path, TextureFormat format) 37 | { 38 | this.section = section; 39 | this.path = path; 40 | this.format = format; 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Texture2DOverride.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Timers; 8 | using Texture2D = U::UnityEngine.Texture2D; 9 | using TextureFormat = U::UnityEngine.TextureFormat; 10 | 11 | namespace UnityEngine.UI.Translation 12 | { 13 | internal static class Texture2DOverride 14 | { 15 | private static Dictionary uniqueimagesdata; 16 | 17 | private const int Interval = 15; 18 | 19 | private static System.Timers.Timer timer; 20 | 21 | private readonly static object DataLock; 22 | 23 | private static Dictionary unused; 24 | 25 | private static Dictionary loaded; 26 | 27 | private static string lastraisedfile; 28 | 29 | private static DateTime lastraisedtime; 30 | 31 | private static FileSystemWatcher gniw; 32 | 33 | private static FileSystemWatcher iniw; 34 | 35 | private static IniFile mainini; 36 | 37 | private static Dictionary inidata; 38 | 39 | private readonly static object WriterLock; 40 | 41 | private static List writerdata; 42 | 43 | private static System.Timers.Timer writertimer; 44 | 45 | private static string MAINFOLDERKEY; 46 | 47 | private const string TEXTUREPATHKEY = "sPath"; 48 | 49 | private const string FLIPTEXTUREKEY = "bFlipTexture"; 50 | 51 | private const string INI = "{0}.ini"; 52 | 53 | private static string mainfoldersection; 54 | 55 | private static string mainfolder; 56 | 57 | private static string mainfolderdir; 58 | 59 | internal static string GlobalImageDir 60 | { 61 | get 62 | { 63 | return string.Concat(IniSettings.MainDir, IniSettings.LanguageDir, "Image\\"); 64 | } 65 | } 66 | 67 | internal static string GlobalTranslationImageDir 68 | { 69 | get 70 | { 71 | return Texture2DOverride.GlobalImageDir; 72 | } 73 | } 74 | 75 | internal static string GlobalTranslationImageIniFileDir 76 | { 77 | get 78 | { 79 | return Texture2DOverride.GlobalImageDir; 80 | } 81 | } 82 | 83 | internal static string GlobalTranslationImageIniFileName 84 | { 85 | get 86 | { 87 | return string.Format("{0}.ini", IniSettings.ProcessName); 88 | } 89 | } 90 | 91 | internal static string GlobalTranslationImageIniFilePath 92 | { 93 | get 94 | { 95 | return string.Concat(Texture2DOverride.GlobalTranslationImageIniFileDir, Texture2DOverride.GlobalTranslationImageIniFileName); 96 | } 97 | } 98 | 99 | internal static string ImageDir 100 | { 101 | get 102 | { 103 | return string.Concat(IniSettings.MainDir, IniSettings.ProcessPathDir, IniSettings.LanguageDir, "Image\\"); 104 | } 105 | } 106 | 107 | internal static string MainFolder 108 | { 109 | get 110 | { 111 | if (Texture2DOverride.mainfolder == null) 112 | { 113 | if (!string.IsNullOrEmpty(IniSettings.ProcessPathDir)) 114 | { 115 | Texture2DOverride.mainfolder = string.Empty; 116 | } 117 | else 118 | { 119 | Texture2DOverride.mainfolder = IniSettings.ProcessName; 120 | } 121 | } 122 | return Texture2DOverride.mainfolder; 123 | } 124 | private set 125 | { 126 | char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); 127 | if (value == null) 128 | { 129 | if (!string.IsNullOrEmpty(IniSettings.ProcessPathDir)) 130 | { 131 | Texture2DOverride.mainfolder = string.Empty; 132 | } 133 | else 134 | { 135 | Texture2DOverride.mainfolder = IniSettings.ProcessName; 136 | } 137 | } 138 | else if (value != string.Empty) 139 | { 140 | value = value.Trim(); 141 | if (value != string.Empty && value.IndexOfAny(invalidFileNameChars) != -1) 142 | { 143 | if (!string.IsNullOrEmpty(IniSettings.ProcessPathDir)) 144 | { 145 | value = string.Empty; 146 | } 147 | else 148 | { 149 | value = IniSettings.ProcessName; 150 | } 151 | } 152 | } 153 | if (value != Texture2DOverride.mainfolder) 154 | { 155 | Texture2DOverride.mainfolder = value; 156 | Texture2DOverride.mainfolderdir = value; 157 | if (!string.IsNullOrEmpty(value)) 158 | { 159 | Texture2DOverride.mainfolderdir = string.Concat(Texture2DOverride.mainfolderdir, "\\"); 160 | } 161 | } 162 | } 163 | } 164 | 165 | internal static string MainFolderDir 166 | { 167 | get 168 | { 169 | if (Texture2DOverride.mainfolderdir == null) 170 | { 171 | if (!string.IsNullOrEmpty(Texture2DOverride.MainFolder)) 172 | { 173 | Texture2DOverride.mainfolderdir = string.Concat(Texture2DOverride.MainFolder, "\\"); 174 | } 175 | else 176 | { 177 | Texture2DOverride.mainfolderdir = string.Empty; 178 | } 179 | } 180 | return Texture2DOverride.mainfolderdir; 181 | } 182 | } 183 | 184 | internal static string MainFolderSection 185 | { 186 | get 187 | { 188 | if (Texture2DOverride.mainfoldersection == null) 189 | { 190 | Texture2DOverride.mainfoldersection = Texture2DOverride.Encode(IniSettings.ProcessFile); 191 | } 192 | return Texture2DOverride.mainfoldersection; 193 | } 194 | } 195 | 196 | internal static string TranslationImageDir 197 | { 198 | get 199 | { 200 | if (!(IniSettings.ProcessPathDir == string.Empty) || string.IsNullOrEmpty(Texture2DOverride.MainFolderDir)) 201 | { 202 | return Texture2DOverride.ImageDir; 203 | } 204 | return string.Concat(Texture2DOverride.ImageDir, Texture2DOverride.MainFolderDir); 205 | } 206 | } 207 | 208 | internal static string TranslationImageIniFileDir 209 | { 210 | get 211 | { 212 | return Texture2DOverride.ImageDir; 213 | } 214 | } 215 | 216 | internal static string TranslationImageIniFileName 217 | { 218 | get 219 | { 220 | return string.Format("{0}.ini", IniSettings.ProcessName); 221 | } 222 | } 223 | 224 | internal static string TranslationImageIniFilePath 225 | { 226 | get 227 | { 228 | return string.Concat(Texture2DOverride.TranslationImageIniFileDir, Texture2DOverride.TranslationImageIniFileName); 229 | } 230 | } 231 | 232 | static Texture2DOverride() 233 | { 234 | Texture2DOverride.DataLock = new object(); 235 | Texture2DOverride.unused = new Dictionary(); 236 | Texture2DOverride.loaded = new Dictionary(); 237 | Texture2DOverride.WriterLock = new object(); 238 | Texture2DOverride.MAINFOLDERKEY = "sMainFolder"; 239 | Texture2DOverride.Load(); 240 | TimeSpan timeSpan = TimeSpan.FromSeconds(15); 241 | Texture2DOverride.timer = new System.Timers.Timer(timeSpan.TotalMilliseconds) 242 | { 243 | AutoReset = true 244 | }; 245 | Texture2DOverride.timer.Elapsed += new ElapsedEventHandler(Texture2DOverride.timer_Elapsed); 246 | Texture2DOverride.timer.Start(); 247 | Texture2DOverride.writerdata = new List(); 248 | timeSpan = TimeSpan.FromSeconds(15); 249 | Texture2DOverride.writertimer = new System.Timers.Timer(timeSpan.TotalMilliseconds) 250 | { 251 | AutoReset = false 252 | }; 253 | Texture2DOverride.writertimer.Elapsed += new ElapsedEventHandler(Texture2DOverride.WriterTimerElapsed); 254 | IniSettings.LanguageDirChanged += new Action((string value) => Texture2DOverride.Load()); 255 | IniSettings.ProcessPathDirChanged += new Action((string value) => Texture2DOverride.Load()); 256 | } 257 | 258 | private static string Encode(string text) 259 | { 260 | StringBuilder stringBuilder = new StringBuilder(text); 261 | stringBuilder.Replace("[", "0x5B"); 262 | stringBuilder.Replace("]", "0x5D"); 263 | return stringBuilder.ToString(); 264 | } 265 | 266 | private static U::UnityEngine.Texture2D FlipTextureY(U::UnityEngine.Texture2D original) 267 | { 268 | U::UnityEngine.Texture2D texture2D; 269 | try 270 | { 271 | texture2D = new U::UnityEngine.Texture2D(original.width, original.height, original.format, false); 272 | int num = original.width; 273 | int num1 = original.height; 274 | for (int i = 0; i < num1; i++) 275 | { 276 | for (int j = 0; j < num; j++) 277 | { 278 | texture2D.SetPixel(j, num1 - i - 1, original.GetPixel(j, i)); 279 | } 280 | } 281 | texture2D.Apply(); 282 | } 283 | catch (Exception exception1) 284 | { 285 | Exception exception = exception1; 286 | texture2D = original; 287 | IniSettings.Error(string.Concat("FlipTextureY:\n", exception.ToString())); 288 | } 289 | return texture2D; 290 | } 291 | 292 | private static Dictionary GetUniqueImageFiles(string dir) 293 | { 294 | Dictionary strs = new Dictionary(); 295 | try 296 | { 297 | if (Texture2DData.ValidExtensions.Count > 0 && dir != null && Directory.Exists(dir)) 298 | { 299 | HashSet strs1 = new HashSet(); 300 | foreach (Texture2DData value in Texture2DOverride.inidata.Values) 301 | { 302 | if (strs1.Contains(value.Path) || !value.Exists) 303 | { 304 | continue; 305 | } 306 | strs1.Add(value.Path); 307 | } 308 | string[] files = Directory.GetFiles(dir, "*", SearchOption.AllDirectories); 309 | HashSet strs2 = new HashSet(Texture2DData.ValidExtensions); 310 | string[] strArrays = files; 311 | for (int i = 0; i < (int)strArrays.Length; i++) 312 | { 313 | string str = strArrays[i]; 314 | if (strs2.Contains(Path.GetExtension(str).ToLower())) 315 | { 316 | string str1 = str; 317 | if (str1.StartsWith(dir)) 318 | { 319 | str1 = str1.Remove(0, dir.Length); 320 | } 321 | string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(str); 322 | if (!strs.ContainsKey(fileNameWithoutExtension) && !strs1.Contains(str1)) 323 | { 324 | strs.Add(fileNameWithoutExtension, str1); 325 | } 326 | } 327 | } 328 | } 329 | } 330 | catch (Exception exception) 331 | { 332 | IniSettings.Error(string.Concat("GetUniqueImageFiles:\n", exception.ToString())); 333 | } 334 | return strs; 335 | } 336 | 337 | private static void Load() 338 | { 339 | Texture2DCacheData texture2DCacheDatum; 340 | object dataLock = Texture2DOverride.DataLock; 341 | Monitor.Enter(dataLock); 342 | try 343 | { 344 | Texture2DOverride.StopWatchTextFiles(); 345 | Dictionary nums = new Dictionary(Texture2DOverride.loaded); 346 | Texture2DOverride.unused.Clear(); 347 | Texture2DOverride.loaded.Clear(); 348 | Texture2DOverride.LoadMainIniFile(); 349 | Texture2DOverride.inidata = Texture2DOverride.ParseIniData(Texture2DOverride.mainini); 350 | Texture2DOverride.uniqueimagesdata = Texture2DOverride.GetUniqueImageFiles(Texture2DOverride.TranslationImageDir); 351 | if (Texture2DOverride.GlobalTranslationImageIniFilePath != Texture2DOverride.TranslationImageDir) 352 | { 353 | Dictionary strs = Texture2DOverride.ParseIniData(new IniFile(Texture2DOverride.GlobalTranslationImageIniFilePath)); 354 | foreach (KeyValuePair keyValuePair in strs) 355 | { 356 | if (Texture2DOverride.inidata.ContainsKey(keyValuePair.Key)) 357 | { 358 | continue; 359 | } 360 | Texture2DOverride.inidata.Add(keyValuePair.Key, keyValuePair.Value); 361 | } 362 | strs.Clear(); 363 | strs = null; 364 | Dictionary uniqueImageFiles = Texture2DOverride.GetUniqueImageFiles(Texture2DOverride.GlobalTranslationImageDir); 365 | foreach (KeyValuePair uniqueImageFile in uniqueImageFiles) 366 | { 367 | if (Texture2DOverride.uniqueimagesdata.ContainsKey(uniqueImageFile.Key)) 368 | { 369 | continue; 370 | } 371 | Texture2DOverride.uniqueimagesdata.Add(uniqueImageFile.Key, uniqueImageFile.Value); 372 | } 373 | uniqueImageFiles.Clear(); 374 | uniqueImageFiles = null; 375 | } 376 | Texture2DOverride.WatchTextFiles(); 377 | foreach (KeyValuePair num in nums) 378 | { 379 | Texture2DOverrideData overrideData = num.Value.OverrideData; 380 | Texture2DOverride.LoadTexture2D(num.Value.ObjectName, overrideData.OriginalTexture2D, out overrideData); 381 | if (!Texture2DOverride.loaded.TryGetValue(overrideData.InstanceID, out texture2DCacheDatum)) 382 | { 383 | continue; 384 | } 385 | texture2DCacheDatum.IncreaseAmount(num.Value.Count); 386 | } 387 | if (IniSettings.DebugMode || IniSettings.FindImage) 388 | { 389 | int count = Texture2DOverride.inidata.Count; 390 | IniSettings.Log(string.Concat("ImageSettingsLoaded: ", count.ToString())); 391 | } 392 | } 393 | finally 394 | { 395 | Monitor.Exit(dataLock); 396 | } 397 | } 398 | 399 | private static void LoadMainIniFile() 400 | { 401 | try 402 | { 403 | Texture2DOverride.mainini = new IniFile(Texture2DOverride.TranslationImageIniFilePath); 404 | if (File.Exists(Texture2DOverride.TranslationImageIniFilePath)) 405 | { 406 | string mainFolderSection = Texture2DOverride.MainFolderSection; 407 | string mAINFOLDERKEY = Texture2DOverride.MAINFOLDERKEY; 408 | string value = Texture2DOverride.mainini.GetValue(mainFolderSection, mAINFOLDERKEY, null); 409 | Texture2DOverride.MainFolder = value; 410 | if (value != Texture2DOverride.MainFolder) 411 | { 412 | Texture2DOverride.mainini.WriteValue(mainFolderSection, mAINFOLDERKEY, Texture2DOverride.MainFolder); 413 | } 414 | } 415 | } 416 | catch (Exception exception) 417 | { 418 | IniSettings.Error(string.Concat("Texture2D::LoadIniFile:", exception.ToString())); 419 | } 420 | } 421 | 422 | internal static void LoadTexture2D(string objectName, U::UnityEngine.Texture2D texture2D, out Texture2DOverrideData overrideData) 423 | { 424 | string str; 425 | Texture2DData texture2DDatum; 426 | string texturePath; 427 | overrideData = new Texture2DOverrideData(); 428 | try 429 | { 430 | if (!string.IsNullOrEmpty(texture2D.name)) 431 | { 432 | if (string.IsNullOrEmpty(objectName)) 433 | { 434 | objectName = string.Empty; 435 | } 436 | str = (string.IsNullOrEmpty(objectName) || objectName == texture2D.name ? texture2D.name : string.Format("{0}:{1}", objectName, texture2D.name)); 437 | str = Texture2DOverride.Encode(str); 438 | if (!Texture2DOverride.inidata.TryGetValue(str, out texture2DDatum)) 439 | { 440 | if (Texture2DOverride.TryLoadCacheTexture(texture2D, ref overrideData)) 441 | { 442 | texturePath = overrideData.TexturePath; 443 | } 444 | else if (!Texture2DOverride.uniqueimagesdata.TryGetValue(texture2D.name, out texturePath)) 445 | { 446 | texturePath = texture2D.name; 447 | } 448 | else 449 | { 450 | bool flag = false; 451 | string lower = Path.GetExtension(texturePath).ToLower(); 452 | if (lower == ".dds" || lower == ".psd") 453 | { 454 | flag = true; 455 | } 456 | Texture2DOverride.TryLoadNewTexture(str, texture2D, texturePath, ref overrideData, flag); 457 | } 458 | Texture2DOverride.inidata.Add(str, new Texture2DData(texturePath, false)); 459 | if (IniSettings.FindImage) 460 | { 461 | object writerLock = Texture2DOverride.WriterLock; 462 | Monitor.Enter(writerLock); 463 | try 464 | { 465 | Texture2DOverride.writerdata.Add(new Texture2DDumpData(str, texturePath, texture2D.format)); 466 | Texture2DOverride.writertimer.Start(); 467 | } 468 | finally 469 | { 470 | Monitor.Exit(writerLock); 471 | } 472 | } 473 | } 474 | else if (texture2DDatum.Exists && !Texture2DOverride.TryLoadCacheTexture(texture2D, ref overrideData)) 475 | { 476 | bool flag1 = false; 477 | string lower1 = Path.GetExtension(texture2DDatum.Path).ToLower(); 478 | if (lower1 == ".dds" || lower1 == ".psd") 479 | { 480 | flag1 = true; 481 | } 482 | Texture2DOverride.TryLoadNewTexture(str, texture2D, texture2DDatum.Path, ref overrideData, flag1); 483 | } 484 | } 485 | } 486 | catch (Exception exception) 487 | { 488 | IniSettings.Error(string.Concat("LoadTexture2D:\n", exception.ToString())); 489 | } 490 | } 491 | 492 | private static bool LoadTextureData(string path, out U::UnityEngine.Texture2D texture2D) 493 | { 494 | bool flag; 495 | texture2D = null; 496 | try 497 | { 498 | path = string.Concat(Texture2DOverride.TranslationImageDir, path); 499 | string extension = Path.GetExtension(path); 500 | if (extension == ".dds") 501 | { 502 | flag = DXTLoader.LoadDXT(path, out texture2D); 503 | } 504 | else if (extension == ".jpeg" || extension == ".jpg") 505 | { 506 | texture2D = new Texture2D(2, 2, TextureFormat.RGB24, false); 507 | flag = texture2D.LoadImage(File.ReadAllBytes(path)); 508 | } 509 | else if (extension == ".png") 510 | { 511 | texture2D = new Texture2D(2, 2, TextureFormat.ARGB32, false); 512 | flag = texture2D.LoadImage(File.ReadAllBytes(path)); 513 | } 514 | else if (extension == ".psd") 515 | { 516 | flag = PSDLoader.LoadPSD(path, out texture2D); 517 | } 518 | else if (extension == ".tga") 519 | { 520 | flag = TGALoader.LoadTGA(path, out texture2D); 521 | } 522 | else 523 | { 524 | return false; 525 | } 526 | } 527 | catch (Exception exception) 528 | { 529 | IniSettings.Error(string.Concat("LoadImage:\n", exception.ToString())); 530 | return false; 531 | } 532 | return flag; 533 | } 534 | 535 | private static Dictionary ParseIniData(IniFile ini) 536 | { 537 | Dictionary strs = new Dictionary(); 538 | try 539 | { 540 | string[] sections = ini.GetSections(); 541 | for (int i = 0; i < (int)sections.Length; i++) 542 | { 543 | string str = sections[i]; 544 | bool flag = false; 545 | string value = ini.GetValue(str, "sPath", ""); 546 | string value1 = ini.GetValue(str, "bFlipTexture", null); 547 | if (!string.IsNullOrEmpty(value1) && !bool.TryParse(value1, out flag)) 548 | { 549 | flag = true; 550 | } 551 | Texture2DData texture2DDatum = new Texture2DData(value, flag); 552 | strs.Remove(str); 553 | strs.Add(str, texture2DDatum); 554 | } 555 | } 556 | catch (Exception exception) 557 | { 558 | IniSettings.Error(string.Concat("LoadIniData:\n", exception.ToString())); 559 | } 560 | return strs; 561 | } 562 | 563 | private static void StopWatchTextFiles() 564 | { 565 | if (Texture2DOverride.gniw != null) 566 | { 567 | Texture2DOverride.gniw.Dispose(); 568 | Texture2DOverride.gniw = null; 569 | } 570 | if (Texture2DOverride.iniw != null) 571 | { 572 | Texture2DOverride.iniw.Dispose(); 573 | Texture2DOverride.iniw = null; 574 | } 575 | } 576 | 577 | private static void timer_Elapsed(object sender, ElapsedEventArgs e) 578 | { 579 | object dataLock = Texture2DOverride.DataLock; 580 | Monitor.Enter(dataLock); 581 | try 582 | { 583 | try 584 | { 585 | List nums = new List(); 586 | foreach (KeyValuePair keyValuePair in Texture2DOverride.unused) 587 | { 588 | if (DateTime.Now <= keyValuePair.Value.AddSeconds(15)) 589 | { 590 | continue; 591 | } 592 | nums.Add(keyValuePair.Key); 593 | if (Texture2DOverride.loaded[keyValuePair.Key].OverrideData.OriginalTexture2D == null) 594 | { 595 | continue; 596 | } 597 | int key = keyValuePair.Key; 598 | Texture2DOverride.loaded.Remove(key); 599 | } 600 | if (nums.Count > 0) 601 | { 602 | Dictionary nums1 = Texture2DOverride.unused; 603 | foreach (int num in nums) 604 | { 605 | nums1.Remove(num); 606 | } 607 | Texture2DOverride.unused = nums1; 608 | } 609 | } 610 | catch (Exception exception) 611 | { 612 | IniSettings.Error(string.Concat("timer_Elapsed:\n", exception.ToString())); 613 | } 614 | } 615 | finally 616 | { 617 | Monitor.Exit(dataLock); 618 | } 619 | } 620 | 621 | private static bool TryLoadCacheTexture(U::UnityEngine.Texture2D texture2D, ref Texture2DOverrideData overrideData) 622 | { 623 | Texture2DCacheData texture2DCacheDatum; 624 | bool flag; 625 | object dataLock = Texture2DOverride.DataLock; 626 | Monitor.Enter(dataLock); 627 | try 628 | { 629 | int instanceID = texture2D.GetInstanceID(); 630 | if (!Texture2DOverride.loaded.TryGetValue(instanceID, out texture2DCacheDatum)) 631 | { 632 | flag = false; 633 | } 634 | else 635 | { 636 | if (!Texture2DOverride.unused.Remove(instanceID)) 637 | { 638 | texture2DCacheDatum.IncreaseAmount((long)1); 639 | } 640 | overrideData = texture2DCacheDatum.OverrideData; 641 | flag = true; 642 | } 643 | } 644 | finally 645 | { 646 | Monitor.Exit(dataLock); 647 | } 648 | return flag; 649 | } 650 | 651 | private static bool TryLoadNewTexture(string section, U::UnityEngine.Texture2D texture2D, string path, ref Texture2DOverrideData overrideData, bool flip = false) 652 | { 653 | U::UnityEngine.Texture2D texture2D1; 654 | bool flag; 655 | object dataLock = Texture2DOverride.DataLock; 656 | Monitor.Enter(dataLock); 657 | try 658 | { 659 | if (!Texture2DOverride.LoadTextureData(path, out texture2D1)) 660 | { 661 | flag = false; 662 | } 663 | else 664 | { 665 | if (flip) 666 | { 667 | texture2D1 = Texture2DOverride.FlipTextureY(texture2D1); 668 | } 669 | texture2D1.name = texture2D.name; 670 | texture2D1.anisoLevel = texture2D.anisoLevel; 671 | texture2D1.filterMode = texture2D.filterMode; 672 | texture2D1.mipMapBias = texture2D.mipMapBias; 673 | texture2D1.wrapMode = texture2D.wrapMode; 674 | overrideData = new Texture2DOverrideData(texture2D, path, texture2D1); 675 | Texture2DOverride.loaded.Add(texture2D.GetInstanceID(), new Texture2DCacheData(section, overrideData)); 676 | flag = true; 677 | } 678 | } 679 | finally 680 | { 681 | Monitor.Exit(dataLock); 682 | } 683 | return flag; 684 | } 685 | 686 | internal static void UnloadTexture2D(ref Texture2DOverrideData overrideData) 687 | { 688 | Texture2DCacheData texture2DCacheDatum; 689 | object dataLock = Texture2DOverride.DataLock; 690 | Monitor.Enter(dataLock); 691 | try 692 | { 693 | try 694 | { 695 | try 696 | { 697 | if (overrideData.OriginalTexture2D != null) 698 | { 699 | int instanceID = overrideData.InstanceID; 700 | if (Texture2DOverride.loaded.TryGetValue(instanceID, out texture2DCacheDatum)) 701 | { 702 | if (texture2DCacheDatum.Count <= (long)0) 703 | { 704 | Texture2DOverride.unused.Add(instanceID, DateTime.Now); 705 | } 706 | else 707 | { 708 | texture2DCacheDatum.DecreaseAmount((long)1); 709 | } 710 | } 711 | } 712 | } 713 | catch (Exception exception1) 714 | { 715 | Exception exception = exception1; 716 | IniSettings.Error(string.Concat(new object[] { "UnloadTexture2D[", overrideData.InstanceID, "]:\n", exception.ToString() })); 717 | } 718 | } 719 | finally 720 | { 721 | overrideData = new Texture2DOverrideData(); 722 | } 723 | } 724 | finally 725 | { 726 | Monitor.Exit(dataLock); 727 | } 728 | } 729 | 730 | private static void WatcherNotice(object sender, FileSystemEventArgs e) 731 | { 732 | if (Texture2DOverride.lastraisedfile == e.FullPath && DateTime.Now < Texture2DOverride.lastraisedtime) 733 | { 734 | return; 735 | } 736 | Texture2DOverride.lastraisedfile = e.FullPath; 737 | Texture2DOverride.lastraisedtime = DateTime.Now.AddSeconds(1); 738 | Texture2DOverride.Load(); 739 | } 740 | 741 | private static void WatchTextFiles() 742 | { 743 | if (Texture2DOverride.GlobalTranslationImageIniFilePath != Texture2DOverride.TranslationImageDir && Texture2DOverride.gniw == null && Directory.Exists(Texture2DOverride.GlobalTranslationImageIniFileDir)) 744 | { 745 | Texture2DOverride.gniw = new FileSystemWatcher(Texture2DOverride.GlobalTranslationImageIniFileDir, Texture2DOverride.GlobalTranslationImageIniFileName) 746 | { 747 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime, 748 | IncludeSubdirectories = false 749 | }; 750 | Texture2DOverride.gniw.Changed += new FileSystemEventHandler(Texture2DOverride.WatcherNotice); 751 | Texture2DOverride.gniw.Created += new FileSystemEventHandler(Texture2DOverride.WatcherNotice); 752 | Texture2DOverride.gniw.Error += new ErrorEventHandler((object sender, ErrorEventArgs e) => IniSettings.Error(e.GetException().ToString())); 753 | Texture2DOverride.gniw.EnableRaisingEvents = true; 754 | } 755 | if (Texture2DOverride.iniw == null && Directory.Exists(Texture2DOverride.TranslationImageIniFileDir)) 756 | { 757 | Texture2DOverride.iniw = new FileSystemWatcher(Texture2DOverride.TranslationImageIniFileDir, Texture2DOverride.TranslationImageIniFileName) 758 | { 759 | NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime, 760 | IncludeSubdirectories = false 761 | }; 762 | Texture2DOverride.iniw.Changed += new FileSystemEventHandler(Texture2DOverride.WatcherNotice); 763 | Texture2DOverride.iniw.Created += new FileSystemEventHandler(Texture2DOverride.WatcherNotice); 764 | Texture2DOverride.iniw.Error += new ErrorEventHandler((object sender, ErrorEventArgs e) => IniSettings.Error(e.GetException().ToString())); 765 | Texture2DOverride.iniw.EnableRaisingEvents = true; 766 | } 767 | } 768 | 769 | private static void WriterTimerElapsed(object sender, ElapsedEventArgs e) 770 | { 771 | object writerLock = Texture2DOverride.WriterLock; 772 | Monitor.Enter(writerLock); 773 | try 774 | { 775 | Texture2DOverride.StopWatchTextFiles(); 776 | try 777 | { 778 | if (!Directory.Exists(Texture2DOverride.TranslationImageIniFileDir)) 779 | { 780 | Directory.CreateDirectory(Texture2DOverride.TranslationImageIniFileDir); 781 | } 782 | if (!File.Exists(Texture2DOverride.TranslationImageIniFilePath)) 783 | { 784 | Texture2DOverride.LoadMainIniFile(); 785 | } 786 | if (!Directory.Exists(Texture2DOverride.TranslationImageDir)) 787 | { 788 | Directory.CreateDirectory(Texture2DOverride.TranslationImageDir); 789 | } 790 | foreach (Texture2DDumpData writerdatum in Texture2DOverride.writerdata) 791 | { 792 | Texture2DOverride.mainini.WriteValue(writerdatum.Section, "sPath", writerdatum.Path); 793 | if (writerdatum.Format != TextureFormat.DXT1 && writerdatum.Format != TextureFormat.DXT5) 794 | { 795 | continue; 796 | } 797 | Texture2DOverride.mainini.WriteValue(writerdatum.Section, "bFlipTexture", true); 798 | } 799 | } 800 | catch (Exception exception) 801 | { 802 | IniSettings.Error(string.Concat("DumpTexture2D:\n", exception.ToString())); 803 | } 804 | Texture2DOverride.writerdata.Clear(); 805 | Texture2DOverride.WatchTextFiles(); 806 | } 807 | finally 808 | { 809 | Monitor.Exit(writerLock); 810 | } 811 | } 812 | } 813 | } -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/Texture2DOverrideData.cs: -------------------------------------------------------------------------------- 1 | extern alias U; 2 | using Texture2D = U::UnityEngine.Texture2D; 3 | namespace UnityEngine.UI.Translation 4 | { 5 | using System.Runtime.InteropServices; 6 | 7 | [StructLayout(LayoutKind.Sequential)] 8 | public struct Texture2DOverrideData 9 | { 10 | private int instanceID; 11 | private int overrideID; 12 | private int cacheID; 13 | private string originalname; 14 | private Texture2D originalTexture2D; 15 | private string texturepath; 16 | private Texture2D overrideTexture2D; 17 | private Texture2D overrideTextureCache; 18 | public int InstanceID 19 | { 20 | get 21 | { 22 | return this.instanceID; 23 | } 24 | } 25 | public int OverrideID 26 | { 27 | get 28 | { 29 | return this.overrideID; 30 | } 31 | } 32 | public int CacheID 33 | { 34 | get 35 | { 36 | return this.cacheID; 37 | } 38 | } 39 | public string OriginalName 40 | { 41 | get 42 | { 43 | return this.originalname; 44 | } 45 | } 46 | public Texture2D OriginalTexture2D 47 | { 48 | get 49 | { 50 | return this.originalTexture2D; 51 | } 52 | } 53 | public string TexturePath 54 | { 55 | get 56 | { 57 | return this.texturepath; 58 | } 59 | } 60 | public Texture2D OverrideTexture2D 61 | { 62 | get 63 | { 64 | return this.overrideTexture2D; 65 | } 66 | } 67 | public Texture2D OverrideTextureCache 68 | { 69 | get 70 | { 71 | return this.overrideTextureCache; 72 | } 73 | set 74 | { 75 | this.cacheID = (value == null) ? 0 : value.GetInstanceID(); 76 | this.overrideTextureCache = value; 77 | } 78 | } 79 | public Texture2DOverrideData(Texture2D originalTexture2D, string texturepath, Texture2D overrideTexture2D) 80 | { 81 | if (texturepath != null) 82 | { 83 | this.texturepath = texturepath; 84 | } 85 | else 86 | { 87 | this.texturepath = string.Empty; 88 | } 89 | if (originalTexture2D != null) 90 | { 91 | this.instanceID = originalTexture2D.GetInstanceID(); 92 | this.originalname = originalTexture2D.name; 93 | } 94 | else 95 | { 96 | this.instanceID = 0; 97 | this.originalname = string.Empty; 98 | } 99 | this.originalTexture2D = originalTexture2D; 100 | if (overrideTexture2D != null) 101 | { 102 | this.overrideID = overrideTexture2D.GetInstanceID(); 103 | } 104 | else 105 | { 106 | this.overrideID = 0; 107 | } 108 | this.overrideTexture2D = overrideTexture2D; 109 | this.cacheID = 0; 110 | this.overrideTextureCache = null; 111 | } 112 | } 113 | } 114 | 115 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/TranslationData.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal class TranslationData : TranslationDataBase 4 | { 5 | public TranslationData() 6 | { 7 | } 8 | 9 | public TranslationData(string path) : base(path) 10 | { 11 | } 12 | 13 | public TranslationData(string path, string value) : base(path, value) 14 | { 15 | } 16 | 17 | public TranslationData(string path, string key, string value) : base(path, value) 18 | { 19 | this.Key = key; 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return string.Format("{0} {{ \"{1}\" = \"{2}\" }}", base.Path, this.Key, base.Value); 25 | } 26 | 27 | public string Key { get; protected set; } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /UnityEngine.UI.Translation/UnityEngine/UI/Translation/TranslationDataBase.cs: -------------------------------------------------------------------------------- 1 | namespace UnityEngine.UI.Translation 2 | { 3 | internal class TranslationDataBase 4 | { 5 | public TranslationDataBase() 6 | { 7 | } 8 | 9 | public TranslationDataBase(string path) : this(path, string.Empty) 10 | { 11 | } 12 | 13 | public TranslationDataBase(string path, string value) 14 | { 15 | this.Path = path; 16 | this.Value = value; 17 | } 18 | 19 | public override string ToString() 20 | { 21 | return string.Format("{0} {{ \"{1}\" }}", this.Path, this.Value); 22 | } 23 | 24 | public string Path { get; protected set; } 25 | 26 | public string Value { get; protected set; } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Unity UI Translation 2 | 3 | A solution for Unity games (UGUI) translation, created by akyryz at first. 4 | 5 | Currently, it supports Unity **5.x-5.6.0**. It won't work on Unity 5.6.3+ because of some type changes. The further versions will focus on the newest Unity versions. 6 | 7 | Notice: This is for game translation without the source project. If you are a developer and searching for a solution to use in your own game, this project is not for you. 8 | 9 | ## UITL 10 | 11 | *UnityEngine.UI.Translation* by akyryz 12 | 13 | The **Loader**. It's based on [akyryz's **UI Translation Loader**](http://www.anime-sharing.com/forum/requests-releases-123/release-ui-translation-loader-v0-12-3-translation-502649/) (version 0.16). 14 | It works with modified *UnityEngine* & *UnityEngine.UI* to dump texts/textures/audios and reload the translated version at runtime. 15 | 16 | TODO: 17 | - Font support 18 | 19 | ## UITI 20 | 21 | *UInjector* by Ulysses 22 | 23 | The **Injector**. It modifies *UnityEngine* & *UnityEngine.UI* to create a version which can co-operate with the Loader. It aims to support Unity 5.x. 24 | 25 | It only supports the Loader here and may not support akyryz's new version since I have no idea what he might add into it :) and I may add some other things into it later. 26 | 27 | ## Demo 28 | 29 | Japanese: (Original) 30 | 31 | ![P.K.-jp](https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/master/screenshot/UIT-jp-1.png) 32 | 33 | English: 34 | 35 | ![P.K.-en](https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/master/screenshot/UIT-en-1.png) 36 | 37 | Chinese: (*Currently, the font is changed manually.*) 38 | 39 | ![P.K.-zh](https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/master/screenshot/UIT-zh-1.png) 40 | 41 | -------------------------------------------------------------------------------- /ref/UnityEngine.UI.ref.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/51237459a23252384548f7a6e0a99cb8032d9769/ref/UnityEngine.UI.ref.dll -------------------------------------------------------------------------------- /ref/UnityEngine.ref.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/51237459a23252384548f7a6e0a99cb8032d9769/ref/UnityEngine.ref.dll -------------------------------------------------------------------------------- /screenshot/UIT-en-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/51237459a23252384548f7a6e0a99cb8032d9769/screenshot/UIT-en-1.png -------------------------------------------------------------------------------- /screenshot/UIT-jp-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/51237459a23252384548f7a6e0a99cb8032d9769/screenshot/UIT-jp-1.png -------------------------------------------------------------------------------- /screenshot/UIT-zh-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UlyssesWu/UnityEngine.UI.Translation/51237459a23252384548f7a6e0a99cb8032d9769/screenshot/UIT-zh-1.png --------------------------------------------------------------------------------