-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
2,350 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.1.32328.378 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SwordAndFairy7Translator", "SwordAndFairy7Translator\SwordAndFairy7Translator.csproj", "{2481D2E1-9A7C-40DC-932B-7633252E7B09}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ethereality", "D:\code\Ethereality\Ethereality\Ethereality.csproj", "{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Éléments de solution", "Éléments de solution", "{2A2BCC1F-F43E-4C51-A0FE-7595AAA92526}" | ||
ProjectSection(SolutionItems) = preProject | ||
.gitignore = .gitignore | ||
EndProjectSection | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Debug|x64 = Debug|x64 | ||
Release|Any CPU = Release|Any CPU | ||
Release|x64 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Debug|x64.ActiveCfg = Debug|x64 | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Debug|x64.Build.0 = Debug|x64 | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Release|x64.ActiveCfg = Release|x64 | ||
{2481D2E1-9A7C-40DC-932B-7633252E7B09}.Release|x64.Build.0 = Release|x64 | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Debug|x64.ActiveCfg = Debug|x64 | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Debug|x64.Build.0 = Debug|x64 | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Release|x64.ActiveCfg = Release|x64 | ||
{21CEA71C-F222-4FF1-8FC5-C1C0B0180A6E}.Release|x64.Build.0 = Release|x64 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {01FF3FD6-39EA-401F-8F25-36D349B2B195} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Application x:Class="SwordAndFairy7Translator.App" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:local="clr-namespace:SwordAndFairy7Translator" | ||
StartupUri="MainWindow.xaml"> | ||
<Application.Resources> | ||
<ResourceDictionary> | ||
|
||
<ResourceDictionary.MergedDictionaries> | ||
<ResourceDictionary Source="pack://application:,,,/Ethereality;component/Ethereality.xaml" /> | ||
<ResourceDictionary Source="Views/TranslatorServiceConfigViews.xaml" /> | ||
</ResourceDictionary.MergedDictionaries> | ||
|
||
</ResourceDictionary> | ||
</Application.Resources> | ||
</Application> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using SwordAndFairy7Translator.Views.StartupDialog; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Configuration; | ||
using System.Data; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using System.Windows; | ||
|
||
namespace SwordAndFairy7Translator | ||
{ | ||
/// <summary> | ||
/// Interaction logic for App.xaml | ||
/// </summary> | ||
public partial class App : Application | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System.Windows; | ||
|
||
[assembly: ThemeInfo( | ||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located | ||
//(used if a resource is not found in the page, | ||
// or application resource dictionaries) | ||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located | ||
//(used if a resource is not found in the page, | ||
// app, or any theme specific resource dictionaries) | ||
)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
using PostSharp.Patterns.Model; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Net.Http; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using System.Web; | ||
using System.Windows; | ||
|
||
namespace SwordAndFairy7Translator; | ||
|
||
[NotifyPropertyChanged] | ||
public class AzureTranslator : ITranslatorService | ||
{ | ||
private static readonly string endpoint = "https://api.cognitive.microsofttranslator.com/"; | ||
|
||
private IEnumerable<Language>? languages; | ||
|
||
[SafeForDependencyAnalysis] | ||
public string? Key { get => Settings.Default.AzureAPIKey; set => Settings.Default.AzureAPIKey = value; } | ||
[SafeForDependencyAnalysis] | ||
public string? Region { get => Settings.Default.AzureRegion; set => Settings.Default.AzureRegion = value; } | ||
|
||
public string Name => "Microsoft Azure"; | ||
|
||
[SafeForDependencyAnalysis] | ||
public IEnumerable<Language>? Languages | ||
{ | ||
get | ||
{ | ||
if (languages is null) | ||
{ | ||
Task.Run(async () => | ||
{ | ||
using var client = new HttpClient(); | ||
using var request = new HttpRequestMessage | ||
{ | ||
Method = HttpMethod.Get, | ||
RequestUri = new Uri("https://api.cognitive.microsofttranslator.com/languages?api-version=3.0"), | ||
}; | ||
var response = await client.SendAsync(request).ConfigureAwait(false); | ||
var result = await response.Content.ReadAsStringAsync(); | ||
|
||
var json = JObject.Parse(result); | ||
Dictionary<string, Language> langs = JsonConvert.DeserializeObject<Dictionary<string, Language>>(json["translation"]!.ToString())!; | ||
foreach (var (k, v) in langs) | ||
v.Code = k; | ||
languages = langs.Values.AsEnumerable(); | ||
}); | ||
} | ||
return languages; | ||
} | ||
} | ||
public async Task<IEnumerable<string>> TranslateAsync(string from, params string[] textToTranslate) | ||
{ | ||
if (string.IsNullOrEmpty(Key)) return Enumerable.Empty<string>(); | ||
|
||
// split strings in substrings with or without html tags | ||
var allMStrings = textToTranslate | ||
.Select(text => TranslatorServiceHelper.GetMStrings(text)) | ||
.ToArray(); | ||
|
||
// Filter strings with html tags and those who don't have text to translate | ||
var toTranslateMStrings = allMStrings | ||
.SelectMany(x => x) | ||
.Where(x => !Regex.IsMatch(x.Text, @"<[^>]+>") && Regex.IsMatch(x.Text, @"\p{L}")) | ||
.ToArray(); | ||
|
||
// Create Chunks of 40k characters max | ||
var chunks = new List<List<TranslatorServiceHelper.MString>> | ||
{ | ||
new() | ||
}; | ||
foreach (var str in toTranslateMStrings) | ||
{ | ||
if (chunks.Last().Count >= 1000 || chunks.Last().Sum(x => x.Text.Length) + str.Text.Length > 40000) | ||
chunks.Add(new()); | ||
chunks.Last().Add(str); | ||
} | ||
|
||
// Translate using Azure | ||
foreach (var body in chunks) | ||
{ | ||
try | ||
{ | ||
var requestBody = JsonConvert.SerializeObject(body); | ||
|
||
using var client = new HttpClient(); | ||
using var request = new HttpRequestMessage | ||
{ | ||
Method = HttpMethod.Post, | ||
RequestUri = new Uri($"{endpoint}translate?api-version=3.0&from={from}&to={Settings.Default.TargetLanguage}"), | ||
Content = new StringContent(requestBody, Encoding.UTF8, "application/json"), | ||
}; | ||
request.Headers.Add("Ocp-Apim-Subscription-Key", Key); | ||
request.Headers.Add("Ocp-Apim-Subscription-Region", Region); | ||
|
||
var response = await client.SendAsync(request).ConfigureAwait(false); | ||
var result = await response.Content.ReadAsStringAsync(); | ||
|
||
var json = JToken.Parse(result); | ||
if (json.Type == JTokenType.Object) | ||
{ | ||
|
||
if (((JObject)json).ContainsKey("error")) | ||
throw new ApplicationException((string)json["error"]!["message"]!); | ||
} | ||
else if (json.Type == JTokenType.Array) | ||
{ | ||
var tr = json.Select(j => j["translations"]![0]!["text"]!.Value<string>()!); | ||
foreach (var (t, ms) in tr.Zip(body)) | ||
{ | ||
ms.Text = t; | ||
} | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
MessageBox.Show(e.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); | ||
} | ||
} | ||
|
||
// Rebuild strings | ||
var translations = allMStrings | ||
.Select(x => string.Join("", x.Select(t => t.Text))) | ||
.ToArray(); | ||
|
||
return translations; | ||
} | ||
|
||
public async Task<bool> TestAsync() | ||
{ | ||
try | ||
{ | ||
_ = await TranslateAsync(from: "en", "Hello, World!"); | ||
return true; | ||
} | ||
catch (Exception) | ||
{ | ||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using System.Windows; | ||
using DeepL; | ||
using PostSharp.Patterns.Model; | ||
|
||
namespace SwordAndFairy7Translator | ||
{ | ||
[NotifyPropertyChanged] | ||
public class DeepLTranslator : ITranslatorService, INotifyPropertyChanged | ||
{ | ||
public event PropertyChangedEventHandler? PropertyChanged; | ||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null!) | ||
=> PropertyChanged?.Invoke(this, new(propertyName)); | ||
|
||
private IEnumerable<Language>? languages; | ||
|
||
public string Name => "DeepL"; | ||
|
||
[SafeForDependencyAnalysis] | ||
public string? Key | ||
{ | ||
get => Settings.Default.DeepLAPIKey; | ||
set | ||
{ | ||
Settings.Default.DeepLAPIKey = value; | ||
OnPropertyChanged(nameof(Languages)); | ||
} | ||
} | ||
[SafeForDependencyAnalysis] | ||
public bool UseFreeApi { | ||
get => Settings.Default.DeepLUseFreeApi; | ||
set | ||
{ | ||
Settings.Default.DeepLUseFreeApi = value; | ||
OnPropertyChanged(nameof(Languages)); | ||
} | ||
} | ||
|
||
[SafeForDependencyAnalysis] | ||
public IEnumerable<Language>? Languages | ||
{ | ||
get | ||
{ | ||
if (languages is null) | ||
{ | ||
Task.Run(async () => | ||
{ | ||
if (!await TestAsync()) return; | ||
using var deepl = new DeepLClient(Key, UseFreeApi); | ||
var langs = await deepl.GetSupportedLanguagesAsync(); | ||
languages = langs | ||
.Select(l => new Language | ||
{ | ||
Code = l.LanguageCode.ToLower(), | ||
Name = l.Name, | ||
}); | ||
}); | ||
} | ||
return languages; | ||
} | ||
} | ||
|
||
public async Task<bool> TestAsync() | ||
{ | ||
using var deepl = new DeepLClient(Key, UseFreeApi); | ||
try | ||
{ | ||
await deepl.TranslateAsync("Hello, World!", Settings.Default.TargetLanguage); | ||
return true; | ||
} | ||
catch | ||
{ | ||
return false; | ||
} | ||
|
||
} | ||
|
||
public async Task<IEnumerable<string>> TranslateAsync(string from, params string[] texts) | ||
{ | ||
if (string.IsNullOrEmpty(Key)) return Enumerable.Empty<string>(); | ||
|
||
// split strings in substrings with or without html tags | ||
var allMStrings = texts | ||
.Select(text => TranslatorServiceHelper.GetMStrings(text)) | ||
.ToArray(); | ||
|
||
// Filter strings with html tags and those who don't have text to translate | ||
var toTranslateMStrings = allMStrings | ||
.SelectMany(x => x) | ||
.Where(x => !Regex.IsMatch(x.Text, @"<[^>]+>") && Regex.IsMatch(x.Text, @"\p{L}")) | ||
.ToArray(); | ||
|
||
// Create Chunks of 40k characters max | ||
var chunks = new List<List<TranslatorServiceHelper.MString>> | ||
{ | ||
new() | ||
}; | ||
foreach (var str in toTranslateMStrings) | ||
{ | ||
if (chunks.Last().Count >= 50 || chunks.Last().Sum(x => x.Text.Length) + str.Text.Length > 5000) | ||
chunks.Add(new()); | ||
chunks.Last().Add(str); | ||
} | ||
|
||
using var deepl = new DeepLClient(Key, UseFreeApi); | ||
// Translate using Azure | ||
foreach (var body in chunks) | ||
{ | ||
try | ||
{ | ||
var tr = await deepl.TranslateAsync(body.Select(b => b.Text), Settings.Default.TargetLanguage); | ||
foreach (var (t, ms) in tr.Zip(body)) | ||
{ | ||
ms.Text = t.Text; | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
MessageBox.Show(e.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); | ||
} | ||
} | ||
|
||
// Rebuild strings | ||
var translations = allMStrings | ||
.Select(x => string.Join("", x.Select(t => t.Text))) | ||
.ToArray(); | ||
|
||
return translations; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[DerivedDataBackendGraph] | ||
Root=(Type=KeyLength, Length=120, Inner=AsyncPut) | ||
AsyncPut=(Type=AsyncPut, Inner=Hierarchy) | ||
Hierarchy=(Type=Hierarchical, Inner=Boot, Inner=Pak, Inner=EnginePak, Inner=Local, Inner=Shared) | ||
Local=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, PurgeTransient=true, DeleteUnused=true, UnusedFileAge=34, FoldersToClean=-1, PromptIfMissing=true, Path=%ENGINEDIR%DerivedDataCache, EnvPathOverride=UE-LocalDataCachePath, EditorOverrideSetting=LocalDerivedDataCache) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
using PostSharp.Patterns.Model; | ||
|
||
[assembly: NotifyPropertyChanged(AttributeTargetTypes = "*ViewModel")] |
Oops, something went wrong.