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. 41
      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.Caching" 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="System.Collections.Immutable" 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.Translations;
using Squidex.Text.Translations;
namespace Squidex.Areas.Api.Controllers.Translations.Models
{
@ -15,14 +16,14 @@ namespace Squidex.Areas.Api.Controllers.Translations.Models
/// <summary>
/// The result of the translation.
/// </summary>
public TranslationResult Result { get; set; }
public TranslationResultCode Result { get; set; }
/// <summary>
/// The translated text.
/// </summary>
public string? Text { get; set; }
public static TranslationDto FromTranslation(Translation translation)
public static TranslationDto FromTranslation(TranslationResult translation)
{
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.Translations;
using Squidex.Shared;
using Squidex.Text.Translations;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Translations
@ -44,7 +45,7 @@ namespace Squidex.Areas.Api.Controllers.Translations
[ApiCosts(0)]
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);
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.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NodaTime;
using Orleans;
using Squidex.Areas.Api.Controllers.Contents.Generator;
@ -31,6 +32,8 @@ using Squidex.Infrastructure.Orleans;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.UsageTracking;
using Squidex.Pipeline.Robots;
using Squidex.Text.Translations;
using Squidex.Text.Translations.GoogleCloud;
using Squidex.Web;
using Squidex.Web.Pipeline;
@ -120,15 +123,23 @@ namespace Squidex.Config.Domain
public static void AddSquidexTranslation(this IServiceCollection services, IConfiguration config)
{
services.Configure<DeepLTranslatorOptions>(
services.Configure<DeepLOptions>(
config.GetSection("translations:deepL"));
services.Configure<GoogleCloudTranslationOptions>(
config.GetSection("translations:googleCloud"));
services.Configure<LanguagesOptions>(
config.GetSection("languages"));
services.AddSingletonAs<LanguagesInitializer>()
.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>();
}

41
backend/src/Squidex/appsettings.json

@ -672,11 +672,18 @@
},
"translations": {
/*
* The deepl api key if you want to support automated translations.
*/
"deepl": {
/*
* The deepl api key if you want to support automated translations.
*/
"authKey": ""
},
"googleCloud": {
/*
* The google cloud project id if you want to support automated translations.
*/
"projectId": ""
}
},
@ -684,38 +691,38 @@
/*
* Set to true to rebuild apps.
*/
"apps": false,
"apps": false,
/*
/*
* Set to true to rebuild assets.
*/
"assets": false,
"assets": false,
/*
/*
* Set to true to create dummy asset files if they do not exist. Useful when a backup fail.
*/
"assetFiles": false,
"assetFiles": false,
/*
/*
* Set to true to rebuild contents.
*/
"contents": false,
"contents": false,
/*
/*
* Set to true to rebuild rules.
*/
"rules": false,
"rules": false,
/*
/*
* Set to true to rebuild schemas.
*/
"schemas": false,
"schemas": false,
/*
/*
* Set to true to rebuild indexes.
*/
"indexes": false
},
"indexes": false
},
/*"
* A list of configuration values that should be exposed from the info endpoint and in the UI.

Loading…
Cancel
Save