Skip to content

Commit

Permalink
Add Azure translation service. Requires adding your own key to a priv…
Browse files Browse the repository at this point in the history
…ate appsettings JSON file to translate locally with it.
  • Loading branch information
kooliokey committed Jan 27, 2023
1 parent 7aedb59 commit 9712250
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# This file will contain settings we don't want committed to GIT
appsettings.private.json

# User-specific files
*.rsuser
*.suo
Expand Down
14 changes: 14 additions & 0 deletions site/AntDesign.Docs.Build.CLI/AntDesign.Docs.Build.CLI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
<ItemGroup>
<PackageReference Include="LoxSmoke.DocXml" Version="3.5.0" />
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
<PackageReference Include="YamlDotnet" Version="11.2.1" />
<PackageReference Include="Markdig" Version="0.25.0" />
</ItemGroup>
Expand All @@ -17,4 +22,13 @@
<ProjectReference Include="..\..\components\AntDesign.csproj" />
<ProjectReference Include="..\AntDesign.Docs\AntDesign.Docs.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="appsettings.private.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions site/AntDesign.Docs.Build.CLI/AzureTranslateOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace AntDesign.Docs.Build.CLI
{
public class AzureTranslateOptions
{
public string Key { get; set; }

public string Region { get; set; }
}
}
28 changes: 25 additions & 3 deletions site/AntDesign.Docs.Build.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using AntDesign.Docs.Build.CLI.Services.Translation;
using AntDesign.Docs.Build.CLI.Utils;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace AntDesign.Docs.Build.CLI
{
Expand Down Expand Up @@ -39,6 +41,9 @@ private int Run(string[] args)
private IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();

ConfigureOptions(services);

services.AddSingleton<CommandLineApplicationFactory>();
services.AddSingleton(p => p.GetRequiredService<CommandLineApplicationFactory>().Create());
services.AddSingleton<IAppCommandResolver, AppCommandResolver>();
Expand All @@ -49,18 +54,35 @@ private IServiceProvider ConfigureServices()
services.AddSingleton<IAppCommand, GenerateMenuJsonCommand>();
services.AddSingleton<IAppCommand, GenerateDocsToHtmlCommand>();
services.AddSingleton<IAppCommand, GenerateIconsToJsonCommand>();
services.AddHttpClient<Translate>(client =>
services.AddHttpClient<GoogleTranslate>(client =>
{
client.BaseAddress = new Uri("https://translate.google.com");
});
services.AddHttpClient<AzureTranslate>(client =>
{
client.BaseAddress = new Uri($"https://translate.google.com");
client.BaseAddress = new Uri("https://api.cognitive.microsofttranslator.com");
});
services.AddSingleton<ITranslate>(provider =>
{
var translateClient = provider.GetRequiredService<Translate>();
// You can switch to translating documentation with the Google translation service if desired
// var translateClient = provider.GetRequiredService<GoogleTranslate>();
var translateClient = provider.GetRequiredService<AzureTranslate>();
return new TranslateCache(translateClient);
});

return services.BuildServiceProvider();
}

private static void ConfigureOptions(ServiceCollection services)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.private.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();

services.Configure<AzureTranslateOptions>(configuration.GetSection("AzureTranslate"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using YamlDotNet.Core.Tokens;

namespace AntDesign.Docs.Build.CLI.Services.Translation
{
public class AzureTranslate : ITranslate
{
private readonly HttpClient _client;

private readonly IOptionsSnapshot<AzureTranslateOptions> _options;

public AzureTranslate(HttpClient client, IOptionsSnapshot<AzureTranslateOptions> options)
{
_client = client;
_options = options;
}

public Task BackupTranslations(bool onlyKeepUsed = true)
{
throw new NotImplementedException("Not the best design, but this class doesn't implement this. It is meant for the cache wrapper class.");
}

public async Task<string> TranslateText(string text, string to, string from = "auto")
{
if (string.IsNullOrWhiteSpace(_options.Value.Key) || string.IsNullOrWhiteSpace(text))
{
return text;
}

using var request = new HttpRequestMessage();

request.Headers.Add("Ocp-Apim-Subscription-Key", _options.Value.Key);

if (!string.IsNullOrWhiteSpace(_options.Value.Region))
{
request.Headers.Add("Ocp-Apim-Subscription-Region", _options.Value.Region);
}

request.Method = HttpMethod.Post;
request.Content = RequestContent(text);
request.RequestUri = BuildRequestUri(from, to);

var response = await _client.SendAsync(request);
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
throw new TranslationTooManyRequestsException();
}

var responseContent = await response.Content.ReadAsStringAsync();
var deserialized = JsonSerializer.Deserialize<IEnumerable<AzureTranslationResponse>>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

return deserialized.SingleOrDefault()?.Translations.SingleOrDefault()?.Text ?? text;
}

private Uri BuildRequestUri(string from, string to)
{
var url = _client.BaseAddress + $"translate?api-version=3.0&to={to}";
if (from != "auto")
{
url += $"&from={from}";
}

return new Uri(url);
}

private static HttpContent RequestContent(string text)
{
var body = new object[] {
new {
Text = text
}
};

return new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;

namespace AntDesign.Docs.Build.CLI.Services.Translation
{
public class AzureTranslationResponse
{
public IEnumerable<Translation> Translations { get; set; }

public class Translation
{
public string To { get; set; }

public string Text { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@

namespace AntDesign.Docs.Build.CLI.Services.Translation
{
public class Translate : ITranslate
public class GoogleTranslate : ITranslate
{
private readonly HttpClient _client;

public Translate(HttpClient client)
public GoogleTranslate(HttpClient client)
{
_client = client;
}
Expand Down Expand Up @@ -55,7 +55,7 @@ public async Task<string> TranslateText(string text, string to, string from = "a
}

var responseContent = await response.Content.ReadAsStringAsync();
var deserialized = JsonSerializer.Deserialize<TranslationResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var deserialized = JsonSerializer.Deserialize<GoogleTranslationResponse>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

var combinedResponse = string.Join(string.Empty, deserialized.Sentences.Select(x => x.Trans));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace AntDesign.Docs.Build.CLI.Services.Translation
{
public class TranslationResponse
public class GoogleTranslationResponse
{
public IEnumerable<SentencesModel> Sentences { get; set; }

Expand Down
6 changes: 6 additions & 0 deletions site/AntDesign.Docs.Build.CLI/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AzureTranslate": {
"Key": "",
"Region": ""
}
}

0 comments on commit 9712250

Please sign in to comment.