Browse Source

Translator fixes.

pull/613/head
Sebastian 5 years ago
parent
commit
2d2e51f4ff
  1. 2
      backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj
  2. 101
      backend/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs
  3. 14
      backend/src/Squidex.Infrastructure/Translations/DeepLTranslatorOptions.cs
  4. 17
      backend/src/Squidex.Infrastructure/Translations/ITranslator.cs
  5. 22
      backend/src/Squidex.Infrastructure/Translations/NoopTranslator.cs
  6. 25
      backend/src/Squidex.Infrastructure/Translations/Translation.cs
  7. 18
      backend/src/Squidex.Infrastructure/Translations/TranslationResult.cs
  8. 5
      backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs
  9. 3
      backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs
  10. 15
      backend/src/Squidex/Config/Domain/InfrastructureServices.cs
  11. 9
      backend/src/Squidex/appsettings.json

2
backend/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj

@ -30,7 +30,7 @@
<PackageReference Include="Squidex.Assets" Version="1.3.0" /> <PackageReference Include="Squidex.Assets" Version="1.3.0" />
<PackageReference Include="Squidex.Caching" Version="1.1.0" /> <PackageReference Include="Squidex.Caching" Version="1.1.0" />
<PackageReference Include="Squidex.Log" Version="1.1.0" /> <PackageReference Include="Squidex.Log" Version="1.1.0" />
<PackageReference Include="Squidex.Text" Version="1.1.0" /> <PackageReference Include="Squidex.Text" Version="1.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" /> <PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />

101
backend/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs

@ -1,101 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Json;
namespace Squidex.Infrastructure.Translations
{
[ExcludeFromCodeCoverage]
public sealed class DeepLTranslator : ITranslator
{
private const string Url = "https://api.deepl.com/v2/translate";
private readonly HttpClient httpClient = new HttpClient();
private readonly DeepLTranslatorOptions deeplOptions;
private readonly IJsonSerializer jsonSerializer;
private sealed class Response
{
public ResponseTranslation[] Translations { get; set; }
}
private sealed class ResponseTranslation
{
public string Text { get; set; }
}
public DeepLTranslator(IOptions<DeepLTranslatorOptions> deeplOptions, IJsonSerializer jsonSerializer)
{
Guard.NotNull(deeplOptions, nameof(deeplOptions));
Guard.NotNull(jsonSerializer, nameof(jsonSerializer));
this.deeplOptions = deeplOptions.Value;
this.jsonSerializer = jsonSerializer;
}
public async Task<Translation> Translate(string sourceText, Language targetLanguage, Language? sourceLanguage = null, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(sourceText) || targetLanguage == null)
{
return new Translation(TranslationResult.NotTranslated, sourceText);
}
if (string.IsNullOrWhiteSpace(deeplOptions.AuthKey))
{
return new Translation(TranslationResult.NotImplemented);
}
var parameters = new Dictionary<string, string>
{
["auth_key"] = deeplOptions.AuthKey,
["text"] = sourceText,
["target_lang"] = GetLanguageCode(targetLanguage)
};
if (sourceLanguage != null)
{
parameters["source_lang"] = GetLanguageCode(sourceLanguage);
}
var body = new FormUrlEncodedContent(parameters!);
using (var response = await httpClient.PostAsync(Url, body, ct))
{
var responseString = await response.Content.ReadAsStringAsync(ct);
if (response.IsSuccessStatusCode)
{
var result = jsonSerializer.Deserialize<Response>(responseString);
if (result?.Translations?.Length == 1)
{
return new Translation(TranslationResult.Translated, result.Translations[0].Text);
}
}
if (response.StatusCode == HttpStatusCode.BadRequest)
{
return new Translation(TranslationResult.LanguageNotSupported, resultText: responseString);
}
return new Translation(TranslationResult.Failed, resultText: responseString);
}
}
private static string GetLanguageCode(Language language)
{
return language.Iso2Code.Substring(0, 2).ToUpperInvariant();
}
}
}

14
backend/src/Squidex.Infrastructure/Translations/DeepLTranslatorOptions.cs

@ -1,14 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Translations
{
public sealed class DeepLTranslatorOptions
{
public string? AuthKey { get; set; }
}
}

17
backend/src/Squidex.Infrastructure/Translations/ITranslator.cs

@ -1,17 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
namespace Squidex.Infrastructure.Translations
{
public interface ITranslator
{
Task<Translation> Translate(string sourceText, Language targetLanguage, Language? sourceLanguage = null, CancellationToken ct = default);
}
}

22
backend/src/Squidex.Infrastructure/Translations/NoopTranslator.cs

@ -1,22 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading;
using System.Threading.Tasks;
namespace Squidex.Infrastructure.Translations
{
public sealed class NoopTranslator : ITranslator
{
public Task<Translation> Translate(string sourceText, Language targetLanguage, Language? sourceLanguage = null, CancellationToken ct = default)
{
var result = new Translation(TranslationResult.NotImplemented);
return Task.FromResult(result);
}
}
}

25
backend/src/Squidex.Infrastructure/Translations/Translation.cs

