├── .github
└── FUNDING.yml
├── ACT.FFXIVTranslate
├── RTFLib
│ ├── RTF
│ │ ├── IRtfProcessor.cs
│ │ ├── RTFBorderSide.cs
│ │ ├── RTFFont.cs
│ │ ├── IRTFCell.cs
│ │ ├── IRTFRow.cs
│ │ ├── RTFAlignment.cs
│ │ ├── RTFBuilder.UnWrapped.cs
│ │ ├── RTFUtil.cs
│ │ ├── RTFBuilder.RTFParaWrap.cs
│ │ ├── RTFCell.cs
│ │ ├── RTFRowDefinition.cs
│ │ ├── RTFCellDefinition.cs
│ │ ├── RTFBuilder.RTFFonts.cs
│ │ ├── RTFCellDefinitionBuilder.cs
│ │ ├── RTFBuilder.RTFFormatWrap.cs
│ │ └── RTFBuilder.cs
│ ├── RTFLib.sln
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── RTFLib.csproj
├── ACT.FFXIVTranslate
│ ├── ILMergeOrder.txt
│ ├── packages.config
│ ├── localization
│ │ └── Localization.cs
│ ├── UpdateChecker.cs
│ ├── app.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── translate
│ │ ├── youdao
│ │ │ ├── YoudaoTranslateProviderFactory.cs
│ │ │ └── YoudaoTranslateProvider.cs
│ │ ├── baidu
│ │ │ ├── BaiduTranslateProviderFactory.cs
│ │ │ └── BaiduTranslateProvider.cs
│ │ ├── microsoft
│ │ │ ├── MicrosoftTranslateProviderFactory.cs
│ │ │ ├── AzureAuthToken.cs
│ │ │ └── MicrosoftTranslateProvider.cs
│ │ ├── google_unofficial
│ │ │ ├── GoogleTranslateProviderFactory.cs
│ │ │ └── GoogleTranslateProvider.cs
│ │ ├── tencent
│ │ │ ├── TencentTranslateProviderFactory.cs
│ │ │ └── TencentTranslateProvider.cs
│ │ ├── yandax
│ │ │ ├── YandaxTranslateProviderFactory.cs
│ │ │ └── YandaxTranslateProvider.cs
│ │ ├── ITranslateProvider.cs
│ │ ├── TranslateProviderPanel.cs
│ │ └── TranslateService.cs
│ ├── ProxyFactory.cs
│ ├── ILMerge.props
│ ├── WindowsMessagePump.cs
│ ├── MainController.cs
│ └── SettingsHolder.cs
├── ACT.FFXIVTranslate.Test
│ ├── packages.config
│ ├── app.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── WorldNameTest.cs
│ ├── YandaxTranslateTest.cs
│ ├── MicrosoftTranslateTest.cs
│ ├── UnofficialGoogleTranslateTest.cs
│ ├── BaiduTranslateTest.cs
│ ├── YoudaoTranslateTest.cs
│ └── ACT.FFXIVTranslate.Test.csproj
└── ACT.FFXIVTranslate.sln
├── .gitmodules
├── appveyor.yml
├── .gitattributes
├── .gitignore
├── README.md
└── MSBuild.ILMerge.Task.targets
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: Noisyfox
2 | custom: ['https://paypal.me/noisyfox']
3 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/IRtfProcessor.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Noisyfox/ACT.FFXIVTranslate/HEAD/ACT.FFXIVTranslate/RTFLib/RTF/IRtfProcessor.cs
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ACT.FFXIVTranslate/ACT.FoxCommon"]
2 | path = ACT.FFXIVTranslate/ACT.FoxCommon
3 | url = https://github.com/Noisyfox/ACT.FoxCommon.git
4 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/ILMergeOrder.txt:
--------------------------------------------------------------------------------
1 | # this file contains the partial list of the merged assemblies in the merge order
2 | # you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build
3 | # and finetune merge order to your satisfaction
4 |
5 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBorderSide.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System;
9 |
10 | [Flags]
11 | public enum RTFBorderSide
12 | {
13 | None = 0,
14 | Left = 0x01,
15 | Right = 0x02,
16 | Top = 0x04,
17 | Bottom = 0x08,
18 | Default = 0x0F,
19 | DoubleThickness = 0x10,
20 | DoubleBorder = 0x20
21 | }
22 | }
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFFont.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | namespace RTF
6 | {
7 | public enum RTFFont
8 | {
9 | Arial,
10 | ArialBlack,
11 | BookmanOldStyle,
12 | Broadway,
13 | CenturyGothic ,
14 | Consolas ,
15 | CordiaNew ,
16 | CourierNew,
17 | FontTimesNewRoman,
18 | Garamond,
19 | Georgia ,
20 | Impact ,
21 | LucidaConsole ,
22 | Symbol ,
23 | WingDings ,
24 | MSSansSerif
25 | }
26 | }
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("ACT.FFXIVTranslate.Test")]
6 | [assembly: AssemblyDescription("")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyCompany("")]
9 | [assembly: AssemblyProduct("ACT.FFXIVTranslate.Test")]
10 | [assembly: AssemblyCopyright("Copyright © 2017")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | [assembly: ComVisible(false)]
15 |
16 | [assembly: Guid("81906072-43fd-40d0-916a-f16d0eda15ba")]
17 |
18 | // [assembly: AssemblyVersion("1.0.*")]
19 | [assembly: AssemblyVersion("1.0.0.0")]
20 | [assembly: AssemblyFileVersion("1.0.0.0")]
21 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/localization/Localization.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 | using ACT.FoxCommon.localization;
3 |
4 | namespace ACT.FFXIVTranslate.localization
5 | {
6 | public static class Localization
7 | {
8 | public static readonly LanguageDef[] SupportedLanguages = {
9 | LanguageDef.BuildLangFromCulture("zh-CN"),
10 | LanguageDef.BuildLangFromCulture("en-US"),
11 | };
12 |
13 | private const string DefaultLanguage = "zh-CN";
14 |
15 | static Localization()
16 | {
17 | LocalizationBase.InitLocalization(strings.ResourceManager, SupportedLanguages, DefaultLanguage);
18 | }
19 |
20 |
21 | public static void ConfigLocalization(string code)
22 | {
23 | strings.Culture = CultureInfo.GetCultureInfo(code);
24 | LocalizationBase.ConfigLocalization(code);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/UpdateChecker.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using ACT.FoxCommon.update;
3 |
4 | namespace ACT.FFXIVTranslate
5 | {
6 | internal class UpdateChecker : UpdateCheckerBase
7 | {
8 | public const string ReleasePage = "https://github.com/Noisyfox/ACT.FFXIVTranslate/releases";
9 |
10 |
11 | protected override string UpdateUrl { get; } = "https://api.github.com/repos/Noisyfox/ACT.FFXIVTranslate/releases";
12 |
13 | private const string NameMatcher =
14 | @"^ACT\.FFXIVTranslate(?:-|\.)(?\d+(?:\.\d+)*)(?:|-Release)\.7z$";
15 |
16 | protected override string ParseVersion(string fileName)
17 | {
18 | var match = Regex.Match(fileName, NameMatcher);
19 | if (match.Success)
20 | {
21 | return match.Groups["version"].Value;
22 | }
23 |
24 | return null;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.6.1.{build}
2 | image: Visual Studio 2019
3 | configuration:
4 | - Debug
5 | - Release
6 | assembly_info:
7 | patch: true
8 | file: ACT.FFXIVTranslate\ACT.FFXIVTranslate*\**\AssemblyInfo.*
9 | assembly_version: '{version}'
10 | assembly_file_version: '{version}'
11 | assembly_informational_version: '{version}'
12 | before_build:
13 | - cmd: >-
14 | git submodule update --init --recursive
15 |
16 | nuget restore ACT.FFXIVTranslate
17 |
18 | cp MSBuild.ILMerge.Task.targets .\ACT.FFXIVTranslate\packages\MSBuild.ILMerge.Task.1.1.3\build\MSBuild.ILMerge.Task.targets
19 | build:
20 | project: ACT.FFXIVTranslate/ACT.FFXIVTranslate.sln
21 | verbosity: minimal
22 | after_build:
23 | - cmd: >-
24 | cd ACT.FFXIVTranslate\ACT.FFXIVTranslate\bin\%CONFIGURATION%\
25 |
26 |
27 | 7z a -x!*.pdb %APPVEYOR_BUILD_FOLDER%\ACT.FFXIVTranslate-%APPVEYOR_BUILD_VERSION%-%CONFIGURATION%.7z .\*
28 | test: off
29 | artifacts:
30 | - path: ACT.FFXIVTranslate\ACT.FFXIVTranslate\bin\**\*
31 | name: Bin
32 | - path: ACT.FFXIVTranslate*.7z
33 | name: PKG
34 |
35 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/IRTFCell.cs:
--------------------------------------------------------------------------------
1 | namespace RTF
2 | {
3 | using System;
4 |
5 | // ----------------------------------------------------------------------------------------
6 | // _ ___ _..-._ Date: 12/11/08 23:32
7 | // \`.|\..----...-'` `-._.-'' _.-..'
8 | // / ' ` , __.-''
9 | // )/` _/ \ `-_, / Solution: RTFLib
10 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
11 | // _.-'_./ {_.' ; / Author : Anton
12 | // {_.-``-' {_/ Assembly: 1.0.0.0
13 | // Copyright © 2005-2008, Rogue Trader/MWM
14 | // Project Item Name: IRTFCell.cs - Code
15 | // Purpose: Exposes an underlying RTFBuilderbase
16 | // ----------------------------------------------------------------------------------------
17 | ///
18 | /// Exposes an underlying RTFBuilderbase
19 | ///
20 | public interface IBuilderContent : IDisposable
21 | {
22 | RTFBuilderbase Content { get; }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/IRTFRow.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System;
9 | using System.Collections.Generic;
10 |
11 | // ----------------------------------------------------------------------------------------
12 | // _ ___ _..-._ Date: 12/11/08 23:33
13 | // \`.|\..----...-'` `-._.-'' _.-..'
14 | // / ' ` , __.-''
15 | // )/` _/ \ `-_, / Solution: RTFLib
16 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
17 | // _.-'_./ {_.' ; / Author : Anton
18 | // {_.-``-' {_/ Assembly: 1.0.0.0
19 | // Copyright © 2005-2008, Rogue Trader/MWM
20 | // Project Item Name: IRTFRow.cs - Code
21 | // Purpose: Row Interface
22 | // ----------------------------------------------------------------------------------------
23 | ///
24 | /// Row Interface
25 | ///
26 | public interface IRTFRow : IDisposable, IEnumerable
27 | {
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("ACT.FFXIVTranslate")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ACT.FFXIVTranslate")]
13 | [assembly: AssemblyCopyright("Copyright © 2017-2021 Noisyfox")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | //将 ComVisible 设置为 false 将使此程序集中的类型
18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("7263a6d5-a142-4f3f-92a7-c3dfa9ba45b9")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
33 | // 方法是按如下所示使用“*”: :
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.6.1.0")]
36 | [assembly: AssemblyFileVersion("1.6.1.0")]
37 |
38 | [assembly: InternalsVisibleTo("ACT.FFXIVTranslate.Test")]
39 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/WorldNameTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Collections.Generic;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace ACT.FFXIVTranslate.Test
7 | {
8 | [TestClass]
9 | public class WorldNameTest
10 | {
11 | [TestMethod]
12 | public void TestParseSenderName()
13 | {
14 | var bytes = new byte[]
15 | {
16 | 0x02, 0x27, 0x13, 0x01, 0x0F, 0x01, 0x01, 0xEF, 0xBF, 0xBD, 0x20, 0x4D, 0x69, 0x6C, 0x61, 0x20,
17 | 0x45, 0x74, 0x65, 0x72, 0x6E, 0x61, 0x6C, 0x03, 0xEE, 0x82, 0x96, 0x4D, 0x69, 0x6C, 0x61, 0x20,
18 | 0x45, 0x74, 0x65, 0x72, 0x6E, 0x61, 0x6C, 0x02, 0x27, 0x07, 0xEF, 0xBF, 0xBD, 0x01, 0x01, 0x01,
19 | 0xEF, 0xBF, 0xBD, 0x01, 0x03, 0x02, 0x12, 0x02, 0x59, 0x03, 0x55, 0x6C, 0x74, 0x69, 0x6D, 0x61
20 | };
21 | // var bytes = new byte[]
22 | // {
23 | // 0x02, 0x12, 0x02, 0x59, 0x03, 0x55, 0x6C, 0x74, 0x69, 0x6D, 0x61
24 | // };
25 |
26 | var input = Encoding.UTF8.GetString(bytes);
27 |
28 | var v = TextProcessor.ExtractName(input);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTFLib.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTFLib", "RTFLib\RTFLib.csproj", "{CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTFLibDemo", "RTFLibDemo\RTFLibDemo.csproj", "{A0E9311B-1207-4331-BAB8-0ABA5B380589}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {A0E9311B-1207-4331-BAB8-0ABA5B380589}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {A0E9311B-1207-4331-BAB8-0ABA5B380589}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {A0E9311B-1207-4331-BAB8-0ABA5B380589}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {A0E9311B-1207-4331-BAB8-0ABA5B380589}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | EndGlobal
27 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/YandaxTranslateTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using ACT.FFXIVTranslate.translate.yandax;
3 | using ACT.FoxCommon.localization;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace ACT.FFXIVTranslate.Test
7 | {
8 | [TestClass]
9 | public class YandaxTranslateTest
10 | {
11 | [TestMethod]
12 | public void TestYandaxTranslate()
13 | {
14 | var factory = new YandaxTranslateProviderFactory();
15 | var key = factory.DefaultPublicKey;
16 | var to = LanguageDef.BuildLangFromCulture("zh");
17 | var provider = factory.CreateProvider(key, null, to);
18 |
19 | var lines = new[]
20 | {
21 | new ChattingLine {RawContent = "This is a testing string."},
22 | new ChattingLine {RawContent = "This is another testing string."},
23 | new ChattingLine {RawContent = "Wow lots of strings!"},
24 | new ChattingLine {RawContent = "I like the game called 'Final Fantasy XIV'!"},
25 | new ChattingLine {RawContent = "This is a string contains html tag."},
26 | new ChattingLine {RawContent = "This is a string < contains html tag."},
27 | new ChattingLine {RawContent = "<"},
28 | }.Select(it =>
29 | {
30 | provider.PreprocessLine(it);
31 | return it;
32 | }).ToList();
33 |
34 | provider.Translate(lines);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RTFLib")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RTFLib")]
13 | [assembly: AssemblyCopyright("Copyright © 2008")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("640e0969-5726-48bd-9855-ef80f796f2f1")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/MicrosoftTranslateTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using ACT.FFXIVTranslate.translate.microsoft;
3 | using ACT.FoxCommon.localization;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace ACT.FFXIVTranslate.Test
7 | {
8 | [TestClass]
9 | public class MicrosoftTranslateTest
10 | {
11 | [TestMethod]
12 | public void TestMicrosoftTranslate()
13 | {
14 | var factory = new MicrosoftTranslateProviderFactory();
15 | var key = "90ebd9b5e7544500a5c1cf3ff7996314";
16 | var to = LanguageDef.BuildLangFromCulture("zh-CHS");
17 | var provider = factory.CreateProvider(key, null, to);
18 |
19 | var lines = new[]
20 | {
21 | new ChattingLine{RawContent = "This is a testing string."},
22 | new ChattingLine{RawContent = "This is another testing string."},
23 | new ChattingLine{RawContent = "Wow lots of strings!"},
24 | new ChattingLine{RawContent = "I like the game called 'Final Fantasy XIV'!"},
25 | new ChattingLine{RawContent = "This is a string contains html tag."},
26 | new ChattingLine{RawContent = "This is a string < contains html tag."},
27 | new ChattingLine{RawContent = "<"},
28 | }.Select(it =>
29 | {
30 | provider.PreprocessLine(it);
31 | return it;
32 | }).ToList();
33 |
34 | provider.Translate(lines);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/youdao/YoudaoTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.youdao
6 | {
7 | internal class YoudaoTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh-CHS"),
12 | LanguageDef.BuildLangFromCulture("en", "EN"),
13 | LanguageDef.BuildLangFromCulture("ja"),
14 | LanguageDef.BuildLangFromCulture("fr"),
15 | LanguageDef.BuildLangFromCulture("ru"),
16 | LanguageDef.BuildLangFromCulture("ko"),
17 | }.ToList();
18 |
19 | public string ProviderId => "有道翻译";
20 | public string ProviderName => LocalizationBase.GetString("translateProviderNameYoudao", ProviderId);
21 | public bool SupportAutoDetect => true;
22 | public List SupportedSrcLanguages => _allSupportedLanguages;
23 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
24 | {
25 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
26 | }
27 | public ProviderLegalInfo LegalInfo => null;
28 | public string DefaultPublicKey => null;
29 |
30 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
31 | {
32 | return new YoudaoTranslateProvider(apiKey, src, dst);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/UnofficialGoogleTranslateTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using ACT.FFXIVTranslate.localization;
3 | using ACT.FFXIVTranslate.translate.google_unofficial;
4 | using ACT.FoxCommon.localization;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | namespace ACT.FFXIVTranslate.Test
8 | {
9 | [TestClass]
10 | public class UnofficialGoogleTranslateTest
11 | {
12 | [TestMethod]
13 | public void TestUnofficialGoogleTranslate()
14 | {
15 | var factory = new GoogleTranslateProviderFactory();
16 | var to = LanguageDef.BuildLangFromCulture("zh");
17 | var provider = factory.CreateProvider(null, null, to);
18 |
19 | var lines = new[]
20 | {
21 | new ChattingLine{RawContent = "This is a testing string."},
22 | new ChattingLine{RawContent = "This is another testing string."},
23 | new ChattingLine{RawContent = "Wow lots of strings!"},
24 | new ChattingLine{RawContent = "I like the game called 'Final Fantasy XIV'!"},
25 | new ChattingLine{RawContent = "This is a string contains html tag."},
26 | new ChattingLine{RawContent = "This is a string < contains html tag."},
27 | new ChattingLine{RawContent = "<"},
28 | new ChattingLine{RawContent = "你在逗我呢?"},
29 | }.Select(it =>
30 | {
31 | provider.PreprocessLine(it);
32 | return it;
33 | }).ToList();
34 |
35 | provider.Translate(lines);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/BaiduTranslateTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using ACT.FFXIVTranslate.translate.baidu;
3 | using ACT.FoxCommon.localization;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace ACT.FFXIVTranslate.Test
7 | {
8 | [TestClass]
9 | public class BaiduTranslateTest
10 | {
11 | [TestMethod]
12 | public void TestBaiduTranslate()
13 | {
14 | var factory = new BaiduTranslateProviderFactory();
15 | var to = LanguageDef.BuildLangFromCulture("zh");
16 | var appId = "YOUR-APP-ID";
17 | var secret = "YOUR-APP-SECRET";
18 | var provider = factory.CreateProvider($"{appId}:{secret}", null, to);
19 |
20 | var lines = new[]
21 | {
22 | new ChattingLine{RawContent = "This is a testing string."},
23 | new ChattingLine{RawContent = "This is another testing string."},
24 | new ChattingLine{RawContent = "Wow lots of strings!"},
25 | new ChattingLine{RawContent = "I like the game called 'Final Fantasy XIV'!"},
26 | new ChattingLine{RawContent = "This is a string contains html tag."},
27 | new ChattingLine{RawContent = "This is a string < contains html tag."},
28 | new ChattingLine{RawContent = "<"},
29 | new ChattingLine{RawContent = "你在逗我呢?"},
30 | }.Select(it =>
31 | {
32 | provider.PreprocessLine(it);
33 | return it;
34 | }).ToList();
35 |
36 | provider.Translate(lines);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/YoudaoTranslateTest.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using ACT.FFXIVTranslate.translate.youdao;
3 | using ACT.FoxCommon.localization;
4 | using Microsoft.VisualStudio.TestTools.UnitTesting;
5 |
6 | namespace ACT.FFXIVTranslate.Test
7 | {
8 | [TestClass]
9 | public class YoudaoTranslateTest
10 | {
11 | [TestMethod]
12 | public void TestYoudaoTranslate()
13 | {
14 | var factory = new YoudaoTranslateProviderFactory();
15 | var to = LanguageDef.BuildLangFromCulture("zh-CHS");
16 | var appId = "YOUR-APP-ID";
17 | var secret = "YOUR-APP-SECRET";
18 | var provider = factory.CreateProvider($"{appId}:{secret}", null, to);
19 |
20 | var lines = new[]
21 | {
22 | new ChattingLine{RawContent = "This is a testing string."},
23 | new ChattingLine{RawContent = "This is another testing string."},
24 | new ChattingLine{RawContent = "Wow lots of strings!"},
25 | new ChattingLine{RawContent = "I like the game called 'Final Fantasy XIV'!"},
26 | new ChattingLine{RawContent = "This is a string contains html tag."},
27 | new ChattingLine{RawContent = "This is a string < contains html tag."},
28 | new ChattingLine{RawContent = "<"},
29 | new ChattingLine{RawContent = "你在逗我呢?"},
30 | }.Select(it =>
31 | {
32 | provider.PreprocessLine(it);
33 | return it;
34 | }).ToList();
35 |
36 | provider.Translate(lines);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/baidu/BaiduTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.baidu
6 | {
7 | internal class BaiduTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh"),
12 | LanguageDef.BuildLangFromCulture("en"),
13 | LanguageDef.BuildLangFromCulture("ja", "jp"),
14 | LanguageDef.BuildLangFromCulture("de"),
15 | LanguageDef.BuildLangFromCulture("fr", "fra"),
16 | LanguageDef.BuildLangFromCulture("ru"),
17 | LanguageDef.BuildLangFromCulture("ko", "kor"),
18 | }.ToList();
19 |
20 | public string ProviderId => "百度翻译";
21 | public string ProviderName => LocalizationBase.GetString("translateProviderNameBaidu", ProviderId);
22 |
23 | public bool SupportAutoDetect => true;
24 | public List SupportedSrcLanguages => _allSupportedLanguages;
25 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
26 | {
27 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
28 | }
29 |
30 | public ProviderLegalInfo LegalInfo => null;
31 | public string DefaultPublicKey => null;
32 |
33 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
34 | {
35 | return new BaiduTranslateProvider(apiKey, src, dst);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/microsoft/MicrosoftTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.microsoft
6 | {
7 | internal class MicrosoftTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh-CHS"),
12 | LanguageDef.BuildLangFromCulture("zh-CHT"),
13 | LanguageDef.BuildLangFromCulture("en"),
14 | LanguageDef.BuildLangFromCulture("ja"),
15 | LanguageDef.BuildLangFromCulture("de"),
16 | LanguageDef.BuildLangFromCulture("fr"),
17 | LanguageDef.BuildLangFromCulture("ru"),
18 | LanguageDef.BuildLangFromCulture("ko"),
19 | }.ToList();
20 |
21 | public string ProviderId => "Microsoft Translator";
22 | public string ProviderName => LocalizationBase.GetString("translateProviderNameMicrosoft", ProviderId);
23 | public bool SupportAutoDetect => true;
24 | public List SupportedSrcLanguages => _allSupportedLanguages;
25 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
26 | {
27 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
28 | }
29 | public ProviderLegalInfo LegalInfo => null;
30 | public string DefaultPublicKey => null;
31 |
32 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
33 | {
34 | return new MicrosoftTranslateProvider(apiKey, src, dst);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/google_unofficial/GoogleTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.google_unofficial
6 | {
7 | internal class GoogleTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh-CN"),
12 | LanguageDef.BuildLangFromCulture("zh-TW"),
13 | LanguageDef.BuildLangFromCulture("en"),
14 | LanguageDef.BuildLangFromCulture("ja"),
15 | LanguageDef.BuildLangFromCulture("de"),
16 | LanguageDef.BuildLangFromCulture("fr"),
17 | LanguageDef.BuildLangFromCulture("ru"),
18 | LanguageDef.BuildLangFromCulture("ko"),
19 | }.ToList();
20 |
21 | public string ProviderId => "Google Translate (unofficial)";
22 | public string ProviderName => LocalizationBase.GetString("translateProviderNameGoogleUnofficial", ProviderId);
23 | public bool SupportAutoDetect => true;
24 | public List SupportedSrcLanguages => _allSupportedLanguages;
25 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
26 | {
27 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
28 | }
29 | public ProviderLegalInfo LegalInfo => null;
30 | public string DefaultPublicKey => null;
31 |
32 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
33 | {
34 | return new GoogleTranslateProvider(src, dst);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/tencent/TencentTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.tencent
6 | {
7 | internal class TencentTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh-CN", "zh"),
12 | LanguageDef.BuildLangFromCulture("zh-TW"),
13 | LanguageDef.BuildLangFromCulture("en"),
14 | LanguageDef.BuildLangFromCulture("ja", "jp"),
15 | LanguageDef.BuildLangFromCulture("de"),
16 | LanguageDef.BuildLangFromCulture("fr"),
17 | LanguageDef.BuildLangFromCulture("ru"),
18 | LanguageDef.BuildLangFromCulture("ko", "kr"),
19 | }.ToList();
20 |
21 | public string ProviderId => "Tencent Translate";
22 | public string ProviderName => LocalizationBase.GetString("translateProviderNameTencent", ProviderId);
23 | public bool SupportAutoDetect => true;
24 | public List SupportedSrcLanguages => _allSupportedLanguages;
25 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
26 | {
27 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
28 | }
29 | public ProviderLegalInfo LegalInfo => null;
30 | public string DefaultPublicKey => "AKIDMSHqSphlMjpeFsgPu9ByUjzZz9KHnOZf:1nLn10iCcsscLq54qY2JnMglaPyHK7oG";
31 |
32 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
33 | {
34 | return new TencentTranslateProvider(apiKey, src, dst);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFAlignment.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System;
9 |
10 | [Flags]
11 | public enum RTFAlignment
12 | {
13 | None = 0,
14 |
15 | /// Content is vertically aligned at the bottom, and horizontally aligned at the center.
16 | /// 1
17 | BottomCenter = 512,
18 | /// Content is vertically aligned at the bottom, and horizontally aligned on the left.
19 | /// 1
20 | BottomLeft = 256,
21 | /// Content is vertically aligned at the bottom, and horizontally aligned on the right.
22 | /// 1
23 | BottomRight = 1024,
24 | /// Content is vertically aligned in the middle, and horizontally aligned at the center.
25 | /// 1
26 | MiddleCenter = 32,
27 | /// Content is vertically aligned in the middle, and horizontally aligned on the left.
28 | /// 1
29 | MiddleLeft = 16,
30 | /// Content is vertically aligned in the middle, and horizontally aligned on the right.
31 | /// 1
32 | MiddleRight = 64,
33 | /// Content is vertically aligned at the top, and horizontally aligned at the center.
34 | /// 1
35 | TopCenter = 2,
36 | /// Content is vertically aligned at the top, and horizontally aligned on the left.
37 | /// 1
38 | TopLeft = 1,
39 | /// Content is vertically aligned at the top, and horizontally aligned on the right.
40 | /// 1
41 | TopRight = 4
42 | }
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/yandax/YandaxTranslateProviderFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate.yandax
6 | {
7 | internal class YandaxTranslateProviderFactory : ITranslateProviderFactory
8 | {
9 | private readonly List _allSupportedLanguages = new[]
10 | {
11 | LanguageDef.BuildLangFromCulture("zh"),
12 | LanguageDef.BuildLangFromCulture("en"),
13 | LanguageDef.BuildLangFromCulture("ja"),
14 | LanguageDef.BuildLangFromCulture("de"),
15 | LanguageDef.BuildLangFromCulture("fr"),
16 | LanguageDef.BuildLangFromCulture("ru"),
17 | LanguageDef.BuildLangFromCulture("ko"),
18 | }.ToList();
19 |
20 | public string ProviderId => "Yandex Translate";
21 | public string ProviderName => LocalizationBase.GetString("translateProviderNameYandex", ProviderId);
22 |
23 | public bool SupportAutoDetect => true;
24 |
25 | public List SupportedSrcLanguages => _allSupportedLanguages;
26 | public List GetSupportedDestLanguages(LanguageDef srcLanguage)
27 | {
28 | return _allSupportedLanguages.Where(it => it != srcLanguage).ToList();
29 | }
30 | public ProviderLegalInfo LegalInfo { get; } = new ProviderLegalInfo
31 | {
32 | LabelMain = "Powered by Yandex.Translate",
33 | LabelResult = "Powered by Yandex.Translate",
34 | LabelMainLink = "http://translate.yandex.com",
35 | LabelResultLink = "http://translate.yandex.com",
36 | };
37 |
38 | public string DefaultPublicKey => "trnsl.1.1.20170716T025951Z.13c73247084b012d.3404189299f91adf7792235bc7cf7fb7f3bd26a2";
39 |
40 | public ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst)
41 | {
42 | return new YandaxTranslateProvider(apiKey, src, dst);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2008
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACT.FFXIVTranslate", "ACT.FFXIVTranslate\ACT.FFXIVTranslate.csproj", "{7263A6D5-A142-4F3F-92A7-C3DFA9BA45B9}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACT.FFXIVTranslate.Test", "ACT.FFXIVTranslate.Test\ACT.FFXIVTranslate.Test.csproj", "{81906072-43FD-40D0-916A-F16D0EDA15BA}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RTFLib", "RTFLib\RTFLib.csproj", "{CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACT.FoxCommon", "ACT.FoxCommon\ACT.FoxCommon\ACT.FoxCommon.csproj", "{78342B89-6BAA-43E8-824A-A6FB06CDE993}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {7263A6D5-A142-4F3F-92A7-C3DFA9BA45B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {7263A6D5-A142-4F3F-92A7-C3DFA9BA45B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {7263A6D5-A142-4F3F-92A7-C3DFA9BA45B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {7263A6D5-A142-4F3F-92A7-C3DFA9BA45B9}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {81906072-43FD-40D0-916A-F16D0EDA15BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {81906072-43FD-40D0-916A-F16D0EDA15BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {81906072-43FD-40D0-916A-F16D0EDA15BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {81906072-43FD-40D0-916A-F16D0EDA15BA}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {78342B89-6BAA-43E8-824A-A6FB06CDE993}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {78342B89-6BAA-43E8-824A-A6FB06CDE993}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {78342B89-6BAA-43E8-824A-A6FB06CDE993}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {78342B89-6BAA-43E8-824A-A6FB06CDE993}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {6CBEA01A-631F-40AE-9131-0FE099C906F9}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBuilder.UnWrapped.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | namespace RTF
5 | {
6 | using System;
7 |
8 | partial class RTFBuilder
9 | {
10 | #region Nested type: RTFBuilderUnWrapped
11 |
12 | // ----------------------------------------------------------------------------------------
13 | // _ ___ _..-._ Date: 12/11/08 23:38
14 | // \`.|\..----...-'` `-._.-'' _.-..'
15 | // / ' ` , __.-''
16 | // )/` _/ \ `-_, / Solution: RTFLib
17 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
18 | // _.-'_./ {_.' ; / Author : Anton
19 | // {_.-``-' {_/ Assembly: 1.0.0.0
20 | // Copyright © 2005-2008, Rogue Trader/MWM
21 | // Project Item Name: RTFBuilder.UnWrapped.cs - Code
22 | // Purpose: Cancels persistent Formatting Changes on an unwrapped RtfBuilder
23 | // ----------------------------------------------------------------------------------------
24 | ///
25 | /// Cancels persistent Formatting Changes on an unwrapped RtfBuilder
26 | /// Exposed by the FormatLock on RtfBuilderbase
27 | ///
28 | private class RTFBuilderUnWrapped : IDisposable
29 | {
30 | #region Fields
31 |
32 | private readonly RTFBuilder _builder;
33 | private readonly RTFFormatWrap wrapped;
34 |
35 | #endregion
36 |
37 | #region Constructor
38 |
39 | public RTFBuilderUnWrapped(RTFBuilder builder)
40 | {
41 | this.wrapped = new RTFFormatWrap(builder);
42 | this._builder = builder;
43 | this._builder._unwrapped = true;
44 | }
45 |
46 | #endregion
47 |
48 | #region Override Methods
49 |
50 | ~RTFBuilderUnWrapped()
51 | {
52 | this.Dispose(false);
53 | }
54 |
55 | #endregion
56 |
57 | #region Public Methods
58 |
59 | public void Dispose(bool disposing)
60 | {
61 | if (this._builder != null)
62 | {
63 | this.wrapped.Dispose();
64 | this._builder._unwrapped = false;
65 | }
66 | if (disposing)
67 | {
68 | GC.SuppressFinalize(this);
69 | }
70 | }
71 |
72 | #endregion
73 |
74 | #region IDisposable Members
75 |
76 | public void Dispose()
77 | {
78 | this.Dispose(true);
79 | }
80 |
81 | #endregion
82 | }
83 |
84 | #endregion
85 | }
86 | }
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/ITranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using ACT.FoxCommon.localization;
4 |
5 | namespace ACT.FFXIVTranslate.translate
6 | {
7 | internal interface ITranslateProvider
8 | {
9 | void Translate(List chattingLines);
10 |
11 | ///
12 | /// False if this line can be ignored (usually is empty), True otherwise.
13 | bool PreprocessLine(ChattingLine chattingLine);
14 | }
15 |
16 | ///
17 | /// A provider that use TextProcessor.NaiveCleanText() as the content preprocessor
18 | /// and ignores all empty lines after that.
19 | ///
20 | internal abstract class DefaultTranslateProvider : ITranslateProvider
21 | {
22 | public abstract void Translate(List chattingLines);
23 |
24 | public virtual bool PreprocessLine(ChattingLine chattingLine)
25 | {
26 | chattingLine.CleanedContent = TextProcessor.NaiveCleanText(chattingLine.RawContent);
27 |
28 | return !string.IsNullOrEmpty(chattingLine.CleanedContent);
29 | }
30 | }
31 |
32 | internal interface ITranslateProviderFactory
33 | {
34 | string ProviderId { get; }
35 |
36 | string ProviderName { get; }
37 |
38 | bool SupportAutoDetect { get; }
39 |
40 | List SupportedSrcLanguages { get; }
41 |
42 | List GetSupportedDestLanguages(LanguageDef srcLanguage);
43 |
44 |
45 | ProviderLegalInfo LegalInfo { get; }
46 |
47 | ///
48 | /// The default API key for free public use. A gift from me :)
49 | ///
50 | string DefaultPublicKey { get; }
51 |
52 | ITranslateProvider CreateProvider(string apiKey, LanguageDef src, LanguageDef dst);
53 | }
54 |
55 | internal class TranslateException : Exception
56 | {
57 | public enum ExceptionReason
58 | {
59 | InvalidApiKey,
60 | ApiLimitExceed,
61 | DirectionNotSupported,
62 | GeneralServiceError,
63 | NetworkError,
64 | InternalError,
65 | UnknownError
66 | }
67 |
68 | public ExceptionReason Reason { get; }
69 |
70 | public TranslateException(ExceptionReason reason, string message, Exception innerException)
71 | : base(message, innerException)
72 | {
73 | Reason = reason;
74 | }
75 |
76 | public override string ToString()
77 | {
78 | return $"({Reason}){base.ToString()}";
79 | }
80 | }
81 |
82 | public class ProviderLegalInfo
83 | {
84 | public string LabelMain { get; set; }
85 | public string LabelMainLink { get; set; }
86 | public string LabelResult { get; set; }
87 | public string LabelResultLink { get; set; }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTFLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {CD1CF51F-CDE9-4403-A07E-C8CA4C015C58}
9 | Library
10 | Properties
11 | RTFLib
12 | RTFLib
13 | v2.0
14 | 512
15 |
16 |
17 |
18 |
19 | 3.5
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
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 |
77 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/ProxyFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Http;
4 | using Extreme.Net;
5 |
6 | namespace ACT.FFXIVTranslate
7 | {
8 | class ProxyFactory : IPluginComponent
9 | {
10 | public const string TypeNone = "none";
11 | public const string TypeHttp = "http";
12 | public const string TypeSocks5 = "socks5";
13 |
14 | public static ProxyFactory Instance { get; } = new ProxyFactory();
15 |
16 | private ProxyFactory()
17 | {
18 |
19 | }
20 |
21 | private ProxySettings _currentSettings;
22 |
23 | public void AttachToAct(FFXIVTranslatePlugin plugin)
24 | {
25 | plugin.Controller.ProxyChanged += ControllerOnProxyChanged;
26 | }
27 |
28 | public void PostAttachToAct(FFXIVTranslatePlugin plugin)
29 | {
30 | }
31 |
32 | private void ControllerOnProxyChanged(bool fromView, string type, string server, int port, string user,
33 | string password, string domain)
34 | {
35 | if (!fromView)
36 | {
37 | return;
38 | }
39 |
40 | _currentSettings = new ProxySettings
41 | {
42 | Type = type,
43 | Server = server,
44 | Port = port,
45 | User = user,
46 | Password = password,
47 | Domain = domain
48 | };
49 | }
50 |
51 | private class ProxySettings
52 | {
53 | public string Type { get; set; }
54 | public string Server { get; set; }
55 | public int Port { get; set; }
56 | public string User { get; set; }
57 | public string Password { get; set; }
58 | public string Domain { get; set; }
59 | }
60 |
61 | public HttpClient NewClient()
62 | {
63 | var settings = _currentSettings;
64 | if (settings == null || settings.Type == TypeNone)
65 | {
66 | return new HttpClient(new HttpClientHandler
67 | {
68 | UseProxy = false
69 | });
70 | }
71 | switch (settings.Type)
72 | {
73 | case TypeHttp:
74 | {
75 | var proxyCreds = new NetworkCredential(settings.User, settings.Password, settings.Domain);
76 | var proxy = new WebProxy(new Uri($"http://{settings.Server}:{settings.Port}"), true)
77 | {
78 | UseDefaultCredentials = false,
79 | Credentials = proxyCreds
80 | };
81 | var handler = new HttpClientHandler
82 | {
83 | Proxy = proxy,
84 | UseProxy = true,
85 | PreAuthenticate = true,
86 | UseDefaultCredentials = false
87 | };
88 | return new HttpClient(handler);
89 | }
90 | case TypeSocks5:
91 | {
92 | var proxy = new Socks5ProxyClient(settings.Server, settings.Port, settings.User, settings.Password);
93 | var handler = new ProxyHandler(proxy);
94 | return new HttpClient(handler);
95 | }
96 | default:
97 | throw new Exception($"Proxy Error: Unknown proxy type: {settings.Type}");
98 | }
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/ILMerge.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | true
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
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 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFUtil.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System.Text;
9 |
10 | // ----------------------------------------------------------------------------------------
11 | // _ ___ _..-._ Date: 12/11/08 23:50
12 | // \`.|\..----...-'` `-._.-'' _.-..'
13 | // / ' ` , __.-''
14 | // )/` _/ \ `-_, / Solution: RTFLib
15 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
16 | // _.-'_./ {_.' ; / Author : Anton
17 | // {_.-``-' {_/ Assembly: 1.0.0.0
18 | // Copyright © 2005-2008, Rogue Trader/MWM
19 | // Project Item Name: RTFUtil.cs - Code
20 | // Purpose: A Work in Progress
21 | // ----------------------------------------------------------------------------------------
22 | ///
23 | /// A Work in Progress
24 | ///
25 | public class RTFUtil
26 | {
27 | #region Public Methods
28 |
29 | public void ParagraphBorderSide(StringBuilder sb, RTFBorderSide rTFBorderSide)
30 | {
31 | if (rTFBorderSide == RTFBorderSide.None)
32 | {
33 | return;
34 | }
35 | if ((rTFBorderSide & RTFBorderSide.Left) == RTFBorderSide.Left)
36 | {
37 | sb.Append("\\brdrl");
38 | }
39 | if ((rTFBorderSide & RTFBorderSide.Right) == RTFBorderSide.Right)
40 | {
41 | sb.Append("\\brdrr");
42 | }
43 | if ((rTFBorderSide & RTFBorderSide.Top) == RTFBorderSide.Top)
44 | {
45 | sb.Append("\\brdrt");
46 | }
47 | if ((rTFBorderSide & RTFBorderSide.Bottom) == RTFBorderSide.Bottom)
48 | {
49 | sb.Append("\\brdrb");
50 | }
51 |
52 | if ((rTFBorderSide & RTFBorderSide.DoubleThickness) == RTFBorderSide.DoubleThickness)
53 | {
54 | sb.Append("\\brdrth");
55 | }
56 | else
57 | {
58 | sb.Append("\\brdrs");
59 | }
60 | if ((rTFBorderSide & RTFBorderSide.DoubleBorder) == RTFBorderSide.DoubleBorder)
61 | {
62 | sb.Append("\\brdrdb");
63 | }
64 | sb.Append("\\brdrw10");
65 | }
66 |
67 | public void TableRowBorderSide(StringBuilder sb, RTFBorderSide rTFBorderSide)
68 | {
69 | if (rTFBorderSide == RTFBorderSide.None)
70 | {
71 | return;
72 | }
73 | if ((rTFBorderSide & RTFBorderSide.Left) == RTFBorderSide.Left)
74 | {
75 | sb.Append("\\trbrdrl");
76 | }
77 | if ((rTFBorderSide & RTFBorderSide.Right) == RTFBorderSide.Right)
78 | {
79 | sb.Append("\\trbrdrr");
80 | }
81 | if ((rTFBorderSide & RTFBorderSide.Top) == RTFBorderSide.Top)
82 | {
83 | sb.Append("\\trbrdrt");
84 | }
85 | if ((rTFBorderSide & RTFBorderSide.Bottom) == RTFBorderSide.Bottom)
86 | {
87 | sb.Append("\\trbrdrb");
88 | }
89 | if ((rTFBorderSide & RTFBorderSide.DoubleThickness) == RTFBorderSide.DoubleThickness)
90 | {
91 | sb.Append("\\brdrth");
92 | }
93 | else
94 | {
95 | sb.Append("\\brdrs");
96 | }
97 | if ((rTFBorderSide & RTFBorderSide.DoubleBorder) == RTFBorderSide.DoubleBorder)
98 | {
99 | sb.Append("\\brdrdb");
100 | }
101 | sb.Append("\\brdrw10");
102 | }
103 |
104 | #endregion
105 | }
106 | }
107 |
108 |
109 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBuilder.RTFParaWrap.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System;
9 | using System.Drawing;
10 |
11 | public partial class RTFBuilder
12 | {
13 | #region Nested type: RTFParaWrap
14 |
15 | // ----------------------------------------------------------------------------------------
16 | // _ ___ _..-._ Date: 12/11/08 23:36
17 | // \`.|\..----...-'` `-._.-'' _.-..'
18 | // / ' ` , __.-''
19 | // )/` _/ \ `-_, / Solution: RTFLib
20 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
21 | // _.-'_./ {_.' ; / Author : Anton
22 | // {_.-``-' {_/ Assembly: 1.0.0.0
23 | // Copyright © 2005-2008, Rogue Trader/MWM
24 | // Project Item Name: RTFBuilder.RTFParaWrap.cs - Code
25 | // Purpose: Wraps RtfBuilderbase injecting appropriate rtf codes after paragraph append
26 | // ----------------------------------------------------------------------------------------
27 | ///
28 | /// Wraps RtfBuilderbase injecting appropriate rtf codes after paragraph append
29 | ///
30 | private class RTFParaWrap : IDisposable
31 | {
32 | #region Fields
33 |
34 | private readonly RTFBuilder _builder;
35 |
36 | #endregion
37 |
38 | #region Constructor
39 |
40 | public RTFParaWrap(RTFBuilder builder)
41 | {
42 | this._builder = builder;
43 | int len = this._builder._sb.Length;
44 | if (this._builder._sf.Alignment == StringAlignment.Center)
45 | {
46 | this._builder._sb.Append("\\qc");
47 | }
48 | else if (this._builder._sf.Alignment == StringAlignment.Far)
49 | {
50 | this._builder._sb.Append("\\qr");
51 | }
52 | if (this._builder._firstLineIndent > 0)
53 | {
54 | this._builder._sb.Append("\\fi" + this._builder._firstLineIndent);
55 | }
56 | if (this._builder._lineIndent > 0)
57 | {
58 | this._builder._sb.Append("\\li" + this._builder._lineIndent);
59 | }
60 |
61 |
62 | if (this._builder._sb.Length > len)
63 | {
64 | this._builder._sb.Append(" ");
65 | }
66 | }
67 |
68 | #endregion
69 |
70 | #region Override Methods
71 |
72 | ~RTFParaWrap()
73 | {
74 | this.Dispose(false);
75 | }
76 |
77 | #endregion
78 |
79 | #region Methods
80 |
81 | protected void Dispose(bool disposing)
82 | {
83 | if ( this._builder != null && !this._builder._unwrapped)
84 | {
85 | if (this._builder._sf.Alignment != StringAlignment.Near || this._builder._lineIndent > 0 || this._builder._firstLineIndent > 0)
86 | {
87 | this._builder._firstLineIndent = 0;
88 | this._builder._lineIndent = 0;
89 | this._builder._sf.Alignment = StringAlignment.Near;
90 | this._builder._sb.Append("\\pard ");
91 | }
92 | }
93 | if (disposing)
94 | {
95 | GC.SuppressFinalize(this);
96 | }
97 | }
98 |
99 | #endregion
100 |
101 | #region IDisposable Members
102 |
103 | public void Dispose()
104 | {
105 | this.Dispose(true);
106 | }
107 |
108 | #endregion
109 | }
110 |
111 | #endregion
112 | }
113 | }
114 |
115 |
116 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFCell.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | namespace RTF
5 | {
6 | using System;
7 |
8 | public partial class RTFBuilder
9 | {
10 | #region Nested type: RTFCell
11 |
12 | // ----------------------------------------------------------------------------------------
13 | // _ ___ _..-._ Date: 12/11/08 23:46
14 | // \`.|\..----...-'` `-._.-'' _.-..'
15 | // / ' ` , __.-''
16 | // )/` _/ \ `-_, / Solution: RTFLib
17 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
18 | // _.-'_./ {_.' ; / Author : Anton
19 | // {_.-``-' {_/ Assembly: 1.0.0.0
20 | // Copyright © 2005-2008, Rogue Trader/MWM
21 | // Project Item Name: RTFCell.cs - Code
22 | // Purpose: Cell In Table Row
23 | // ----------------------------------------------------------------------------------------
24 | ///
25 | /// Cell In Table Row
26 | ///
27 | public class RTFCell : IBuilderContent
28 | {
29 | #region Fields
30 |
31 | private RTFBuilder _builder;
32 | private RTFCellDefinition _cellDefinition;
33 | private bool _firstAccessContent;
34 |
35 | #endregion
36 |
37 | #region Constructor
38 |
39 | public RTFCell(RTFBuilder builder, RTFCellDefinition cellDefinition)
40 | {
41 | this._builder = builder;
42 | this._cellDefinition = cellDefinition;
43 | this._firstAccessContent = true;
44 | }
45 |
46 | #endregion
47 |
48 | #region Override Methods
49 |
50 | ~RTFCell()
51 | {
52 | this.Dispose(false);
53 | }
54 |
55 | #endregion
56 |
57 | #region Methods
58 |
59 | protected void Dispose(bool disposing)
60 | {
61 | if (disposing && this._builder != null)
62 | {
63 | this._builder._sb.AppendLine("\\cell ");
64 | }
65 | this._builder = null;
66 | if (disposing)
67 | {
68 | GC.SuppressFinalize(this);
69 | }
70 | }
71 |
72 | #endregion
73 |
74 | #region IBuilderContent Members
75 |
76 | public void Dispose()
77 | {
78 | this.Dispose(true);
79 | }
80 |
81 | public RTFBuilderbase Content
82 | {
83 | get
84 | {
85 | if (this._firstAccessContent)
86 | {
87 | //par in table
88 | switch (this._cellDefinition.Alignment)
89 | {
90 | case RTFAlignment.TopCenter:
91 | case RTFAlignment.BottomCenter:
92 | case RTFAlignment.MiddleCenter:
93 | this._builder._sb.Append("\\qc ");
94 | break;
95 | case RTFAlignment.TopLeft:
96 | case RTFAlignment.MiddleLeft:
97 | case RTFAlignment.BottomLeft:
98 | this._builder._sb.Append("\\ql ");
99 | break;
100 | case RTFAlignment.TopRight:
101 | case RTFAlignment.BottomRight:
102 | case RTFAlignment.MiddleRight:
103 | this._builder._sb.Append("\\qr ");
104 | break;
105 | }
106 | this._firstAccessContent = false;
107 | }
108 | return this._builder;
109 | }
110 | }
111 |
112 | #endregion
113 | }
114 |
115 | #endregion
116 | }
117 | }
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/google_unofficial/GoogleTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Web;
8 | using ACT.FoxCommon.localization;
9 | using Newtonsoft.Json.Linq;
10 |
11 | namespace ACT.FFXIVTranslate.translate.google_unofficial
12 | {
13 | internal class GoogleTranslateProvider : DefaultTranslateProvider
14 | {
15 | private const int MaxContentLength = 2048 - 50;
16 |
17 | private readonly string _langFrom;
18 | private readonly string _langTo;
19 |
20 | public GoogleTranslateProvider(LanguageDef src, LanguageDef dst)
21 | {
22 | _langFrom = src?.LangCode ?? "auto";
23 | _langTo = dst.LangCode;
24 | }
25 |
26 | public override void Translate(List chattingLines)
27 | {
28 | try
29 | {
30 | var current = 0;
31 | while (current < chattingLines.Count)
32 | {
33 | var start = current;
34 |
35 | if (start > 0)
36 | {
37 | // Second call, make a short delay so google might like us :)
38 | Thread.Sleep(500);
39 | }
40 |
41 | // Build text
42 | var vaildText = string.Empty;
43 | var textBuilder = new StringBuilder();
44 | for (current = start; current < chattingLines.Count; current++)
45 | {
46 | if (textBuilder.Length > 0)
47 | {
48 | textBuilder.Append('\n');
49 | }
50 | textBuilder.Append(chattingLines[current].CleanedContent);
51 | var newText = HttpUtility.UrlEncode(textBuilder.ToString(), Encoding.UTF8);
52 | if (newText.Length > MaxContentLength)
53 | {
54 | break;
55 | }
56 | vaildText = newText;
57 | }
58 | if (current == start)
59 | {
60 | // The single line exceeds the limit, skip
61 | chattingLines[current].TranslatedContent = "Content too long for translating.";
62 | current++;
63 | continue;
64 | }
65 |
66 | // Send request
67 | var url =
68 | $"https://translate.googleapis.com/translate_a/single?client=gtx&sl={_langFrom}&tl={_langTo}&dt=t&ie=UTF-8&oe=UTF-8&q={vaildText}";
69 | string responseBody;
70 | using (var client = ProxyFactory.Instance.NewClient())
71 | using (var request = new HttpRequestMessage())
72 | {
73 | request.Method = HttpMethod.Get;
74 | request.RequestUri = new Uri(url);
75 | var response = client.SendAsync(request).Result;
76 | response.EnsureSuccessStatusCode();
77 | responseBody = response.Content.ReadAsStringAsync().Result;
78 | }
79 | // Parse result json
80 | var results = (JArray) JArray.Parse(responseBody)[0];
81 | var full = string.Join(string.Empty, results.Select(it => (string) it[0]));
82 | var finalResults = full.Split('\n');
83 | if (finalResults.Length >= current - start)
84 | {
85 | for (var i = start; i < current; i++)
86 | {
87 | chattingLines[i].TranslatedContent = finalResults[i - start];
88 | }
89 | }
90 | else
91 | {
92 | // TODO: Oops!
93 | }
94 | }
95 | }
96 | catch (TranslateException)
97 | {
98 | throw;
99 | }
100 | catch (Exception ex)
101 | {
102 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFRowDefinition.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System.Diagnostics;
9 | using System.Drawing;
10 | using System.Windows.Forms;
11 |
12 | ///
13 | ///
14 | ///
15 | // ----------------------------------------------------------------------------------------
16 | // _ ___ _..-._ Date: 12/11/08 23:49
17 | // \`.|\..----...-'` `-._.-'' _.-..'
18 | // / ' ` , __.-''
19 | // )/` _/ \ `-_, / Solution: RTFLib
20 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
21 | // _.-'_./ {_.' ; / Author : Anton
22 | // {_.-``-' {_/ Assembly: 1.0.0.0
23 | // Copyright © 2005-2008, Rogue Trader/MWM
24 | // Project Item Name: RTFRowDefinition.cs - Code
25 | // Purpose: Definition of Rich Table Row
26 | // ----------------------------------------------------------------------------------------
27 | ///
28 | /// Definition of Rich Table Row
29 | ///
30 | public struct RTFRowDefinition
31 | {
32 | #region Fields
33 |
34 | private readonly RTFAlignment _alignment;
35 | private readonly Color _borderColor;
36 | private readonly int _borderWidth;
37 | private readonly Padding _padding;
38 | private readonly RTFBorderSide _rTFBorderSide;
39 | private int _rowWidth;
40 |
41 | #endregion
42 |
43 | #region Constructor
44 |
45 | ///
46 | /// Initializes a new instance of the struct.
47 | ///
48 | /// Width of the row.
49 | /// The alignment.
50 | /// The RTFBorderSide.
51 | /// Width of the border.
52 | /// Color of the border.
53 | public RTFRowDefinition(int rowWidth, RTFAlignment alignment, RTFBorderSide rTFBorderSide, int borderWidth, Color borderColor, Padding padding)
54 | {
55 | this._padding = padding;
56 | this._alignment = alignment;
57 | this._rTFBorderSide = rTFBorderSide;
58 | this._borderWidth = borderWidth;
59 | this._borderColor = borderColor;
60 | this._rowWidth = rowWidth * RTFBuilder.TWIPSA4 / 100;
61 | }
62 |
63 | #endregion
64 |
65 | #region Public Properties
66 |
67 | ///
68 | /// Gets the alignment.
69 | ///
70 | /// The alignment.
71 | public RTFAlignment Alignment
72 | {
73 | [DebuggerStepThrough]
74 | get { return this._alignment; }
75 | }
76 |
77 | public Padding Padding
78 | {
79 | [DebuggerStepThrough]
80 | get { return this._padding; }
81 | }
82 |
83 | ///
84 | /// Gets the RTF border side.
85 | ///
86 | /// The RTF border side.
87 | public RTFBorderSide RTFBorderSide
88 | {
89 | [DebuggerStepThrough]
90 | get { return this._rTFBorderSide; }
91 | }
92 |
93 | ///
94 | /// Gets the width of the border.
95 | ///
96 | /// The width of the border.
97 | public int BorderWidth
98 | {
99 | [DebuggerStepThrough]
100 | get { return this._borderWidth; }
101 | }
102 |
103 | ///
104 | /// Gets the color of the border.
105 | ///
106 | /// The color of the border.
107 | public Color BorderColor
108 | {
109 | [DebuggerStepThrough]
110 | get { return this._borderColor; }
111 | }
112 |
113 | ///
114 | /// Gets or sets the width of the cell.
115 | ///
116 | /// The width of the cell.
117 | public int RowWidth
118 | {
119 | [DebuggerStepThrough]
120 | get { return this._rowWidth; }
121 | [DebuggerStepThrough]
122 | set { this._rowWidth = value; }
123 | }
124 |
125 | #endregion
126 | }
127 | }
128 |
129 |
130 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/WindowsMessagePump.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using System.Windows.Forms;
4 | using ACT.FoxCommon;
5 |
6 | namespace ACT.FFXIVTranslate
7 | {
8 | class WindowsMessagePump : WindowsMessagePumpBase
9 | {
10 |
11 | private MessageOnlyWindow _window;
12 |
13 | public override void AttachToAct(FFXIVTranslatePlugin plugin)
14 | {
15 | base.AttachToAct(plugin);
16 |
17 | _window = new MessageOnlyWindow(plugin);
18 |
19 | Controller.ChannelFilterChanged += ControllerOnChannelFilterChanged;
20 | }
21 |
22 | public override void Dispose()
23 | {
24 | Controller.ChannelFilterChanged -= ControllerOnChannelFilterChanged;
25 |
26 | _window?.Dispose();
27 | _window = null;
28 |
29 | base.Dispose();
30 | }
31 |
32 | private void ControllerOnChannelFilterChanged(bool fromView, EventCode code, bool show)
33 | {
34 | if (code != EventCode.Clipboard)
35 | {
36 | return;
37 | }
38 |
39 | _window.EnableClipboardMonitor(show);
40 | }
41 | }
42 |
43 | sealed class MessageOnlyWindow : NativeWindow, IDisposable
44 | {
45 |
46 | // Only works on VISTA+, but since we use .net 4.5, so it's guaranteed to work
47 | [DllImport("user32.dll", SetLastError = true)]
48 | private static extern bool AddClipboardFormatListener(IntPtr hwnd);
49 |
50 | [DllImport("user32.dll", SetLastError = true)]
51 | private static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
52 |
53 | [DllImport("user32.dll", CharSet = CharSet.Auto)]
54 | public static extern bool PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
55 |
56 | private const int WM_CLIPBOARDUPDATE = 0x031D;
57 |
58 | private const int WM_USER = 0x0400;
59 | private const int WM_USER_POSTCLIPBOARDUPDATE = WM_USER + 1;
60 |
61 | private readonly FFXIVTranslatePlugin _plugin;
62 |
63 | private bool _clipboardEnabled = false;
64 |
65 | public MessageOnlyWindow(FFXIVTranslatePlugin plugin)
66 | {
67 | _plugin = plugin;
68 |
69 | var cp = new CreateParams();
70 | var HWND_MESSAGE = new IntPtr(-3);
71 | cp.Parent = HWND_MESSAGE;
72 | CreateHandle(cp);
73 | }
74 |
75 | protected override void WndProc(ref Message m)
76 | {
77 | switch (m.Msg)
78 | {
79 | case WM_CLIPBOARDUPDATE:
80 | PostMessage(Handle, WM_USER_POSTCLIPBOARDUPDATE, IntPtr.Zero, IntPtr.Zero);
81 | m.Result = IntPtr.Zero;
82 | break;
83 | case WM_USER_POSTCLIPBOARDUPDATE:
84 | var text = Clipboard.GetText(TextDataFormat.UnicodeText);
85 | if (!string.IsNullOrWhiteSpace(text))
86 | {
87 | _plugin.Controller.NotifyClipboardContentChanged(false, text);
88 | // _plugin.Controller.NotifyLogMessageAppend(false, $"Clipboard: {text}\n");
89 | }
90 | break;
91 | default:
92 | base.WndProc(ref m);
93 | break;
94 | }
95 | }
96 |
97 | public void Dispose()
98 | {
99 | EnableClipboardMonitor(false);
100 | DestroyHandle();
101 | }
102 |
103 | public void EnableClipboardMonitor(bool enable)
104 | {
105 | if (_clipboardEnabled == enable)
106 | {
107 | return;
108 | }
109 |
110 | if (enable)
111 | {
112 | if (!AddClipboardFormatListener(Handle))
113 | {
114 | _plugin.Controller.NotifyLogMessageAppend(false, "AddClipboardFormatListener() failed! \n");
115 | return;
116 | }
117 | }
118 | else
119 | {
120 | if (!RemoveClipboardFormatListener(Handle))
121 | {
122 | _plugin.Controller.NotifyLogMessageAppend(false, "RemoveClipboardFormatListener() failed! \n");
123 | return;
124 | }
125 | }
126 |
127 | _clipboardEnabled = enable;
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFCellDefinition.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System.Diagnostics;
9 | using System.Drawing;
10 | using System.Windows.Forms;
11 |
12 | // ----------------------------------------------------------------------------------------
13 | // _ ___ _..-._ Date: 12/11/08 23:47
14 | // \`.|\..----...-'` `-._.-'' _.-..'
15 | // / ' ` , __.-''
16 | // )/` _/ \ `-_, / Solution: RTFLib
17 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
18 | // _.-'_./ {_.' ; / Author : Anton
19 | // {_.-``-' {_/ Assembly: 1.0.0.0
20 | // Copyright © 2005-2008, Rogue Trader/MWM
21 | // Project Item Name: RTFCellDefinition.cs - Code
22 | // Purpose: Definition Of Cell In Table Row
23 | // ----------------------------------------------------------------------------------------
24 | ///
25 | /// Definition Of Cell In Table Row
26 | ///
27 | public struct RTFCellDefinition
28 | {
29 | #region Fields
30 |
31 | private RTFAlignment _alignment;
32 | private Color _borderColor;
33 | private int _borderWidth;
34 | private float _cellWidth;
35 | private Padding _padding;
36 | private RTFBorderSide _rTFBorderSide;
37 |
38 | private int _x;
39 |
40 | #endregion
41 |
42 | #region Constructor
43 |
44 | public RTFCellDefinition(int cellwidth, RTFAlignment alignment, RTFBorderSide rTFBorderSide, int borderWidth, Color borderColor, Padding padding)
45 | {
46 | this._x = 0;
47 | this._padding = padding;
48 | this._alignment = alignment;
49 | this._rTFBorderSide = rTFBorderSide;
50 | this._borderWidth = borderWidth;
51 | this._borderColor = borderColor;
52 | this._cellWidth = (float) cellwidth / 100;
53 | }
54 |
55 | #endregion
56 |
57 | #region Public Properties
58 |
59 | ///
60 | /// Gets the alignment.
61 | ///
62 | /// The alignment.
63 | public RTFAlignment Alignment
64 | {
65 | [DebuggerStepThrough]
66 | get { return this._alignment; }
67 | [DebuggerStepThrough]
68 | set { this._alignment = value; }
69 | }
70 |
71 | ///
72 | /// Gets the RTFborderside.
73 | ///
74 | /// The RTF border side.
75 | public RTFBorderSide RTFBorderSide
76 | {
77 | [DebuggerStepThrough]
78 | get { return this._rTFBorderSide; }
79 | [DebuggerStepThrough]
80 | set { this._rTFBorderSide = value; }
81 | }
82 |
83 | ///
84 | /// Gets the width of the border.
85 | ///
86 | /// The width of the border.
87 | public int BorderWidth
88 | {
89 | [DebuggerStepThrough]
90 | get { return this._borderWidth; }
91 | [DebuggerStepThrough]
92 | set { this._borderWidth = value; }
93 | }
94 |
95 | ///
96 | /// Gets the color of the border.
97 | ///
98 | /// The color of the border.
99 | public Color BorderColor
100 | {
101 | [DebuggerStepThrough]
102 | get { return this._borderColor; }
103 | [DebuggerStepThrough]
104 | set { this._borderColor = value; }
105 | }
106 |
107 | ///
108 | /// Gets or sets the width of the cell.
109 | ///
110 | /// The width of the cell.
111 | public float CellWidthRaw
112 | {
113 | [DebuggerStepThrough]
114 | get { return this._cellWidth; }
115 | [DebuggerStepThrough]
116 | set { this._cellWidth = value; }
117 | }
118 |
119 | ///
120 | /// Gets the X.
121 | ///
122 | /// The X.
123 | public int X
124 | {
125 | [DebuggerStepThrough]
126 | get { return this._x; }
127 | }
128 |
129 | public Padding Padding
130 | {
131 | [DebuggerStepThrough]
132 | get { return this._padding; }
133 | [DebuggerStepThrough]
134 | set { this._padding = value; }
135 | }
136 |
137 | #endregion
138 |
139 | #region Public Methods
140 |
141 | [DebuggerStepThrough]
142 | public void SetX(int value)
143 | {
144 | this._x = value;
145 | }
146 |
147 | #endregion
148 | }
149 | }
150 |
151 |
152 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate.Test/ACT.FFXIVTranslate.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {81906072-43FD-40D0-916A-F16D0EDA15BA}
8 | Library
9 | Properties
10 | ACT.FFXIVTranslate.Test
11 | ACT.FFXIVTranslate.Test
12 | v4.5.2
13 | 512
14 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 15.0
16 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
17 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
18 | False
19 | UnitTest
20 |
21 |
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\Debug\
28 | DEBUG;TRACE
29 | prompt
30 | 4
31 |
32 |
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 |
40 |
41 |
42 | ..\packages\MSTest.TestFramework.1.1.11\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
43 |
44 |
45 | ..\packages\MSTest.TestFramework.1.1.11\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | {7263a6d5-a142-4f3f-92a7-c3dfa9ba45b9}
68 | ACT.FFXIVTranslate
69 |
70 |
71 |
72 |
73 |
74 |
75 | 此项目引用这台计算机上缺少的 NuGet 程序包。使用 NuGet 程序包还原可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBuilder.RTFFonts.cs:
--------------------------------------------------------------------------------
1 | namespace RTF
2 | {
3 | using System;
4 |
5 | partial class RTFBuilder
6 | {
7 | #region Nested type: RawFonts
8 |
9 |
10 | // ----------------------------------------------------------------------------------------
11 | // _ ___ _..-._ Date: 01/11/08 21:15
12 | // \`.|\..----...-'` `-._.-'' _.-..'
13 | // / ' ` , __.-''
14 | // )/` _/ \ `-_, / Solution: RTFLib
15 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
16 | // _.-'_./ {_.' ; / Author : Anton
17 | // {_.-``-' {_/ Assembly: 1.3.0.2499
18 | // Copyright © 2005-2008, Rogue Trader
19 | // Project Item Name: RTFBuilder.RTFFonts.cs - [PROJECT_ITEM_KIND]
20 | // Purpose: Used internally by RtfBuilderBase
21 | // ----------------------------------------------------------------------------------------
22 |
23 |
24 | internal static class RawFonts
25 | {
26 | #region Fields
27 |
28 | public const string Arial = @"{{\f{0}\fswiss\fprq2\fcharset0 Arial;}}";
29 | public const string ArialBlack = @"{{\f{0}\fswiss\fprq2\fcharset0 Arial Black;}}";
30 | public const string BookmanOldStyle = @"{{\f{0}\froman\fprq2\fcharset0 Bookman Old Style;}}";
31 | public const string Broadway = @"{{\f{0}\fdecor\fprq2\fcharset0 Broadway;}}";
32 | public const string CenturyGothic = @"{{\f{0}\fswiss\fprq2\fcharset0 Century Gothic;}}";
33 | public const string Consolas = @"{{\f{0}\fmodern\fprq1\fcharset0 Consolas;}}";
34 | public const string CordiaNew = @"{{\f{0}\fswiss\fprq2\fcharset0 Cordia New;}}";
35 | public const string CourierNew = @"{{\f{0}\fmodern\fprq1\fcharset0 Courier New;}}";
36 | public const string FontTimesNewRoman = @"{{\f{0}\froman\fcharset0 Times New Roman;}}";
37 | public const string Garamond = @"{{\f{0}\froman\fprq2\fcharset0 Garamond;}}";
38 | public const string Georgia = @"{{\f{0}\froman\fprq2\fcharset0 Georgia;}}";
39 | public const string Impact = @"{{\f{0}\fswiss\fprq2\fcharset0 Impact;}}";
40 | public const string LucidaConsole = @"{{\f{0}\fmodern\fprq1\fcharset0 Lucida Console;}}";
41 | public const string MSSansSerif = "{{\f{0}\fswiss\fprq2\fcharset0 MS Reference Sans Serif;}}";
42 | public const string Symbol = @"{{\f{0}\ftech\fcharset0 Symbol;}}";
43 | public const string WingDings = "{{\f{0}\fnil\fprq2\fcharset2 Wingdings;}}";
44 |
45 | #endregion
46 |
47 | #region Static Methods
48 |
49 | public static string GetKnownFontstring(RTFFont font)
50 | {
51 | string value = string.Empty;
52 | switch (font)
53 | {
54 | case RTFFont.Arial:
55 | value = Arial;
56 | break;
57 | case RTFFont.ArialBlack:
58 | value = ArialBlack;
59 | break;
60 | case RTFFont.BookmanOldStyle:
61 | value = BookmanOldStyle;
62 | break;
63 | case RTFFont.Broadway:
64 | value = Broadway;
65 | break;
66 | case RTFFont.CenturyGothic:
67 | value = CenturyGothic;
68 | break;
69 | case RTFFont.Consolas:
70 | value = Consolas;
71 | break;
72 | case RTFFont.CordiaNew:
73 | value = CordiaNew;
74 | break;
75 | case RTFFont.CourierNew:
76 | value = CourierNew;
77 | break;
78 | case RTFFont.FontTimesNewRoman:
79 | value = FontTimesNewRoman;
80 | break;
81 | case RTFFont.Garamond:
82 | value = Garamond;
83 | break;
84 | case RTFFont.Georgia:
85 | value = Georgia;
86 | break;
87 | case RTFFont.Impact:
88 | value = Impact;
89 | break;
90 | case RTFFont.LucidaConsole:
91 | value = LucidaConsole;
92 | break;
93 | case RTFFont.Symbol:
94 | value = Symbol;
95 | break;
96 | case RTFFont.WingDings:
97 | value = WingDings;
98 | break;
99 | case RTFFont.MSSansSerif:
100 | value = MSSansSerif;
101 | break;
102 | default:
103 | throw new ArgumentOutOfRangeException("font");
104 | }
105 | return value;
106 | }
107 |
108 | #endregion
109 | }
110 |
111 | #endregion
112 | }
113 | }
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/microsoft/AzureAuthToken.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Http;
4 |
5 | namespace ACT.FFXIVTranslate.translate.microsoft
6 | {
7 | ///
8 | /// Client to call Cognitive Services Azure Auth Token service in order to get an access token.
9 | /// Exposes asynchronous as well as synchronous methods.
10 | ///
11 | public class AzureAuthToken
12 | {
13 | /// URL of the token service
14 | private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");
15 |
16 | /// Name of header used to pass the subscription key to the token service
17 | private const string OcpApimSubscriptionKeyHeader = "Ocp-Apim-Subscription-Key";
18 |
19 | /// After obtaining a valid token, this class will cache it for this duration.
20 | /// Use a duration of 5 minutes, which is less than the actual token lifetime of 10 minutes.
21 | private static readonly TimeSpan TokenCacheDuration = new TimeSpan(0, 5, 0);
22 |
23 | /// Cache the value of the last valid token obtained from the token service.
24 | private string _storedTokenValue = string.Empty;
25 |
26 | /// When the last valid token was obtained.
27 | private DateTime _storedTokenTime = DateTime.MinValue;
28 |
29 | /// Gets the subscription key.
30 | public string SubscriptionKey { get; }
31 |
32 | /// Gets the HTTP status code for the most recent request to the token service.
33 | public HttpStatusCode RequestStatusCode { get; private set; }
34 |
35 | ///
36 | /// Creates a client to obtain an access token.
37 | ///
38 | /// Subscription key to use to get an authentication token.
39 | public AzureAuthToken(string key)
40 | {
41 | if (string.IsNullOrEmpty(key))
42 | {
43 | throw new ArgumentNullException(nameof(key), "A subscription key is required");
44 | }
45 |
46 | this.SubscriptionKey = key;
47 | this.RequestStatusCode = HttpStatusCode.InternalServerError;
48 | }
49 |
50 | ///
51 | /// Gets a token for the specified subscription.
52 | ///
53 | /// The encoded JWT token prefixed with the string "Bearer ".
54 | ///
55 | /// This method uses a cache to limit the number of request to the token service.
56 | /// A fresh token can be re-used during its lifetime of 10 minutes. After a successful
57 | /// request to the token service, this method caches the access token. Subsequent
58 | /// invocations of the method return the cached token for the next 5 minutes. After
59 | /// 5 minutes, a new token is fetched from the token service and the cache is updated.
60 | ///
61 | public string GetAccessToken()
62 | {
63 | if (string.IsNullOrWhiteSpace(this.SubscriptionKey))
64 | {
65 | return string.Empty;
66 | }
67 |
68 | // Re-use the cached token if there is one.
69 | if ((DateTime.Now - _storedTokenTime) < TokenCacheDuration)
70 | {
71 | return _storedTokenValue;
72 | }
73 |
74 | using (var client = ProxyFactory.Instance.NewClient())
75 | using (var request = new HttpRequestMessage())
76 | {
77 | request.Method = HttpMethod.Post;
78 | request.RequestUri = ServiceUrl;
79 | request.Content = new StringContent(string.Empty);
80 | request.Headers.TryAddWithoutValidation(OcpApimSubscriptionKeyHeader, this.SubscriptionKey);
81 | client.Timeout = TimeSpan.FromSeconds(2);
82 | var response = client.SendAsync(request).Result;
83 | this.RequestStatusCode = response.StatusCode;
84 | response.EnsureSuccessStatusCode();
85 | var token = response.Content.ReadAsStringAsync().Result;
86 | _storedTokenTime = DateTime.Now;
87 | _storedTokenValue = "Bearer " + token;
88 | return _storedTokenValue;
89 | }
90 | }
91 |
92 | // ///
93 | // /// Gets a token for the specified subscription. Synchronous version.
94 | // /// Use of async version preferred
95 | // ///
96 | // /// The encoded JWT token prefixed with the string "Bearer ".
97 | // ///
98 | // /// This method uses a cache to limit the number of request to the token service.
99 | // /// A fresh token can be re-used during its lifetime of 10 minutes. After a successful
100 | // /// request to the token service, this method caches the access token. Subsequent
101 | // /// invocations of the method return the cached token for the next 5 minutes. After
102 | // /// 5 minutes, a new token is fetched from the token service and the cache is updated.
103 | // ///
104 | // public string GetAccessToken()
105 | // {
106 | // // Re-use the cached token if there is one.
107 | // if ((DateTime.Now - _storedTokenTime) < TokenCacheDuration)
108 | // {
109 | // return _storedTokenValue;
110 | // }
111 | //
112 | // string accessToken = null;
113 | // var task = Task.Factory.StartNew(async () =>
114 | // {
115 | // accessToken = this.GetAccessTokenAsync().Result;
116 | // });
117 | //
118 | // while (!task.IsCompleted)
119 | // {
120 | // System.Threading.Thread.Yield();
121 | // }
122 | // if (task.IsFaulted)
123 | // {
124 | // throw task.Exception;
125 | // }
126 | // if (task.IsCanceled)
127 | // {
128 | // throw new Exception("Timeout obtaining access token.");
129 | // }
130 | // return accessToken;
131 | // }
132 |
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/microsoft/MicrosoftTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Net.Http;
5 | using System.Text;
6 | using ACT.FoxCommon.localization;
7 | using Newtonsoft.Json;
8 |
9 | namespace ACT.FFXIVTranslate.translate.microsoft
10 | {
11 | internal class RequestItem
12 | {
13 | public readonly string Text;
14 |
15 | public RequestItem(string text)
16 | {
17 | Text = text;
18 | }
19 | }
20 |
21 | internal class ResponseItem
22 | {
23 | internal class TranslationItem
24 | {
25 | public string text;
26 | }
27 |
28 | public List translations;
29 | }
30 |
31 | internal class MicrosoftTranslateProvider : DefaultTranslateProvider
32 | {
33 | private readonly AzureAuthToken _token;
34 | private readonly string _langFrom;
35 | private readonly string _langTo;
36 |
37 |
38 | public MicrosoftTranslateProvider(string apiKey, LanguageDef src, LanguageDef dst)
39 | {
40 | _token = new AzureAuthToken(apiKey);
41 | _langFrom = src?.LangCode;
42 | _langTo = dst.LangCode;
43 | }
44 |
45 | private const string ServiceUri = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0";
46 |
47 | public override void Translate(List chattingLines)
48 | {
49 | try
50 | {
51 | // Build text
52 | var uri = $"{ServiceUri}&from={_langFrom}&to={_langTo}";
53 | Console.WriteLine("Uri is: {0}.", uri);
54 |
55 | var bodyContent = new List();
56 | foreach (var line in chattingLines)
57 | {
58 | bodyContent.Add(new RequestItem(line.CleanedContent));
59 | }
60 | var requestBody = JsonConvert.SerializeObject(bodyContent, Formatting.None);
61 | Console.WriteLine("Request body is: {0}.", requestBody);
62 |
63 | // Call Microsoft translate API.
64 | DoRequest(GetAuthToken(), uri, requestBody, out string responseBody, out HttpStatusCode statusCode);
65 |
66 | // Parse result
67 | switch (statusCode)
68 | {
69 | case HttpStatusCode.OK:
70 | Console.WriteLine("Request status is OK. Response body is:");
71 | Console.WriteLine(responseBody);
72 | Console.WriteLine("Result of translate array method is:");
73 |
74 | var response = JsonConvert.DeserializeObject>(responseBody);
75 | var sourceTextCounter = 0;
76 | foreach (var line in response)
77 | {
78 | var result = line.translations[0].text;
79 | Console.WriteLine("\n\nSource text: {0}\nTranslated Text: {1}", chattingLines[sourceTextCounter].RawContent, result);
80 | chattingLines[sourceTextCounter].TranslatedContent = result;
81 | sourceTextCounter++;
82 | }
83 | break;
84 | case HttpStatusCode.Unauthorized:
85 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
86 | "Invalid API key",
87 | null);
88 | default:
89 | Console.WriteLine("Request status code is: {0}.", statusCode);
90 | Console.WriteLine("Request error message: {0}.", responseBody);
91 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
92 | responseBody, null);
93 | }
94 | }
95 | catch (TranslateException)
96 | {
97 | throw;
98 | }
99 | catch (Exception ex)
100 | {
101 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
102 | }
103 | }
104 |
105 | private string GetAuthToken()
106 | {
107 | string authToken;
108 | try
109 | {
110 | authToken = _token.GetAccessToken();
111 | }
112 | catch (HttpRequestException ex)
113 | {
114 | switch (_token.RequestStatusCode)
115 | {
116 | case HttpStatusCode.Unauthorized:
117 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
118 | "Invalid API key",
119 | null);
120 | case HttpStatusCode.Forbidden:
121 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
122 | "Account quota has been exceeded.",
123 | null);
124 | default:
125 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
126 | null, ex);
127 | }
128 | }
129 |
130 | return authToken;
131 | }
132 |
133 | private void DoRequest(string authToken, string uri, string requestBody,
134 | out string responseBody, out HttpStatusCode statusCode)
135 | {
136 | string _responseBody;
137 | HttpStatusCode _statusCode;
138 |
139 | ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
140 |
141 | using (var client = ProxyFactory.Instance.NewClient())
142 | using (var request = new HttpRequestMessage())
143 | {
144 | request.Method = HttpMethod.Post;
145 | request.RequestUri = new Uri(uri);
146 | request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
147 | request.Headers.Add("Authorization", authToken);
148 | var response = client.SendAsync(request).Result;
149 | _responseBody = response.Content.ReadAsStringAsync().Result;
150 | _statusCode = response.StatusCode;
151 | }
152 |
153 | responseBody = _responseBody;
154 | statusCode = _statusCode;
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/youdao/YoudaoTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using ACT.FoxCommon;
8 | using ACT.FoxCommon.localization;
9 | using Newtonsoft.Json.Linq;
10 |
11 | namespace ACT.FFXIVTranslate.translate.youdao
12 | {
13 | internal class YoudaoTranslateProvider : DefaultTranslateProvider
14 | {
15 | private readonly string _appKey;
16 | private readonly string _secret;
17 | private readonly string _langFrom;
18 | private readonly string _langTo;
19 |
20 |
21 | public YoudaoTranslateProvider(string apiKey, LanguageDef src, LanguageDef dst)
22 | {
23 | var kp = apiKey.Split(':');
24 | if (kp.Length < 2)
25 | {
26 | _appKey = "";
27 | _secret = "";
28 | }
29 | else
30 | {
31 | _appKey = kp[0];
32 | _secret = kp[1];
33 | }
34 | _langFrom = src?.LangCode ?? "auto";
35 | _langTo = dst.LangCode;
36 | }
37 |
38 | public override void Translate(List chattingLines)
39 | {
40 | try
41 | {
42 | // Build text
43 | var query = string.Join("\n", chattingLines.Select(it => it.CleanedContent));
44 |
45 | // 1. Generate a salt
46 | var salt = Utils.TimestampMillisFromDateTime(DateTime.Now).ToString();
47 | // 2. Calculate sign
48 | var md5Input = Encoding.UTF8.GetBytes($"{_appKey}{query}{salt}{_secret}");
49 | var md5 = System.Security.Cryptography.MD5.Create();
50 | var hash = md5.ComputeHash(md5Input);
51 | var sign = string.Join("", hash.Select(it => it.ToString("x2")));
52 |
53 | string textResponse;
54 | using (var client = ProxyFactory.Instance.NewClient())
55 | using (var request = new HttpRequestMessage(HttpMethod.Post, "/api"))
56 | {
57 | client.BaseAddress = new Uri("https://openapi.youdao.com");
58 |
59 | var keyValues = new List>();
60 | keyValues.Add(new KeyValuePair("q", query));
61 | keyValues.Add(new KeyValuePair("from", _langFrom));
62 | keyValues.Add(new KeyValuePair("to", _langTo));
63 | keyValues.Add(new KeyValuePair("appKey", _appKey));
64 | keyValues.Add(new KeyValuePair("salt", salt));
65 | keyValues.Add(new KeyValuePair("sign", sign));
66 |
67 | request.Content = new FormUrlEncodedContent(keyValues);
68 | var response = client.SendAsync(request).Result;
69 | response.EnsureSuccessStatusCode();
70 | textResponse = response.Content.ReadAsStringAsync().Result;
71 | Debug.WriteLine(textResponse);
72 | }
73 |
74 | // read json
75 | var result = JObject.Parse(textResponse);
76 | var errorCode = (string) result["errorCode"];
77 | switch (errorCode)
78 | {
79 | case "0": // This one is good
80 | break;
81 | case "102":
82 | throw new TranslateException(TranslateException.ExceptionReason.DirectionNotSupported,
83 | "Language Not Supported", null);
84 | case "103":
85 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
86 | "Query Content Too Long", null);
87 | case "101":
88 | case "104":
89 | case "105":
90 | case "106":
91 | case "107":
92 | case "109":
93 | case "110":
94 | case "201":
95 | throw new TranslateException(TranslateException.ExceptionReason.InternalError,
96 | $"Error {errorCode}.", null);
97 | case "108":
98 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
99 | "AppId Error", null);
100 | case "111":
101 | case "401":
102 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
103 | "Insufficient Account Balance", null);
104 | case "202":
105 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
106 | "Secret Error", null);
107 | case "203":
108 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
109 | "Limited IP",
110 | null);
111 |
112 | case "301":
113 | case "302":
114 | case "303":
115 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
116 | $"Error {errorCode}.", null);
117 | default:
118 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
119 | (string) result["error_msg"], null);
120 | }
121 |
122 | var translation = ((string) result["translation"][0]).Split('\n');
123 | if (translation.Length >= chattingLines.Count)
124 | {
125 | for (var i = 0; i < chattingLines.Count; i++)
126 | {
127 | chattingLines[i].TranslatedContent = translation[i];
128 | }
129 | }
130 | else
131 | {
132 | // TODO: Oops!
133 | }
134 | }
135 | catch (TranslateException)
136 | {
137 | throw;
138 | }
139 | catch (Exception ex)
140 | {
141 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
142 | }
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/baidu/BaiduTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Text;
7 | using ACT.FFXIVTranslate.localization;
8 | using ACT.FoxCommon;
9 | using ACT.FoxCommon.localization;
10 | using Newtonsoft.Json.Linq;
11 |
12 | namespace ACT.FFXIVTranslate.translate.baidu
13 | {
14 | internal class BaiduTranslateProvider : DefaultTranslateProvider
15 | {
16 | private readonly string _appId;
17 | private readonly string _secret;
18 | private readonly string _langFrom;
19 | private readonly string _langTo;
20 |
21 |
22 | public BaiduTranslateProvider(string apiKey, LanguageDef src, LanguageDef dst)
23 | {
24 | var kp = apiKey.Split(':');
25 | if (kp.Length < 2)
26 | {
27 | _appId = "";
28 | _secret = "";
29 | }
30 | else
31 | {
32 | _appId = kp[0];
33 | _secret = kp[1];
34 | }
35 | _langFrom = src?.LangCode ?? "auto";
36 | _langTo = dst.LangCode;
37 | }
38 |
39 | public override void Translate(List chattingLines)
40 | {
41 | try
42 | {
43 | // Build text
44 | var query = string.Join("\n", chattingLines.Select(it => it.CleanedContent));
45 |
46 | // 1. Generate a salt
47 | var salt = Utils.TimestampMillisFromDateTime(DateTime.Now).ToString();
48 | // 2. Calculate sign
49 | var md5Input = Encoding.UTF8.GetBytes($"{_appId}{query}{salt}{_secret}");
50 | var md5 = System.Security.Cryptography.MD5.Create();
51 | var hash = md5.ComputeHash(md5Input);
52 | var sign = string.Join("", hash.Select(it => it.ToString("x2")));
53 |
54 | string textResponse;
55 | using (var client = ProxyFactory.Instance.NewClient())
56 | using (var request = new HttpRequestMessage(HttpMethod.Post, "/api/trans/vip/translate"))
57 | {
58 | client.BaseAddress = new Uri("https://fanyi-api.baidu.com");
59 |
60 | var keyValues = new List>();
61 | keyValues.Add(new KeyValuePair("q", query));
62 | keyValues.Add(new KeyValuePair("from", _langFrom));
63 | keyValues.Add(new KeyValuePair("to", _langTo));
64 | keyValues.Add(new KeyValuePair("appid", _appId));
65 | keyValues.Add(new KeyValuePair("salt", salt));
66 | keyValues.Add(new KeyValuePair("sign", sign));
67 |
68 | request.Content = new FormUrlEncodedContent(keyValues);
69 | var response = client.SendAsync(request).Result;
70 | response.EnsureSuccessStatusCode();
71 | textResponse = response.Content.ReadAsStringAsync().Result;
72 | Debug.WriteLine(textResponse);
73 | }
74 |
75 | // read json
76 | var result = JObject.Parse(textResponse);
77 | if (((IDictionary) result).ContainsKey("error_code"))
78 | {
79 | // Something wrong
80 | var errorCode = (string)result["error_code"];
81 | switch (errorCode)
82 | {
83 | case "52000": // This one is good
84 | break;
85 | case "52001":
86 | case "52002":
87 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
88 | (string) result["error_msg"], null);
89 | case "52003":
90 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
91 | "AppId Error", null);
92 | case "54000":
93 | throw new TranslateException(TranslateException.ExceptionReason.InternalError,
94 | "API Params Missing", null);
95 | case "54001":
96 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
97 | "Secret Error", null);
98 | case "54003":
99 | case "54005":
100 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
101 | "Too Frequently", null);
102 | case "54004":
103 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
104 | "Insufficient Account Balance", null);
105 | case "58000":
106 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
107 | "Limited IP",
108 | null);
109 | case "58001":
110 | throw new TranslateException(TranslateException.ExceptionReason.DirectionNotSupported,
111 | (string) result["error_msg"], null);
112 | default:
113 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
114 | (string) result["error_msg"], null);
115 | }
116 | }
117 |
118 | var transResult = (JArray) result["trans_result"];
119 | if (transResult.Count >= chattingLines.Count)
120 | {
121 | for (var i = 0; i < chattingLines.Count; i++)
122 | {
123 | chattingLines[i].TranslatedContent = (string) transResult[i]["dst"];
124 | }
125 | }
126 | else
127 | {
128 | // TODO: Oops!
129 | }
130 | }
131 | catch (TranslateException)
132 | {
133 | throw;
134 | }
135 | catch (Exception ex)
136 | {
137 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
138 | }
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/yandax/YandaxTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Runtime.Serialization;
7 | using System.Runtime.Serialization.Json;
8 | using System.Text;
9 | using System.Xml;
10 | using ACT.FoxCommon.localization;
11 |
12 | namespace ACT.FFXIVTranslate.translate.yandax
13 | {
14 | internal class YandaxTranslateProvider : DefaultTranslateProvider
15 | {
16 | private readonly string _apiKey;
17 | private readonly string _lang;
18 |
19 | public YandaxTranslateProvider(string apiKey, LanguageDef src, LanguageDef dst)
20 | {
21 | _apiKey = apiKey;
22 | _lang = src == null ? dst.LangCode : $"{src.LangCode}-{dst.LangCode}";
23 | }
24 |
25 | public override void Translate(List chattingLines)
26 | {
27 | try
28 | {
29 | // Build text
30 | var textBuilder = new StringBuilder();
31 | var settings = new XmlWriterSettings {OmitXmlDeclaration = true};
32 | var textWriter = XmlWriter.Create(textBuilder, settings);
33 | textWriter.WriteStartElement("lines");
34 | foreach (var line in chattingLines)
35 | {
36 | textWriter.WriteElementString("line", line.CleanedContent);
37 | }
38 | textWriter.WriteEndElement();
39 | textWriter.Flush();
40 | textWriter.Close();
41 |
42 | var text = textBuilder.ToString();
43 | string textResponse;
44 | using (var client = ProxyFactory.Instance.NewClient())
45 | using (var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1.5/tr.json/translate"))
46 | {
47 | client.BaseAddress = new Uri("https://translate.yandex.net");
48 |
49 | var keyValues = new List>();
50 | keyValues.Add(new KeyValuePair("key", _apiKey));
51 | keyValues.Add(new KeyValuePair("text", text));
52 | keyValues.Add(new KeyValuePair("lang", _lang));
53 | keyValues.Add(new KeyValuePair("options", "1"));
54 | keyValues.Add(new KeyValuePair("format", "html"));
55 |
56 | request.Content = new FormUrlEncodedContent(keyValues);
57 | var response = client.SendAsync(request).Result;
58 | textResponse = response.Content.ReadAsStringAsync().Result;
59 | }
60 |
61 | // read json
62 | var ser = new DataContractJsonSerializer(typeof(YandexTranslateResult));
63 | var result =
64 | (YandexTranslateResult)
65 | ser.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(textResponse)));
66 |
67 | switch (result.Code)
68 | {
69 | case 200:
70 | break;
71 |
72 | // Faild
73 | case 401:
74 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
75 | "Invalid API key",
76 | null);
77 | case 402:
78 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
79 | "Blocked API key",
80 | null);
81 | case 404:
82 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
83 | "Exceeded the daily limit on the amount of translated text", null);
84 | case 413:
85 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
86 | "Exceeded the maximum text size", null);
87 | case 422:
88 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
89 | "The text cannot be translated", null);
90 | case 501:
91 | throw new TranslateException(TranslateException.ExceptionReason.DirectionNotSupported,
92 | "The specified translation direction is not supported", null);
93 | default:
94 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
95 | $"Code = {result.Code}, Msg = {result.Message}", null);
96 | }
97 |
98 |
99 | var translatedLinesXml = result.Text[0];
100 | // Parse xml
101 | var doc = new XmlDocument();
102 | doc.LoadXml(translatedLinesXml);
103 | var nodes = doc.SelectNodes("lines/line");
104 | if (nodes == null || nodes.Count != chattingLines.Count)
105 | {
106 | // Error
107 | throw new TranslateException(TranslateException.ExceptionReason.InternalError,
108 | "Translate result count mismatch.", null);
109 | }
110 |
111 | foreach (var p in chattingLines.Zip(nodes.Cast(),
112 | (a, b) => new KeyValuePair(a, b)))
113 | {
114 | p.Key.TranslatedContent = p.Value.InnerText;
115 | }
116 | }
117 | catch (TranslateException)
118 | {
119 | throw;
120 | }
121 | catch (Exception ex)
122 | {
123 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
124 | }
125 | }
126 |
127 | [DataContract]
128 | internal class YandexTranslateResult
129 | {
130 | [DataContract]
131 | internal class DetectedLang
132 | {
133 | [DataMember(Name = "lang", IsRequired = true)] internal string Lang;
134 | }
135 |
136 | [DataMember(Name = "code", IsRequired = true)] internal int Code;
137 |
138 | [DataMember(Name = "message", IsRequired = false)] internal string Message;
139 |
140 | [DataMember(Name = "detected", IsRequired = false)] internal DetectedLang Detected;
141 |
142 | [DataMember(Name = "lang", IsRequired = false)] internal string Lang;
143 |
144 | [DataMember(Name = "text", IsRequired = false)] internal string[] Text;
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/TranslateProviderPanel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Windows.Forms;
4 | using ACT.FFXIVTranslate.localization;
5 | using ACT.FoxCommon.dpi;
6 | using ACT.FoxCommon.localization;
7 |
8 | namespace ACT.FFXIVTranslate.translate
9 | {
10 | public partial class TranslateProviderPanel : UserControl, IPluginComponent
11 | {
12 | private FFXIVTranslatePlugin _plugin;
13 | private TranslateService _service;
14 |
15 | public TranslateProviderPanel()
16 | {
17 | InitializeComponent();
18 | comboBoxProvider.DisplayMember = nameof(ITranslateProviderFactory.ProviderName);
19 | comboBoxProvider.ValueMember = nameof(ITranslateProviderFactory.ProviderId);
20 | comboBoxLangFrom.DisplayMember = nameof(LanguageDef.DisplayName);
21 | comboBoxLangFrom.ValueMember = nameof(LanguageDef.LangCode);
22 | comboBoxLangTo.DisplayMember = nameof(LanguageDef.DisplayName);
23 | comboBoxLangTo.ValueMember = nameof(LanguageDef.LangCode);
24 |
25 | this.AdjustForDpiScaling();
26 | }
27 |
28 | public void AttachToAct(FFXIVTranslatePlugin plugin)
29 | {
30 | _service = plugin.TranslateService;
31 | _plugin = plugin;
32 |
33 | var controller = plugin.Controller;
34 | controller.TranslateProviderChanged += ControllerOnTranslateProviderChanged;
35 | controller.LegalInfoChanged += ControllerOnLegalInfoChanged;
36 | }
37 |
38 | public void PostAttachToAct(FFXIVTranslatePlugin plugin)
39 | {
40 | }
41 |
42 | public void DoLocalization()
43 | {
44 | comboBoxProvider.DataSource = _service.AllProviders;
45 | }
46 |
47 | private void comboBoxProvider_SelectedIndexChanged(object sender, EventArgs e)
48 | {
49 | var selectedProvider = (ITranslateProviderFactory) comboBoxProvider.SelectedItem;
50 |
51 | if (selectedProvider != null)
52 | {
53 | // Update language selector
54 | comboBoxLangFrom.DataSource = selectedProvider.SupportAutoDetect
55 | ? new[] { new LanguageDef(LanguageDef.CodeAuto, strings.LangAutoDetect, string.Empty) }.Concat(selectedProvider.SupportedSrcLanguages).ToList()
56 | : selectedProvider.SupportedSrcLanguages;
57 |
58 | UpdateSupportedDestLanguage();
59 | }
60 | }
61 |
62 | private void UpdateSupportedDestLanguage()
63 | {
64 | var selectedProvider = (ITranslateProviderFactory) comboBoxProvider.SelectedItem;
65 | var selectedFromLang = (LanguageDef) comboBoxLangFrom.SelectedItem;
66 |
67 | if (selectedProvider != null && selectedFromLang != null)
68 | {
69 | comboBoxLangTo.DataSource = selectedProvider.GetSupportedDestLanguages(selectedFromLang);
70 | }
71 | }
72 |
73 | private void ControllerOnTranslateProviderChanged(bool fromView, string provider, string apiKey, string langFrom, string langTo)
74 | {
75 | if (fromView)
76 | {
77 | return;
78 | }
79 |
80 | if (string.IsNullOrEmpty(provider))
81 | {
82 | comboBoxProvider.SelectedIndex = 0;
83 | }
84 | else
85 | {
86 | comboBoxProvider.SelectedValue = provider;
87 | if (comboBoxProvider.SelectedIndex == -1)
88 | {
89 | comboBoxProvider.SelectedIndex = 0;
90 | }
91 | }
92 |
93 | if (!string.IsNullOrEmpty(apiKey))
94 | {
95 | textBoxApiKey.Text = apiKey;
96 | }
97 |
98 | if (string.IsNullOrEmpty(langFrom))
99 | {
100 | comboBoxLangFrom.SelectedIndex = 0;
101 | }
102 | else
103 | {
104 | comboBoxLangFrom.SelectedValue = langFrom;
105 | if (comboBoxLangFrom.SelectedIndex == -1)
106 | {
107 | comboBoxLangFrom.SelectedIndex = 0;
108 | }
109 | }
110 |
111 | if (string.IsNullOrEmpty(langTo))
112 | {
113 | comboBoxLangTo.SelectedIndex = 0;
114 | }
115 | else
116 | {
117 | comboBoxLangTo.SelectedValue = langTo;
118 | if (comboBoxLangTo.SelectedIndex == -1)
119 | {
120 | comboBoxLangTo.SelectedIndex = 0;
121 | }
122 | }
123 | _plugin.Controller.NotifyTranslateProviderChanged(true, (string)comboBoxProvider.SelectedValue,
124 | textBoxApiKey.Text, (string)comboBoxLangFrom.SelectedValue, (string)comboBoxLangTo.SelectedValue);
125 | }
126 |
127 | private void ControllerOnLegalInfoChanged(bool fromView, ProviderLegalInfo info)
128 | {
129 | var label = info?.LabelResult;
130 | if (label != null)
131 | {
132 | linkLabelPowered.Visible = true;
133 | linkLabelPowered.Text = label;
134 | linkLabelPowered.Tag = info.LabelResultLink;
135 | }
136 | else
137 | {
138 | linkLabelPowered.Visible = false;
139 | linkLabelPowered.Tag = null;
140 | }
141 | }
142 |
143 | private void buttonProviderApply_Click(object sender, EventArgs e)
144 | {
145 | _plugin.Controller.NotifyTranslateProviderChanged(true, (string) comboBoxProvider.SelectedValue,
146 | textBoxApiKey.Text, (string) comboBoxLangFrom.SelectedValue, (string) comboBoxLangTo.SelectedValue);
147 | }
148 |
149 | private void linkLabelPowered_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
150 | {
151 | if (linkLabelPowered.Tag is string link)
152 | {
153 | System.Diagnostics.Process.Start(link);
154 | }
155 | }
156 |
157 | private void buttonFreeKey_Click(object sender, EventArgs e)
158 | {
159 |
160 | var selectedProvider = (ITranslateProviderFactory) comboBoxProvider.SelectedItem;
161 |
162 | if (selectedProvider != null)
163 | {
164 | var key = selectedProvider.DefaultPublicKey;
165 | if (string.IsNullOrEmpty(key))
166 | {
167 | key = string.Empty;
168 | MessageBox.Show(strings.messageNoFreeKey, strings.actPanelTitle,
169 | MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
170 | }
171 | textBoxApiKey.Text = key;
172 | }
173 | }
174 |
175 | private void ComboBoxLangFrom_SelectedIndexChanged(object sender, EventArgs e)
176 | {
177 | UpdateSupportedDestLanguage();
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFCellDefinitionBuilder.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System.Text;
9 | using System.Windows.Forms;
10 |
11 | public partial class RTFBuilder
12 | {
13 | #region Nested type: RTFCellDefinitionBuilder
14 |
15 | // ----------------------------------------------------------------------------------------
16 | // _ ___ _..-._ Date: 12/11/08 23:47
17 | // \`.|\..----...-'` `-._.-'' _.-..'
18 | // / ' ` , __.-''
19 | // )/` _/ \ `-_, / Solution: RTFLib
20 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
21 | // _.-'_./ {_.' ; / Author : Anton
22 | // {_.-``-' {_/ Assembly: 1.0.0.0
23 | // Copyright © 2005-2008, Rogue Trader/MWM
24 | // Project Item Name: RTFCellDefinitionBuilder.cs - Code
25 | // Purpose: Injects Cell Rtf Codes
26 | // ----------------------------------------------------------------------------------------
27 | ///
28 | /// Injects Cell Rtf Codes
29 | ///
30 | private class RTFCellDefinitionBuilder
31 | {
32 | #region Fields
33 |
34 | private readonly RTFBuilder _builder;
35 | private readonly StringBuilder _definitionBuilder;
36 | private RTFCellDefinition _cellDefinition;
37 |
38 | #endregion
39 |
40 | #region Constructor
41 |
42 | internal RTFCellDefinitionBuilder(RTFBuilder builder, StringBuilder definitionBuilder, RTFCellDefinition cellDefinition)
43 | {
44 | this._builder = builder;
45 |
46 | this._definitionBuilder = definitionBuilder;
47 | this._cellDefinition = cellDefinition;
48 |
49 |
50 | this.AppendDefinition();
51 | }
52 |
53 | #endregion
54 |
55 | #region Public Properties
56 |
57 | public RTFCellDefinition CellDefinition
58 | {
59 | get { return this._cellDefinition; }
60 | }
61 |
62 | #endregion
63 |
64 | #region Methods
65 |
66 | private void AppendDefinition()
67 | {
68 | this.CellAlignment();
69 | this.TableCellBorderSide();
70 | //Pad();
71 |
72 |
73 | this._definitionBuilder.AppendFormat("\\cellx{0}", (int) (this._cellDefinition.CellWidthRaw * TWIPSA4) + this._cellDefinition.X);
74 | //_definitionBuilder.AppendFormat("\\clwWidth{0}", _cellDefinition.CellWidth);
75 |
76 | //_definitionBuilder.Append("\\cltxlrtb\\clFitText");
77 |
78 | this._definitionBuilder.AppendLine();
79 |
80 |
81 | //Cell text flow
82 | }
83 |
84 | private string BorderDef()
85 | {
86 | StringBuilder sb = new StringBuilder();
87 | RTFBorderSide _rTFBorderSide = this._cellDefinition.RTFBorderSide;
88 | if ((_rTFBorderSide & RTFBorderSide.DoubleThickness) == RTFBorderSide.DoubleThickness)
89 | {
90 | sb.Append("\\brdrth");
91 | }
92 | else
93 | {
94 | sb.Append("\\brdrs");
95 | }
96 | if ((_rTFBorderSide & RTFBorderSide.DoubleBorder) == RTFBorderSide.DoubleBorder)
97 | {
98 | sb.Append("\\brdrdb");
99 | }
100 | sb.Append("\\brdrw");
101 | sb.Append(this._cellDefinition.BorderWidth);
102 |
103 | sb.Append("\\brdrcf");
104 | sb.Append(this._builder.IndexOf(this._cellDefinition.BorderColor));
105 |
106 | return sb.ToString();
107 | }
108 |
109 | private void CellAlignment()
110 | {
111 | switch (this._cellDefinition.Alignment)
112 | {
113 | case RTFAlignment.BottomCenter:
114 | case RTFAlignment.BottomLeft:
115 | case RTFAlignment.BottomRight:
116 | this._definitionBuilder.Append("\\clvertalb"); //\\qr
117 | break;
118 | case RTFAlignment.MiddleCenter:
119 | case RTFAlignment.MiddleLeft:
120 | case RTFAlignment.MiddleRight:
121 | this._definitionBuilder.Append("\\clvertalc"); //\\qr
122 | break;
123 | case RTFAlignment.TopCenter:
124 | case RTFAlignment.TopLeft:
125 | case RTFAlignment.TopRight:
126 | this._definitionBuilder.Append("\\clvertalt"); //\\qr
127 | break;
128 | }
129 | }
130 |
131 | private void Pad()
132 | {
133 | if (this._cellDefinition.Padding != Padding.Empty)
134 | {
135 | StringBuilder sb = this._definitionBuilder;
136 | sb.AppendFormat("\\clpadfl3\\clpadl{0}", this._cellDefinition.Padding.Left);
137 | sb.AppendFormat("\\clpadlr3\\clpadr{0}", this._cellDefinition.Padding.Right);
138 | sb.AppendFormat("\\clpadlt3\\clpadt{0}", this._cellDefinition.Padding.Top);
139 | sb.AppendFormat("\\clpadlb3\\clpadb{0}", this._cellDefinition.Padding.Bottom);
140 | }
141 | }
142 |
143 | private void TableCellBorderSide()
144 | {
145 | RTFBorderSide _rTFBorderSide = this._cellDefinition.RTFBorderSide;
146 |
147 | if (_rTFBorderSide != RTFBorderSide.None)
148 | {
149 | StringBuilder sb = this._definitionBuilder;
150 | string bd = this.BorderDef();
151 | if (_rTFBorderSide == RTFBorderSide.None)
152 | {
153 | sb.Append("\\brdrnil");
154 | }
155 | else
156 | {
157 | if ((_rTFBorderSide & RTFBorderSide.Left) == RTFBorderSide.Left)
158 | {
159 | sb.Append("\\clbrdrl").Append(bd);
160 | }
161 | if ((_rTFBorderSide & RTFBorderSide.Right) == RTFBorderSide.Right)
162 | {
163 | sb.Append("\\clbrdrr").Append(bd);
164 | }
165 | if ((_rTFBorderSide & RTFBorderSide.Top) == RTFBorderSide.Top)
166 | {
167 | sb.Append("\\clbrdrt").Append(bd);
168 | }
169 | if ((_rTFBorderSide & RTFBorderSide.Bottom) == RTFBorderSide.Bottom)
170 | {
171 | sb.Append("\\clbrdrb").Append(bd);
172 | }
173 | }
174 | }
175 | }
176 |
177 | #endregion
178 | }
179 |
180 | #endregion
181 | }
182 | }
183 |
184 |
185 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://ci.appveyor.com/project/Noisyfox/act-ffxivtranslate/branch/master)
2 |
3 | # Help Translate this Plugin!
4 | The plugin UI now support Chinese (Simplified) and English (US) only.
5 |
6 | If you speak another language or speak English / Chinese better than me and wanna help,
7 | please visit:
8 | https://noisyfox.oneskyapp.com/collaboration/project/128830
9 |
10 | Currently I plan to support Russian and Chinese (Tranditional). If you'd like this plugin
11 | to support your language, please raise an Issue and I can add more languages!
12 |
13 | Any help would be appreciated!
14 |
15 | # ACT.FFXIVTranslate
16 | 这是一个用来翻译最终幻想14国际服玩家聊天内容的ACT插件。
17 |
18 | # 如何使用
19 | 1. 从这里下载最新版的插件 https://github.com/Noisyfox/ACT.FFXIVTranslate/releases
20 | 2. 将7z压缩包内的全部文件解压并覆盖到ACT的安装目录(ACT可执行文件本体所在目录)下。
21 | 3. 打开ACT,在 功能插件 -> 插件列表 选项卡中添加并启用ACT.FFXIVTranslate.dll插件。
22 | 4. 将悬浮窗拖拽到合适的位置,大功告成!
23 |
24 | # 翻译来源设置
25 | 目前本插件支持以下六个在线翻译API:
26 | - Yandax.Translate
27 | - 百度翻译
28 | - Microsoft Translator
29 | - 谷歌翻译非官方版
30 | - 有道翻译
31 | - 腾讯翻译
32 |
33 | 其中谷歌翻译非官方版不需要输入API key就可以使用。
34 | 我为 Yandax.Translate 与 Microsoft Translator 这两个翻译API都申请了免费的API key提供给大家测试或者临时使用。
35 | 由于百度翻译和有道翻译会在免费额度用完后立刻开始收费,因此在此不提供试用key,大家可以按照下文的说明自行申请API key(非常简单)。
36 |
37 | 插件默认使用Yandax.Translate(老毛子的翻译),你可以在**来源**下拉列表中选择不同的翻译API。
38 |
39 | 点击**使用公用密钥**按钮会自动根据当前选择的翻译API设置我提供的免费公开的API密钥,或者你可以输入自己申请的API密钥。
40 |
41 | 请记得每次更改完翻译来源设置后要点击**应用**按钮,否则更改不会被保存。
42 |
43 | # 获取你自己的API密钥
44 | 我提供的免费密钥是有各种使用限制的,你可以申请属于自己的API密钥来避免遇到这些限制。
45 |
46 | ## Yandax.Translate
47 | 1. 访问 https://tech.yandex.com/translate/
48 | 2. 点击页面中的 **Get a free API key.** 链接。
49 | 3. 遵循网页的提示一步步操作,你就可以拥有属于你自己的API密钥啦。
50 |
51 | ## Microsoft Translator
52 | 1. 访问 https://portal.azure.com/
53 | 2. 注册并登录Azure门户。(中国用户请注意,请不要切换到中国区,我不知道中国区的Key能不能用)
54 | 3. 创建一个 **Translator 文本 API** 实例:
55 | 1. 点击页面左上角的加号按钮。
56 | 2. 搜索 **Translator 文本 API**,在搜索结果中点击该项,然后点击 **创建**。
57 | 3. 输入所有必填项,然后点击 **创建** 按钮。记得**定价层**这一项要选**F0**不然不是免费的。
58 | 4. 创建完实例后,在Azure门户中找到这个实例并进入详情页面。
59 | 5. 点击页面左侧的 **Keys** 链接,你会看到两个KEY。这两个KEY你可以任选一个来用。
60 |
61 | ## 百度翻译
62 | 1. 访问 http://api.fanyi.baidu.com/api/trans/product/index
63 | 2. 点击页面中的 **申请接入** 按钮,如有需要请登录你的百度账号。
64 | 3. 根据页面提示输入所需资料并继续。
65 | 4. 当提示**API接口权限申请成功**时,你可以在下方找到你的 *APP ID* 和 *密钥*。
66 | 5. 在本插件的**API密钥**框中输入 *APP ID*:*密钥*,注意分隔符为半角冒号,前后均无任何空格,请不要输错。
67 |
68 | ## 有道翻译
69 | 1. 访问 http://ai.youdao.com/index.s 并登录。
70 | 2. 页面左侧选择**自然语言翻译**->**翻译实例**。
71 | 3. 点击**创建实例**按钮,按照提示创建好一个实例。
72 | 4. 页面左侧选择**应用管理**->**我的应用**。
73 | 5. 点击**创建应用**按钮,按照提示创建好一个应用。在创建应用完成后的**应用实例添加**对话框中,选中刚才创建好的**自然语言翻译服务**的实例,并点击**提交更改**按钮。
74 | 6. 在**应用详情**页面可以看到应用的 *应用ID* 以及 *应用密钥*。
75 | 7. 在本插件的**API密钥**框中输入 *应用ID*:*应用密钥*,注意分隔符为半角冒号,前后均无任何空格,请不要输错。
76 |
77 | ## 腾讯翻译
78 | 1. 访问 https://cloud.tencent.com/product/tmt/, 点击 **立即使用** 按钮。按提示登录腾讯云。
79 | 2. 首次使用会提示要开通机器翻译功能,按提示开通免费版本(当然你愿意可以开收费版:P)。
80 | 3. 开通机器翻译后,访问 https://console.cloud.tencent.com/cam/capi 并点击 **新建密钥** 创建一组 *SecretId* 和 *SecretKey*。
81 | - 可能会看到一个关于使用子用户的高风险提示,如果你只是个人使用那么可以点击 **继续使用**。
82 | - **请勿将自己的密钥共享给他人!该密钥拥有完整的腾讯云权限,随意共享可能导致您的财产损失!**
83 | - **请勿将自己的密钥共享给他人!该密钥拥有完整的腾讯云权限,随意共享可能导致您的财产损失!**
84 | - **请勿将自己的密钥共享给他人!该密钥拥有完整的腾讯云权限,随意共享可能导致您的财产损失!**
85 | - *如果您熟悉腾讯云的权限管理机制的话,您是可以创建出一个能够安全共享的密钥,然而该操作比较复杂,除非您知道自己在做什么,否则***绝对不要***与任何人共享您的密钥!*
86 | - **共享密钥导致的任何损失,本人不承担任何责任!**
87 | - **本插件在任何情况下都不会与任何人共享您输入的密钥。**
88 | - **如果您要截图分享您的插件设置,请注意给自己的密钥打码!**
89 | 4. 在本插件的 **API密钥** 框中输入 *SecretId*:*SecretKey*,注意分隔符为半角冒号,前后均无任何空格,请不要输错。
90 |
91 | # Q & A
92 | > Q: 启用该插件后我的ACT窗口变小了!
93 |
94 | 请参考 [https://github.com/Noisyfox/ACT.FFXIVTranslate/wiki/Fix-ACT-window-scale-down](https://github.com/Noisyfox/ACT.FFXIVTranslate/wiki/Fix-ACT-window-scale-down)
95 |
96 | > Q: 我用的无猫整合版 ACT,没有办法加载插件,肿么办
97 |
98 | 访问 [http://bbs.nga.cn/read.php?tid=12526945](http://bbs.nga.cn/read.php?tid=12526945),找到 __ACT插件自整合__ 分类的百度网盘地址,选择 __单体插件自整合 > 6. 其他工具__,使用其中的
99 | __ACT绿色化工具(配置移根目录).rar__ 处理即可。
100 |
101 | # TODO
102 | - ~~加入显示开关~~
103 | - 加入谷歌翻译官方API支持。
104 | - ~~加入谷歌翻译非官方API支持。~~
105 | - ~~加入http代理支持。~~
106 | - ~~加入socks5代理支持。~~
107 | - ~~在翻译窗口中显示聊天的频道。不同频道的聊天内容会用不同颜色来显示,就和游戏里一样。~~
108 | - (不太容易) 正常显示 *定型文字*。
109 | - ~~显示消息时间。~~
110 | - ~~当游戏窗口非激活状态时自动隐藏悬浮窗。~~
111 | - 以后想到啥再加咯 :P
112 |
113 | -------
114 | # ACT.FFXIVTranslate
115 | An ACT plugin to translate palyers' chatting for Final Fantasy XIV
116 |
117 | # How To
118 | 1. Download the latest version of the plugin from https://github.com/Noisyfox/ACT.FFXIVTranslate/releases
119 | 2. Extract all files inside the .7z archive, put them under your ACT installation directry,
120 | where you can find the ACT's main executable file. Replace any existing files.
121 | 3. Open ACT, add and enable ACT.FFXIVTranslate.dll in Plugins -> Plugin Listing page.
122 | 4. Drag the translation window to your prefer location and enjoy!
123 |
124 | # Translator Provider Settings
125 | Currently this plugin support 6 providers:
126 | - Yandax.Translate
127 | - Baidu Translator
128 | - Microsoft Translator
129 | - Unofficial Google Translate
130 | - Youdao Translator
131 | - Tencent Translator
132 |
133 | The unofficial Google Translate doesn't require an API key.
134 | Yandax.Translate and Microsoft Translator providers are bundled with a free public API key for testing / temporarily using.
135 | For Baidu & Youdao Translator users, I assume you are Chinese people so please read the Chinese part above :P
136 |
137 | The default provider is Yandax.Translate, you could change it by selecting a different one from the **Provider** combo box.
138 |
139 | Click **Use Free Key** button to set the API key to current provider's default key or you could enter your own API key.
140 |
141 | Remember to click **Apply** button if you changed any provider settings otherwise the change won't take effect until next time
142 | the ACT starts.
143 |
144 | # Obtain your own API key
145 | The free api keys have limits on words per month. You may want to get your own personal API keys to avoid those limits.
146 |
147 | ## Yandax.Translate
148 | 1. Visit https://tech.yandex.com/translate/
149 | 2. Click the link **Get a free API key.** on that page.
150 | 3. Follow the instructions and you will get your own API key for free.
151 |
152 | ## Microsoft Translator
153 | 1. Visit https://portal.azure.com/
154 | 2. Register and / or login to Azure portal.
155 | 3. Create a **Translator Text API** instance:
156 | 1. Click the Add icon at the top left bar.
157 | 2. Search **Translator Text API**, click the item from search result, and click **Create**.
158 | 3. Fill in all the request information and click **Click**. Remember to select **F0** plan for
159 | pricing otherwise you will be charged.
160 | 4. After creating the instance, find it in Azure protal and go to the detail page.
161 | 5. Click the link **Keys** at the left side, and you will find two keys. Any of those should be work.
162 |
163 | # Q & A
164 | > Q: My ACT window get resized after enable this plugin
165 |
166 | See https://github.com/Noisyfox/ACT.FFXIVTranslate/wiki/Fix-ACT-window-scale-down
167 |
168 | # TODO
169 | - ~~Add switch to show / hide the overlay~~
170 | - Add official Google Translate support.
171 | - ~~Add unofficial Google Translate support.~~
172 | - ~~Add http proxy support.~~
173 | - ~~Add socks5 proxy support.~~
174 | - ~~Display chatting channel. Have different colors for different channels, just like the game does.~~
175 | - (unlikely) Display *Auto-Translate*.
176 | - ~~Show message time.~~
177 | - ~~Hide overlay when game window is not active.~~
178 | - More to come :P
179 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/MainController.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using ACT.FFXIVTranslate.translate;
4 | using ACT.FoxCommon.core;
5 |
6 | namespace ACT.FFXIVTranslate
7 | {
8 | public class MainController : MainControllerBase
9 | {
10 |
11 | public delegate void OnOverlayMovedDelegate(bool fromView, int x, int y);
12 |
13 | public event OnOverlayMovedDelegate OverlayMoved;
14 |
15 | public void NotifyOverlayMoved(bool fromView, int x, int y)
16 | {
17 | OverlayMoved?.Invoke(fromView, x, y);
18 | }
19 |
20 | public delegate void OnOverlayResizedDelegate(bool fromView, int w, int h);
21 |
22 | public event OnOverlayResizedDelegate OverlayResized;
23 |
24 | public void NotifyOverlayResized(bool fromView, int w, int h)
25 | {
26 | OverlayResized?.Invoke(fromView, w, h);
27 | }
28 |
29 | public delegate void OnOpacityChangedDelegate(bool fromView, double value);
30 |
31 | public event OnOpacityChangedDelegate OpacityChanged;
32 |
33 | public void NotifyOpacityChanged(bool fromView, double value)
34 | {
35 | OpacityChanged?.Invoke(fromView, value);
36 | }
37 |
38 | public delegate void OnClickthroughChangedDelegate(bool fromView, bool clickthrough);
39 |
40 | public event OnClickthroughChangedDelegate ClickthroughChanged;
41 |
42 | public void NotifyClickthroughChanged(bool fromView, bool clickthrough)
43 | {
44 | ClickthroughChanged?.Invoke(fromView, clickthrough);
45 | }
46 |
47 | public delegate void OnBatchTranslateCompletedDelegate(bool fromView, List chattingLines);
48 |
49 | public event OnBatchTranslateCompletedDelegate BatchTranslateCompleted;
50 |
51 | public void NotifyBatchTranslateCompleted(bool fromView, List chattingLines)
52 | {
53 | BatchTranslateCompleted?.Invoke(fromView, chattingLines);
54 | }
55 |
56 | public delegate void OnOverlayContentUpdatedDelegate(bool fromView, string content);
57 |
58 | public event OnOverlayContentUpdatedDelegate OverlayContentUpdated;
59 |
60 | public void NotifyOverlayContentUpdated(bool fromView, string content)
61 | {
62 | OverlayContentUpdated?.Invoke(fromView, content);
63 | }
64 |
65 | public delegate void OnProviderChangedDelegate(
66 | bool fromView, string provider, string apiKey, string langFrom, string langTo);
67 |
68 | public event OnProviderChangedDelegate TranslateProviderChanged;
69 |
70 | public void NotifyTranslateProviderChanged(bool fromView, string provider, string apiKey, string langFrom,
71 | string langTo)
72 | {
73 | TranslateProviderChanged?.Invoke(fromView, provider, apiKey, langFrom, langTo);
74 | }
75 |
76 | public delegate void OnChannelFilterChangedDelegate(bool fromView, EventCode code, bool show);
77 |
78 | public event OnChannelFilterChangedDelegate ChannelFilterChanged;
79 |
80 | public void NotifyChannelFilterChanged(bool fromView, EventCode code, bool show)
81 | {
82 | ChannelFilterChanged?.Invoke(fromView, code, show);
83 | }
84 |
85 | public delegate void OnChannelLabelChangedDelegate(bool fromView, EventCode code, bool show);
86 |
87 | public event OnChannelLabelChangedDelegate ChannelLabelChanged;
88 |
89 | public void NotifyChannelLabelChanged(bool fromView, EventCode code, bool show)
90 | {
91 | ChannelLabelChanged?.Invoke(fromView, code, show);
92 | }
93 |
94 | public delegate void OnChannelColorChangedDelegate(bool fromView, EventCode code, Color color);
95 |
96 | public event OnChannelColorChangedDelegate ChannelColorChanged;
97 |
98 | public void NotifyChannelColorChanged(bool fromView, EventCode code, Color color)
99 | {
100 | ChannelColorChanged?.Invoke(fromView, code, color);
101 | }
102 |
103 | public delegate void OnLanguageChangedDelegate(bool fromView, string lang);
104 |
105 | public event OnLanguageChangedDelegate LanguageChanged;
106 |
107 | public void NotifyLanguageChanged(bool fromView, string lang)
108 | {
109 | LanguageChanged?.Invoke(fromView, lang);
110 | }
111 |
112 | public delegate void OnOverlayFontChangedDelegate(bool fromView, Font font);
113 |
114 | public event OnOverlayFontChangedDelegate OverlayFontChanged;
115 |
116 | public void NotifyOverlayFontChanged(bool fromView, Font font)
117 | {
118 | OverlayFontChanged?.Invoke(fromView, font);
119 | }
120 |
121 | public delegate void OnLegalInfoChangedDelegate(bool fromView, ProviderLegalInfo info);
122 |
123 | public event OnLegalInfoChangedDelegate LegalInfoChanged;
124 |
125 | public void NotifyLegalInfoChanged(bool fromView, ProviderLegalInfo info)
126 | {
127 | LegalInfoChanged?.Invoke(fromView, info);
128 | }
129 |
130 | public delegate void OnShowOverlayChangedDelegate(bool fromView, bool showOverlay);
131 |
132 | public event OnShowOverlayChangedDelegate ShowOverlayChanged;
133 |
134 | public void NotifyShowOverlayChanged(bool fromView, bool showOverlay)
135 | {
136 | ShowOverlayChanged?.Invoke(fromView, showOverlay);
137 | }
138 |
139 | public delegate void OnOverlayAutoHideChangedDelegate(bool fromView, bool autoHide);
140 |
141 | public event OnOverlayAutoHideChangedDelegate OverlayAutoHideChanged;
142 |
143 | public void NotifyOverlayAutoHideChanged(bool fromView, bool autoHide)
144 | {
145 | OverlayAutoHideChanged?.Invoke(fromView, autoHide);
146 | }
147 |
148 | public delegate void OnAddTimestampChangedDelegate(bool fromView, bool show);
149 |
150 | public event OnAddTimestampChangedDelegate AddTimestampChanged;
151 |
152 | public void NotifyAddTimestampChanged(bool fromView, bool show)
153 | {
154 | AddTimestampChanged?.Invoke(fromView, show);
155 | }
156 |
157 | public delegate void OnTimestampFormatChangedDelegate(bool fromView, bool is24Hour);
158 |
159 | public event OnTimestampFormatChangedDelegate TimestampFormatChanged;
160 |
161 | public void NotifyTimestampFormatChanged(bool fromView, bool is24Hour)
162 | {
163 | TimestampFormatChanged?.Invoke(fromView, is24Hour);
164 | }
165 |
166 | public delegate void OnClipboardContentChangedDelegate(bool fromView, string newContent);
167 |
168 | public event OnClipboardContentChangedDelegate ClipboardContentChanged;
169 |
170 | public void NotifyClipboardContentChanged(bool fromView, string newContent)
171 | {
172 | ClipboardContentChanged?.Invoke(fromView, newContent);
173 | }
174 |
175 | public delegate void OnProxyChangedDelegate(bool fromView, string type, string server, int port,
176 | string user, string password, string domain);
177 |
178 | public event OnProxyChangedDelegate ProxyChanged;
179 |
180 | public void NotifyProxyChanged(bool fromView, string type, string server, int port,
181 | string user, string password, string domain)
182 | {
183 | ProxyChanged?.Invoke(fromView, type, server, port, user, password, domain);
184 | }
185 |
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/MSBuild.ILMerge.Task.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(SolutionDir)packages
6 | $(MSBuildProjectDirectory)\ILMergeOrder.txt
7 | $(AssemblyOriginatorKeyFile)
8 |
9 |
10 |
11 | false
12 | false
13 | false
14 | true
15 | false
16 | 512
17 | false
18 |
19 | false
20 | true
21 | true
22 |
23 | false
24 | 40
25 |
26 |
27 | $(MSBuildThisFileDirectory)..\tools\
28 |
29 |
30 |
31 |
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 | @(IntermediateAssembly->'%(FullPath)');@(MergedAssemblies->'%(FullPath)');@(MergedDependencies->'%(FullPath)')
57 |
58 |
59 | @(IntermediateAssembly->'%(FullPath)');@(MergedAssemblies->'%(FullPath)')
60 |
61 |
62 |
63 |
64 |
65 | @(UnmergedAssemblies->'%(FullPath)')
66 | $(TargetPath)
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBuilder.RTFFormatWrap.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | namespace RTF
7 | {
8 | using System;
9 | using System.Drawing;
10 | using System.Text;
11 |
12 | partial class RTFBuilder
13 | {
14 | #region Nested type: RTFFormatWrap
15 |
16 | // ----------------------------------------------------------------------------------------
17 | // _ ___ _..-._ Date: 12/11/08 23:35
18 | // \`.|\..----...-'` `-._.-'' _.-..'
19 | // / ' ` , __.-''
20 | // )/` _/ \ `-_, / Solution: RTFLib
21 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
22 | // _.-'_./ {_.' ; / Author : Anton
23 | // {_.-``-' {_/ Assembly: 1.0.0.0
24 | // Copyright © 2005-2008, Rogue Trader/MWM
25 | // Project Item Name: RTFBuilder.RTFFormatWrap.cs - Code
26 | // Purpose: Wraps RTFBuilderbase for formatting changes allowing injection of appropriate rtf codes to revert format after each Append (string) call
27 | // ----------------------------------------------------------------------------------------
28 | ///
29 | /// Wraps RTFBuilderbase for formatting changes allowing injection of appropriate rtf codes to revert format after each Append (string) call
30 | ///
31 | private class RTFFormatWrap : IDisposable
32 | {
33 | #region Fields
34 |
35 | private readonly RTFBuilder _builder;
36 |
37 | #endregion
38 |
39 | #region Constructor
40 |
41 | public RTFFormatWrap(RTFBuilder builder)
42 | {
43 | this._builder = builder;
44 | if (this._builder._unwrapped)
45 | {
46 | return;
47 | }
48 |
49 | StringBuilder sb = this._builder._sb;
50 |
51 | int len = this._builder._sb.Length;
52 |
53 | if (this._builder._sf.Alignment == StringAlignment.Center)
54 | {
55 | sb.Append("\\qc");
56 | }
57 | else if (this._builder._sf.Alignment == StringAlignment.Far)
58 | {
59 | sb.Append("\\qr");
60 | }
61 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold)
62 | {
63 | sb.Append("\\b");
64 | }
65 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic)
66 | {
67 | sb.Append("\\i");
68 | }
69 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Underline) == System.Drawing.FontStyle.Underline)
70 | {
71 | sb.Append("\\ul");
72 | }
73 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Strikeout) == System.Drawing.FontStyle.Strikeout)
74 | {
75 | sb.Append("\\strike");
76 | }
77 |
78 | if (this._builder._fontSize != this._builder.DefaultFontSize)
79 | {
80 | sb.AppendFormat("\\fs{0}", this._builder._fontSize);
81 | }
82 | if (this._builder._font != 0)
83 | {
84 | sb.AppendFormat("\\f{0}", this._builder._font);
85 | }
86 | if (this._builder._forecolor != this._builder.Defaultforecolor)
87 | {
88 | sb.AppendFormat("\\cf{0}", this._builder.IndexOf(this._builder._forecolor));
89 | }
90 | if (this._builder._backcolor != this._builder.DefaultBackColor)
91 | {
92 | sb.AppendFormat("\\highlight{0}", this._builder.IndexOf(this._builder._backcolor));
93 | }
94 |
95 |
96 | if (sb.Length > len)
97 | {
98 | sb.Append(" ");
99 | }
100 | }
101 |
102 | #endregion
103 |
104 | #region Override Methods
105 |
106 | ~RTFFormatWrap()
107 | {
108 | this.Dispose(false);
109 | }
110 |
111 | #endregion
112 |
113 | #region Methods
114 |
115 | protected void Dispose(bool disposing)
116 | {
117 | if (this._builder != null && !this._builder._unwrapped)
118 | {
119 |
120 | StringBuilder sb = this._builder._sb;
121 |
122 | int len = sb.Length;
123 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold)
124 | {
125 | sb.Append("\\b0");
126 | }
127 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic)
128 | {
129 | sb.Append("\\i0");
130 | }
131 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Underline) == System.Drawing.FontStyle.Underline)
132 | {
133 | sb.Append("\\ulnone");
134 | }
135 | if ((this._builder._fontStyle & System.Drawing.FontStyle.Strikeout) == System.Drawing.FontStyle.Strikeout)
136 | {
137 | sb.Append("\\strike0");
138 | }
139 |
140 | this._builder._fontStyle = System.Drawing.FontStyle.Regular;
141 |
142 | if (this._builder._fontSize != this._builder.DefaultFontSize)
143 | {
144 | this._builder._fontSize = this._builder.DefaultFontSize;
145 | sb.AppendFormat("\\fs{0} ", this._builder.DefaultFontSize);
146 | }
147 | if (this._builder._font != 0)
148 | {
149 | sb.Append("\\f0");
150 | this._builder._font = 0;
151 | }
152 |
153 | if (this._builder._forecolor != this._builder.Defaultforecolor)
154 | {
155 | this._builder._forecolor = this._builder.Defaultforecolor;
156 | sb.Append("\\cf0");
157 | }
158 | if (this._builder._backcolor != this._builder.DefaultBackColor)
159 | {
160 | this._builder._backcolor = this._builder.DefaultBackColor;
161 | sb.Append("\\highlight0");
162 | }
163 | //if (_builder._alignment != StringAlignment.Near )
164 | //{
165 | // _builder._alignment = StringAlignment.Near;
166 | // sb.Append("\\ql");
167 | //}
168 | if (sb.Length > len)
169 | {
170 | sb.Append(" ");
171 | }
172 | }
173 | if (disposing)
174 | {
175 | GC.SuppressFinalize(this);
176 | }
177 | }
178 |
179 | #endregion
180 |
181 | #region IDisposable Members
182 |
183 | public void Dispose()
184 | {
185 | this.Dispose(true);
186 | }
187 |
188 | #endregion
189 | }
190 |
191 | #endregion
192 | }
193 | }
194 |
195 |
196 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/SettingsHolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Drawing;
4 | using System.Windows.Forms;
5 | using ACT.FoxCommon.core;
6 | using ACT.FoxCommon.shortcut;
7 | using Advanced_Combat_Tracker;
8 |
9 | namespace ACT.FFXIVTranslate
10 | {
11 | ///
12 | /// https://github.com/anoyetta/act_timeline/blob/origin/src/PluginSettings.cs
13 | ///
14 | internal class PluginSettings : SettingsSerializer
15 | {
16 | private readonly SettingsIO _settingsIo = new SettingsIO("ACT.FFXIVTranslate");
17 |
18 | public PluginSettings(object ParentSettingsClass) : base(ParentSettingsClass)
19 | {
20 | _settingsIo.WriteSettings = writer =>
21 | {
22 | writer.WriteStartElement("SettingsSerializer");
23 | ExportToXml(writer);
24 | writer.WriteEndElement();
25 | };
26 |
27 | _settingsIo.ReadSettings = reader =>
28 | {
29 | switch (reader.LocalName)
30 | {
31 | case "SettingsSerializer":
32 | ImportFromXml(reader);
33 | break;
34 | }
35 | };
36 | }
37 |
38 | public void Load()
39 | {
40 | _settingsIo.Load();
41 | }
42 |
43 | public void Save()
44 | {
45 | _settingsIo.Save();
46 | }
47 | }
48 |
49 | public class SettingsHolder : IPluginComponent
50 | {
51 | #region Proxy methods
52 |
53 | private PluginSettings Settings { get; }
54 |
55 | public SettingsHolder()
56 | {
57 | Settings = new PluginSettings(this);
58 | }
59 |
60 | public void AddControlSetting(Control controlToSerialize)
61 | {
62 | Settings.AddControlSetting(controlToSerialize.Name, controlToSerialize);
63 | }
64 |
65 | public void Load()
66 | {
67 | Settings.Load();
68 | }
69 |
70 | public void Save()
71 | {
72 | Settings.Save();
73 | }
74 |
75 | #endregion
76 |
77 | #region Settings
78 |
79 | public string TranslateProvider { get; set; }
80 |
81 | public string TranslateApiKey { get; set; }
82 |
83 | public string TranslateLangFrom { get; set; }
84 |
85 | public string TranslateLangTo { get; set; }
86 |
87 | public string Language { get; set; }
88 |
89 | public string OverlayFont { get; set; }
90 |
91 | public string ProxyType { get; set; }
92 |
93 | public string ProxyServer { get; set; }
94 |
95 | public int ProxyPort { get; set; }
96 |
97 | public string ProxyUser { get; set; }
98 |
99 | public string ProxyPassword { get; set; }
100 |
101 | public string ProxyDomain { get; set; }
102 |
103 | public string VersionIgnored { get; set; }
104 |
105 | public string ShortcutHide { get; set; }
106 |
107 | #endregion
108 |
109 | #region Controller notify
110 |
111 | private MainController _controller;
112 |
113 | public void AttachToAct(FFXIVTranslatePlugin plugin)
114 | {
115 | Settings.AddStringSetting(nameof(TranslateProvider));
116 | Settings.AddStringSetting(nameof(TranslateApiKey));
117 | Settings.AddStringSetting(nameof(TranslateLangFrom));
118 | Settings.AddStringSetting(nameof(TranslateLangTo));
119 | Settings.AddStringSetting(nameof(Language));
120 | Settings.AddStringSetting(nameof(OverlayFont));
121 | Settings.AddStringSetting(nameof(ProxyType));
122 | Settings.AddStringSetting(nameof(ProxyServer));
123 | Settings.AddIntSetting(nameof(ProxyPort));
124 | Settings.AddStringSetting(nameof(ProxyUser));
125 | Settings.AddStringSetting(nameof(ProxyPassword));
126 | Settings.AddStringSetting(nameof(ProxyDomain));
127 | Settings.AddStringSetting(nameof(VersionIgnored));
128 | Settings.AddStringSetting(nameof(ShortcutHide));
129 |
130 | _controller = plugin.Controller;
131 |
132 | _controller.LanguageChanged += ControllerOnLanguageChanged;
133 | _controller.OverlayFontChanged += ControllerOnOverlayFontChanged;
134 | _controller.TranslateProviderChanged += ControllerOnTranslateProviderChanged;
135 | _controller.ProxyChanged += ControllerOnProxyChanged;
136 | _controller.NewVersionIgnored += ControllerOnNewVersionIgnored;
137 | _controller.ShortcutChanged += ControllerOnShortcutChanged;
138 | }
139 |
140 | public void PostAttachToAct(FFXIVTranslatePlugin plugin)
141 | {
142 |
143 | }
144 |
145 | public void NotifySettingsLoaded()
146 | {
147 | try
148 | {
149 | _controller.NotifyOverlayFontChanged(false,
150 | (Font)TypeDescriptor.GetConverter(typeof(Font)).ConvertFromString(OverlayFont));
151 | }
152 | catch (Exception)
153 | {
154 | _controller.NotifyOverlayFontChanged(true, new Font(FontFamily.GenericSansSerif, 12, FontStyle.Regular));
155 | }
156 |
157 | _controller.NotifyTranslateProviderChanged(false, TranslateProvider, TranslateApiKey, TranslateLangFrom, TranslateLangTo);
158 | _controller.NotifyProxyChanged(false, ProxyType, ProxyServer, ProxyPort, ProxyUser, ProxyPassword, ProxyDomain);
159 | _controller.NotifyShortcutChanged(false, PluginShortcut.HideOverlay, ShortkeyUtils.StringToKey(ShortcutHide));
160 |
161 | _controller.NotifySettingsLoaded();
162 | }
163 |
164 | private void ControllerOnLanguageChanged(bool fromView, string lang)
165 | {
166 | if (!fromView)
167 | {
168 | return;
169 | }
170 |
171 | Language = lang;
172 | }
173 |
174 | private void ControllerOnOverlayFontChanged(bool fromView, Font font)
175 | {
176 | if (!fromView)
177 | {
178 | return;
179 | }
180 |
181 | OverlayFont = TypeDescriptor.GetConverter(typeof(Font)).ConvertToString(font);
182 | }
183 |
184 | private void ControllerOnTranslateProviderChanged(bool fromView, string provider, string apiKey, string langFrom, string langTo)
185 | {
186 | if (!fromView)
187 | {
188 | return;
189 | }
190 |
191 | TranslateProvider = provider;
192 | TranslateApiKey = apiKey;
193 | TranslateLangFrom = langFrom;
194 | TranslateLangTo = langTo;
195 | }
196 |
197 | private void ControllerOnProxyChanged(bool fromView, string type, string server, int port, string user,
198 | string password, string domain)
199 | {
200 | if (!fromView)
201 | {
202 | return;
203 | }
204 |
205 | ProxyType = type;
206 | ProxyServer = server;
207 | ProxyPort = port;
208 | ProxyUser = user;
209 | ProxyPassword = password;
210 | ProxyDomain = domain;
211 | }
212 |
213 | private void ControllerOnNewVersionIgnored(bool fromView, string ignoredVersion)
214 | {
215 | VersionIgnored = ignoredVersion;
216 | }
217 |
218 | private void ControllerOnShortcutChanged(bool fromView, PluginShortcut shortcut, Keys key)
219 | {
220 | if (!fromView)
221 | {
222 | return;
223 | }
224 |
225 | var ks = ShortkeyUtils.KeyToString(key);
226 | switch (shortcut)
227 | {
228 | case PluginShortcut.HideOverlay:
229 | ShortcutHide = ks;
230 | break;
231 | }
232 | }
233 |
234 | #endregion
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/TranslateService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using ACT.FFXIVTranslate.translate.baidu;
6 | using ACT.FFXIVTranslate.translate.google_unofficial;
7 | using ACT.FFXIVTranslate.translate.microsoft;
8 | using ACT.FFXIVTranslate.translate.tencent;
9 | using ACT.FFXIVTranslate.translate.yandax;
10 | using ACT.FFXIVTranslate.translate.youdao;
11 | using ACT.FoxCommon.core;
12 | using ACT.FoxCommon.localization;
13 |
14 | namespace ACT.FFXIVTranslate.translate
15 | {
16 |
17 | class TranslateService : IPluginComponent
18 | {
19 | private FFXIVTranslatePlugin _plugin;
20 | private MainController _controller;
21 |
22 | private readonly object _mainLock = new object();
23 | private readonly List _pendingLines = new List();
24 | private readonly TranslateThread _workingThread = new TranslateThread();
25 |
26 | private string TranslateProvider { get; set; }
27 | private string TranslateApiKey { get; set; }
28 | private string TranslateLangFrom { get; set; }
29 | private string TranslateLangTo { get; set; }
30 | private bool AddTimestamp { get; set; }
31 | private bool Timestamp24Hour { get; set; }
32 |
33 | public List AllProviders { get; } =
34 | new ITranslateProviderFactory[]
35 | {
36 | new YandaxTranslateProviderFactory(),
37 | new BaiduTranslateProviderFactory(),
38 | new MicrosoftTranslateProviderFactory(),
39 | new GoogleTranslateProviderFactory(),
40 | new YoudaoTranslateProviderFactory(),
41 | new TencentTranslateProviderFactory(),
42 | }.ToList();
43 |
44 | public void AttachToAct(FFXIVTranslatePlugin plugin)
45 | {
46 | _plugin = plugin;
47 | _controller = plugin.Controller;
48 | _controller.TranslateProviderChanged += ControllerOnTranslateProviderChanged;
49 | _controller.AddTimestampChanged += ControllerOnAddTimestampChanged;
50 | _controller.TimestampFormatChanged += ControllerOnTimestampFormatChanged;
51 | }
52 |
53 | public void PostAttachToAct(FFXIVTranslatePlugin plugin)
54 | {
55 | }
56 |
57 | private void ControllerOnTranslateProviderChanged(bool fromView, string provider, string apiKey,
58 | string langFrom,
59 | string langTo)
60 | {
61 | if (!fromView)
62 | {
63 | return;
64 | }
65 |
66 | TranslateProvider = provider;
67 | TranslateApiKey = apiKey;
68 | TranslateLangFrom = langFrom;
69 | TranslateLangTo = langTo;
70 |
71 | var factory = AllProviders.First(it => it.ProviderId == provider);
72 | var lF = langFrom == LanguageDef.CodeAuto
73 | ? null
74 | : factory.SupportedSrcLanguages.First(it => it.LangCode == langFrom);
75 | var lT = factory.GetSupportedDestLanguages(lF).First(it => it.LangCode == langTo);
76 | var context = new TranslateContext
77 | {
78 | Service = this,
79 | Provider = factory.CreateProvider(apiKey, lF, lT)
80 | };
81 |
82 | _controller.NotifyLegalInfoChanged(false, factory.LegalInfo);
83 | _workingThread.StartWorkingThread(context);
84 | }
85 |
86 | private void ControllerOnAddTimestampChanged(bool fromView, bool show)
87 | {
88 | AddTimestamp = show;
89 | }
90 |
91 | private void ControllerOnTimestampFormatChanged(bool fromView, bool is24Hour)
92 | {
93 | Timestamp24Hour = is24Hour;
94 | }
95 |
96 | public void SubmitNewLine(ChattingLine line)
97 | {
98 | lock (_mainLock)
99 | {
100 | _pendingLines.Add(line);
101 | Monitor.PulseAll(_mainLock);
102 | }
103 | }
104 |
105 | public void Stop()
106 | {
107 | _workingThread.StopWorkingThread();
108 | }
109 |
110 | private class TranslateContext
111 | {
112 | public TranslateService Service;
113 | public ITranslateProvider Provider;
114 | }
115 |
116 | private class TranslateThread : BaseThreading
117 | {
118 | private const int BatchThreshold = 10;
119 |
120 | protected override void DoWork(TranslateContext context)
121 | {
122 | var service = context.Service;
123 | var provider = context.Provider;
124 | int batchWait = 0;
125 | var batchWorkingList = new List();
126 | var availableLines = new List();
127 |
128 | while (!WorkingThreadStopping)
129 | {
130 | if (batchWorkingList.Count > BatchThreshold || (batchWait > 1 && batchWorkingList.Count > 0))
131 | {
132 | batchWait = 0;
133 | // Invoke translate service
134 |
135 | try
136 | {
137 | // Make sure we do have something to translate
138 | batchWorkingList.ForEach(it =>
139 | {
140 | if (provider.PreprocessLine(it))
141 | {
142 | availableLines.Add(it);
143 | }
144 | else
145 | {
146 | it.TranslatedContent = string.Empty;
147 | }
148 | });
149 | if (availableLines.Count != 0)
150 | {
151 | provider.Translate(availableLines);
152 | availableLines.Clear();
153 | }
154 |
155 | service._controller.NotifyBatchTranslateCompleted(false, new List(batchWorkingList));
156 |
157 | // Render overlay text
158 | var overlayContentRendered = TextProcessor.BuildRTF(
159 | service._plugin,
160 | service.AddTimestamp,
161 | service.Timestamp24Hour,
162 | batchWorkingList.Where(it => it.EventCode <= EventCode.Clipboard)); // Don't display test channels
163 |
164 | service._controller.NotifyOverlayContentUpdated(false, overlayContentRendered);
165 | }
166 | catch (Exception ex)
167 | {
168 | service._controller.NotifyLogMessageAppend(false, ex + "\n");
169 | }
170 | finally
171 | {
172 | batchWorkingList.Clear();
173 | }
174 | }
175 | else
176 | {
177 | lock (service._mainLock)
178 | {
179 | if (service._pendingLines.Count > 0)
180 | {
181 | batchWait = 0;
182 | batchWorkingList.AddRange(service._pendingLines);
183 | service._pendingLines.Clear();
184 | }
185 | else
186 | {
187 | if (batchWorkingList.Count > 0)
188 | {
189 | batchWait++;
190 | }
191 | Monitor.Wait(service._mainLock, 500);
192 | }
193 | }
194 | }
195 | }
196 | }
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/RTFLib/RTF/RTFBuilder.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | //using CurrentPatient.Properties;
5 |
6 |
7 | namespace RTF
8 | {
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Drawing;
12 | using System.Text;
13 |
14 |
15 | // ----------------------------------------------------------------------------------------
16 | // _ ___ _..-._ Date: 12/11/08 23:34
17 | // \`.|\..----...-'` `-._.-'' _.-..'
18 | // / ' ` , __.-''
19 | // )/` _/ \ `-_, / Solution: RTFLib
20 | // `-'" `"\_ ,_.-;_.-\_ ', Project : RTFLib
21 | // _.-'_./ {_.' ; / Author : Anton
22 | // {_.-``-' {_/ Assembly: 1.0.0.0
23 | // Copyright © 2005-2008, Rogue Trader/MWM
24 | // Project Item Name: RTFBuilder.cs - Code
25 | // Purpose: Rich Text Generator
26 | // ----------------------------------------------------------------------------------------
27 | ///
28 | /// Rich Text Generator
29 | ///
30 | public partial class RTFBuilder : RTFBuilderbase
31 | {
32 | #region Fields
33 |
34 | private static readonly char[] slashable = new[] {'{', '}', '\\'};
35 |
36 | private readonly StringBuilder _sb;
37 |
38 | #endregion
39 |
40 | #region Constructor
41 |
42 | public RTFBuilder()
43 | : base(RTFFont.Arial , 20F)
44 | {
45 | this._sb = new StringBuilder();
46 | }
47 |
48 | public RTFBuilder(RTFFont defaultFont) : base(defaultFont, 20F)
49 | {
50 | this._sb = new StringBuilder();
51 | }
52 |
53 | public RTFBuilder(float defaultFontSize) : base(RTFFont.Arial, defaultFontSize)
54 | {
55 | this._sb = new StringBuilder();
56 | }
57 |
58 | public RTFBuilder(RTFFont defaultFont, float defaultFontSize) : base(defaultFont, defaultFontSize)
59 | {
60 | this._sb = new StringBuilder();
61 | }
62 |
63 | #endregion
64 |
65 | #region Override Methods
66 |
67 | protected override void AppendInternal(string value)
68 | {
69 | if (!string.IsNullOrEmpty(value))
70 | {
71 | using (new RTFFormatWrap(this))
72 | {
73 | value = this.CheckChar(value);
74 | if (value.IndexOf(Environment.NewLine) >= 0)
75 | {
76 | string[] lines = value.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
77 | foreach (string line in lines)
78 | {
79 | this._sb.Append(line);
80 | this._sb.Append("\\line ");
81 | }
82 | }
83 | else
84 | {
85 | this._sb.Append(value);
86 | }
87 | }
88 | }
89 | }
90 |
91 | protected override void AppendLevelInternal(int level)
92 | {
93 | this._sb.AppendFormat("\\level{0} ", level);
94 | }
95 |
96 | protected override void AppendLineInternal(string value)
97 | {
98 | using (new RTFParaWrap(this))
99 | {
100 | Append(value);
101 | this._sb.AppendLine("\\line");
102 | }
103 | }
104 |
105 | protected override void AppendLineInternal()
106 | {
107 | this._sb.AppendLine("\\line");
108 | }
109 |
110 | protected override void AppendPageInternal()
111 | {
112 | using (new RTFParaWrap(this))
113 | {
114 | this._sb.AppendLine("\\page");
115 | }
116 | }
117 |
118 | protected override void AppendParaInternal()
119 | {
120 | using (new RTFParaWrap(this))
121 | {
122 | this._sb.AppendLine("\\par ");
123 | }
124 | }
125 |
126 | protected override void AppendRTFInternal(string rtf)
127 | {
128 | if (!string.IsNullOrEmpty(rtf))
129 | {
130 | this._sb.Append(rtf);
131 | }
132 | }
133 |
134 | protected override IEnumerable EnumerateCellsInternal(RTFRowDefinition rowDefinition, RTFCellDefinition[] cellDefinitions)
135 | {
136 | using (IRTFRow ie = this.CreateRow(rowDefinition, cellDefinitions))
137 | {
138 | IEnumerator ie2 = ie.GetEnumerator();
139 | while (ie2.MoveNext())
140 | {
141 | using (IBuilderContent item = ie2.Current)
142 | {
143 | yield return item.Content;
144 | }
145 | }
146 | }
147 | }
148 |
149 | public override IDisposable FormatLock()
150 | {
151 | return new RTFBuilderUnWrapped(this);
152 | }
153 |
154 | protected override void InsertImageInternal(Image image)
155 | {
156 | try
157 | {
158 | RTFImage rti = new RTFImage(this);
159 | rti.InsertImage(image);
160 | }
161 | catch
162 | {
163 | this._sb.AppendLine("[Insert image error]");
164 | }
165 | }
166 |
167 | protected override int LengthInternal()
168 | {
169 | throw new NotImplementedException();
170 | }
171 |
172 | protected override void ResetInternal()
173 | {
174 | this._sb.AppendLine("\\pard");
175 | }
176 |
177 | public override string ToString()
178 | {
179 | StringBuilder sb = new StringBuilder();
180 | sb.Append("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang3081");
181 | // sb.Append("{\\fonttbl");
182 | //
183 | //
184 | // for (int i = 0; i < _rawFonts.Count; i++)
185 | // {
186 | //
187 | // try
188 | // {
189 | // sb.Append(string.Format(_rawFonts[i], i));
190 | // }
191 | // catch (Exception ex )
192 | // {
193 | //
194 | // Console.WriteLine(ex.Message );
195 | // }
196 | //
197 | // }
198 | //
199 | // sb.AppendLine("}");
200 |
201 | sb.Append("{\\colortbl ;");
202 |
203 | foreach (Color item in _colortbl)
204 | {
205 | sb.AppendFormat("\\red{0}\\green{1}\\blue{2};", item.R, item.G, item.B);
206 | }
207 |
208 | sb.AppendLine("}");
209 |
210 |
211 | // sb.Append("\\viewkind4\\uc1\\pard\\plain\\f0");
212 |
213 | // sb.AppendFormat("\\fs{0} ", DefaultFontSize);
214 | sb.AppendLine();
215 |
216 | sb.Append(this._sb.ToString());
217 | sb.Append("}");
218 |
219 |
220 | return sb.ToString();
221 | }
222 |
223 | #endregion
224 |
225 | #region Public Methods
226 |
227 | public IRTFRow CreateRow(RTFRowDefinition rowDefinition, RTFCellDefinition[] cellDefinitions)
228 | {
229 | return new RTFRow(this, rowDefinition, cellDefinitions);
230 | }
231 |
232 | #endregion
233 |
234 | #region Methods
235 |
236 | ///
237 | /// Checks the char.
238 | ///
239 | /// The value.
240 | ///
241 | private string CheckChar(string value)
242 | {
243 | if (!string.IsNullOrEmpty(value))
244 | {
245 | if (value.IndexOfAny(slashable) >= 0)
246 | {
247 | value = value.Replace("{", "\\{").Replace("}", "\\}").Replace("\\", "\\\\");
248 | }
249 | bool replaceuni = false;
250 | for (int i = 0; i < value.Length; i++)
251 | {
252 | if (value[i] > 255)
253 | {
254 | replaceuni = true;
255 | break;
256 | }
257 | }
258 | if (replaceuni)
259 | {
260 | StringBuilder sb = new StringBuilder();
261 |
262 | for (int i = 0; i < value.Length; i++)
263 | {
264 | if (value[i] <= 255)
265 | {
266 | sb.Append(value[i]);
267 | }
268 | else
269 | {
270 | sb.Append("\\u");
271 | sb.Append((int) value[i]);
272 | sb.Append("?");
273 | }
274 | }
275 | value = sb.ToString();
276 | }
277 | }
278 |
279 |
280 | return value;
281 | }
282 |
283 | #endregion
284 | }
285 | }
286 |
287 |
--------------------------------------------------------------------------------
/ACT.FFXIVTranslate/ACT.FFXIVTranslate/translate/tencent/TencentTranslateProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Net.Http;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 | using ACT.FoxCommon.localization;
9 | using Newtonsoft.Json;
10 | using Newtonsoft.Json.Linq;
11 |
12 | namespace ACT.FFXIVTranslate.translate.tencent
13 | {
14 | internal class TencentTranslateProvider : DefaultTranslateProvider
15 | {
16 | private const string SERVICE = "tmt";
17 | private const string HOST = SERVICE + ".tencentcloudapi.com";
18 | private const string ALGORITHM = "TC3-HMAC-SHA256";
19 |
20 | private readonly string _secretId;
21 | private readonly string _secretKey;
22 | private readonly string _langFrom;
23 | private readonly string _langTo;
24 |
25 | public TencentTranslateProvider(string apiKey, LanguageDef src, LanguageDef dst)
26 | {
27 | var kp = apiKey.Split(':');
28 | if (kp.Length < 2)
29 | {
30 | _secretId = "";
31 | _secretKey = "";
32 | }
33 | else
34 | {
35 | _secretId = kp[0];
36 | _secretKey = kp[1];
37 | }
38 |
39 | _langFrom = src?.LangCode ?? "auto";
40 | _langTo = dst.LangCode;
41 | }
42 |
43 | public override void Translate(List chattingLines)
44 | {
45 | try
46 | {
47 | // Build request json
48 | var query = new Dictionary();
49 | query["Source"] = _langFrom;
50 | query["Target"] = _langTo;
51 | query["ProjectId"] = 0;
52 | query["SourceTextList"] = chattingLines.Select(it => it.CleanedContent).ToList();
53 |
54 | var queryBody = JsonConvert.SerializeObject(query, Formatting.None);
55 |
56 | // Calculate signature, based on https://cloud.tencent.com/document/api/551/30636
57 | // and https://github.com/TencentCloud/tencentcloud-sdk-dotnet/blob/376182fa16beefb19d09cd6bceae536689b62978/TencentCloud/Common/AbstractClient.cs#L234
58 |
59 | var timestamp = ToTimestamp() / 1000;
60 | var date = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp)
61 | .ToString("yyyy-MM-dd");
62 | var credentialScope = $"{date}/{SERVICE}/tc3_request";
63 |
64 | // 1. Build CanonicalRequest
65 | var canonicalRequest =
66 | $"POST\n" +
67 | $"/\n" +
68 | $"\n" +
69 | $"content-type:application/json; charset=utf-8\n" +
70 | $"host:{HOST}\n" +
71 | $"\n" +
72 | $"content-type;host\n" +
73 | $"{SHA256Hex(queryBody)}";
74 |
75 | // 2. Build StringToSign
76 | var stringToSign =
77 | $"{ALGORITHM}\n" +
78 | $"{timestamp}\n" +
79 | $"{credentialScope}\n" +
80 | $"{SHA256Hex(canonicalRequest)}";
81 |
82 | // 3. Calculate Signature
83 | var tc3SecretKey = Encoding.UTF8.GetBytes("TC3" + _secretKey);
84 | var secretDate = HmacSHA256(tc3SecretKey, Encoding.UTF8.GetBytes(date));
85 | var secretService = HmacSHA256(secretDate, Encoding.UTF8.GetBytes(SERVICE));
86 | var secretSigning = HmacSHA256(secretService, Encoding.UTF8.GetBytes("tc3_request"));
87 | var signatureBytes = HmacSHA256(secretSigning, Encoding.UTF8.GetBytes(stringToSign));
88 | var signature = BitConverter.ToString(signatureBytes).Replace("-", "").ToLower();
89 |
90 | // 4. Build Authorization
91 | var authorization =
92 | $"{ALGORITHM} Credential={_secretId}/{credentialScope}, SignedHeaders=content-type;host, Signature={signature}";
93 |
94 | // Build headers
95 | var headers = new Dictionary();
96 | headers["Authorization"] = authorization;
97 | headers["Host"] = HOST;
98 | headers["Content-Type"] = "application/json; charset=utf-8";
99 | headers["X-TC-Action"] = "TextTranslateBatch";
100 | headers["X-TC-Timestamp"] = timestamp.ToString();
101 | headers["X-TC-Version"] = "2018-03-21";
102 | headers["X-TC-Region"] = "ap-shanghai";
103 |
104 | // Make http request
105 | string textResponse;
106 | using (var client = ProxyFactory.Instance.NewClient())
107 | using (var request = new HttpRequestMessage(HttpMethod.Post, "/"))
108 | {
109 | client.BaseAddress = new Uri($"https://{HOST}");
110 |
111 | request.Content = new StringContent(queryBody, Encoding.UTF8, "application/json");
112 | foreach (var header in headers)
113 | {
114 | request.Headers.TryAddWithoutValidation(header.Key, header.Value);
115 | }
116 |
117 | var response = client.SendAsync(request).Result;
118 | response.EnsureSuccessStatusCode();
119 | textResponse = response.Content.ReadAsStringAsync().Result;
120 | Debug.WriteLine(textResponse);
121 | }
122 |
123 | // read json
124 | var result = (JObject) JObject.Parse(textResponse)["Response"];
125 | var error = (JObject) result["Error"];
126 | if (error != null)
127 | {
128 | // handle error
129 | var errorCode = (string) error["Code"];
130 | var errorMessage = (string) error["Message"];
131 |
132 | if (errorCode.StartsWith("AuthFailure."))
133 | {
134 | throw new TranslateException(TranslateException.ExceptionReason.InvalidApiKey,
135 | errorCode + ": " + errorMessage,
136 | null);
137 | }
138 |
139 | switch (errorCode)
140 | {
141 | case "LimitExceeded":
142 | case "RequestLimitExceeded":
143 | throw new TranslateException(TranslateException.ExceptionReason.ApiLimitExceed,
144 | errorCode + ": " + errorMessage, null);
145 |
146 | case "UnsupportedOperation.UnSupportedTargetLanguage":
147 | case "UnsupportedOperation.UnsupportedLanguage":
148 | case "UnsupportedOperation.UnsupportedSourceLanguage":
149 | throw new TranslateException(TranslateException.ExceptionReason.DirectionNotSupported,
150 | errorCode + ": " + errorMessage, null);
151 |
152 | case "UnsupportedOperation.TextTooLong":
153 | throw new TranslateException(TranslateException.ExceptionReason.InternalError,
154 | errorCode + ": " + errorMessage, null);
155 |
156 | default:
157 | throw new TranslateException(TranslateException.ExceptionReason.GeneralServiceError,
158 | textResponse, null);
159 | }
160 | }
161 |
162 | var translation = (JArray) result["TargetTextList"];
163 | if (translation.Count >= chattingLines.Count)
164 | {
165 | for (var i = 0; i < chattingLines.Count; i++)
166 | {
167 | chattingLines[i].TranslatedContent = (string) translation[i];
168 | }
169 | }
170 | else
171 | {
172 | // TODO: Oops!
173 | }
174 | }
175 | catch (TranslateException)
176 | {
177 | throw;
178 | }
179 | catch (Exception ex)
180 | {
181 | throw new TranslateException(TranslateException.ExceptionReason.UnknownError, null, ex);
182 | }
183 | }
184 |
185 | #region Helper functions
186 |
187 | // https://github.com/TencentCloud/tencentcloud-sdk-dotnet/blob/376182fa16beefb19d09cd6bceae536689b62978/TencentCloud/Common/Sign.cs
188 |
189 | private static string SHA256Hex(string s)
190 | {
191 | using (SHA256 algo = SHA256.Create())
192 | {
193 | byte[] hashbytes = algo.ComputeHash(Encoding.UTF8.GetBytes(s));
194 | StringBuilder builder = new StringBuilder();
195 | for (int i = 0; i < hashbytes.Length; ++i)
196 | {
197 | builder.Append(hashbytes[i].ToString("x2"));
198 | }
199 | return builder.ToString();
200 | }
201 | }
202 |
203 | private static byte[] HmacSHA256(byte[] key, byte[] msg)
204 | {
205 | using (HMACSHA256 mac = new HMACSHA256(key))
206 | {
207 | return mac.ComputeHash(msg);
208 | }
209 | }
210 |
211 | // https://github.com/TencentCloud/tencentcloud-sdk-dotnet/blob/376182fa16beefb19d09cd6bceae536689b62978/TencentCloud/Common/AbstractClient.cs#L472
212 | private static long ToTimestamp()
213 | {
214 | DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
215 | DateTime nowTime = DateTime.Now;
216 | long unixTime = (long)Math.Round((nowTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero);
217 | return unixTime;
218 | }
219 |
220 | #endregion
221 |
222 | }
223 | }
224 |
--------------------------------------------------------------------------------