@ -1,25 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Translations
{
public sealed class Translation
{
public TranslationResult Result { get; }
public string? Text { get; }
public string? ResultText { get; set; }
public Translation(TranslationResult result, string? text = null, string? resultText = null)
{
Text = text;
Result = result;
ResultText = resultText;
}
}
}

18
backend/src/Squidex.Infrastructure/Translations/TranslationResult.cs

@ -1,18 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Translations
{
public enum TranslationResult
{
Translated,
LanguageNotSupported,
NotTranslated,
NotImplemented,
Failed
}
}

5
backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs

@ -7,6 +7,7 @@
using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Text.Translations;
namespace Squidex.Areas.Api.Controllers.Translations.Models namespace Squidex.Areas.Api.Controllers.Translations.Models
{ {
@ -15,14 +16,14 @@ namespace Squidex.Areas.Api.Controllers.Translations.Models
/// <summary> /// <summary>
/// The result of the translation. /// The result of the translation.
/// </summary> /// </summary>
public TranslationResult Result { get; set; } public TranslationResultCode Result { get; set; }
/// <summary> /// <summary>
/// The translated text. /// The translated text.
/// </summary> /// </summary>
public string? Text { get; set; } public string? Text { get; set; }
public static TranslationDto FromTranslation(Translation translation) public static TranslationDto FromTranslation(TranslationResult translation)
{ {
return SimpleMapper.Map(translation, new TranslationDto()); return SimpleMapper.Map(translation, new TranslationDto());
} }

3
backend/src/Squidex/Areas/Api/Controllers/Translations/TranslationsController.cs

@ -11,6 +11,7 @@ using Squidex.Areas.Api.Controllers.Translations.Models;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Shared; using Squidex.Shared;
using Squidex.Text.Translations;
using Squidex.Web; using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Translations namespace Squidex.Areas.Api.Controllers.Translations
@ -44,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Translations
[ApiCosts(0)] [ApiCosts(0)]
public async Task<IActionResult> PostTranslation(string app, [FromBody] TranslateDto request) public async Task<IActionResult> PostTranslation(string app, [FromBody] TranslateDto request)
{ {
var result = await translator.Translate(request.Text, request.TargetLanguage, request.SourceLanguage, HttpContext.RequestAborted); var result = await translator.TranslateAsync(request.Text, request.TargetLanguage, request.SourceLanguage, HttpContext.RequestAborted);
var response = TranslationDto.FromTranslation(result); var response = TranslationDto.FromTranslation(result);
return Ok(response); return Ok(response);

15
backend/src/Squidex/Config/Domain/InfrastructureServices.cs

@ -9,6 +9,7 @@ using System;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NodaTime; using NodaTime;
using Orleans; using Orleans;
using Squidex.Areas.Api.Controllers.Contents.Generator; using Squidex.Areas.Api.Controllers.Contents.Generator;
@ -31,6 +32,8 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.UsageTracking; using Squidex.Infrastructure.UsageTracking;
using Squidex.Pipeline.Robots; using Squidex.Pipeline.Robots;
using Squidex.Text.Translations;
using Squidex.Text.Translations.GoogleCloud;
using Squidex.Web; using Squidex.Web;
using Squidex.Web.Pipeline; using Squidex.Web.Pipeline;
@ -120,15 +123,23 @@ namespace Squidex.Config.Domain
public static void AddSquidexTranslation(this IServiceCollection services, IConfiguration config) public static void AddSquidexTranslation(this IServiceCollection services, IConfiguration config)
{ {
services.Configure<DeepLTranslatorOptions>( services.Configure<DeepLOptions>(
config.GetSection("translations:deepL")); config.GetSection("translations:deepL"));
services.Configure<GoogleCloudTranslationOptions>(
config.GetSection("translations:googleCloud"));
services.Configure<LanguagesOptions>( services.Configure<LanguagesOptions>(
config.GetSection("languages")); config.GetSection("languages"));
services.AddSingletonAs<LanguagesInitializer>() services.AddSingletonAs<LanguagesInitializer>()
.AsSelf(); .AsSelf();
services.AddSingletonAs<DeepLTranslator>() services.AddSingletonAs(c => new DeepLTranslationService(c.GetRequiredService<IOptions<DeepLOptions>>().Value))
.As<ITranslationService>();
services.AddSingletonAs(c => new GoogleCloudTranslationService(c.GetRequiredService<IOptions<GoogleCloudTranslationOptions>>().Value))
.As<ITranslationService>();
services.AddSingletonAs<Translator>()
.As<ITranslator>(); .As<ITranslator>();
} }

9
backend/src/Squidex/appsettings.json

@ -672,11 +672,18 @@
}, },
"translations": { "translations": {
"deepl": {
/* /*
* The deepl api key if you want to support automated translations. * The deepl api key if you want to support automated translations.
*/ */
"deepl": {
"authKey": "" "authKey": ""
},
"googleCloud": {
/*
* The google cloud project id if you want to support automated translations.
*/
"projectId": ""
} }
}, },

Loading…
Cancel
Save