Browse Source

Add `Deepl` online translate to CLI.

pull/18632/head
maliming 2 years ago
parent
commit
2c71729469
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 1
      Directory.Packages.props
  2. 1
      framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj
  3. 247
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/TranslateCommand.cs

1
Directory.Packages.props

@ -29,6 +29,7 @@
<PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.1.151.7" /> <PackageVersion Include="Devart.Data.Oracle.EFCore" Version="10.1.151.7" />
<PackageVersion Include="DistributedLock.Core" Version="1.0.5" /> <PackageVersion Include="DistributedLock.Core" Version="1.0.5" />
<PackageVersion Include="DistributedLock.Redis" Version="1.0.2" /> <PackageVersion Include="DistributedLock.Redis" Version="1.0.2" />
<PackageVersion Include="DeepL.net" Version="1.8.0" />
<PackageVersion Include="EphemeralMongo.Core" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo.Core" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.linux-x64" Version="1.1.3" />
<PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" /> <PackageVersion Include="EphemeralMongo6.runtime.osx-x64" Version="1.1.3" />

1
framework/src/Volo.Abp.Cli.Core/Volo.Abp.Cli.Core.csproj

@ -24,6 +24,7 @@
<PackageReference Include="Polly.Extensions.Http" /> <PackageReference Include="Polly.Extensions.Http" />
<PackageReference Include="LibGit2Sharp" /> <PackageReference Include="LibGit2Sharp" />
<PackageReference Include="StackExchange.Redis" /> <PackageReference Include="StackExchange.Redis" />
<PackageReference Include="DeepL.net" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

247
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/TranslateCommand.cs

@ -5,6 +5,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DeepL;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -16,64 +17,61 @@ namespace Volo.Abp.Cli.Commands;
public class TranslateCommand : IConsoleCommand, ITransientDependency public class TranslateCommand : IConsoleCommand, ITransientDependency
{ {
public const string Name = "translate"; public const string Name = "translate";
public ILogger<TranslateCommand> Logger { get; set; } public ILogger<TranslateCommand> Logger { get; set; }
public Task ExecuteAsync(CommandLineArgs commandLineArgs) public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{ {
var currentDirectory = Directory.GetCurrentDirectory(); var currentDirectory = Directory.GetCurrentDirectory();
var referenceCulture = commandLineArgs.Options.GetOrNull(Options.ReferenceCulture.Short, Options.ReferenceCulture.Long) ?? "en";
var allValues = commandLineArgs.Options.ContainsKey(Options.AllValues.Short) || commandLineArgs.Options.ContainsKey(Options.AllValues.Long);
var apply = commandLineArgs.Options.ContainsKey(Options.Apply.Short) || commandLineArgs.Options.ContainsKey(Options.Apply.Long); // Apply abp-translation.json file
if (apply) if (commandLineArgs.Options.ContainsKey(Options.Apply.Short) || commandLineArgs.Options.ContainsKey(Options.Apply.Long))
{ {
var inputFile = Path.Combine(currentDirectory, var inputFile = Path.Combine(currentDirectory, commandLineArgs.Options.GetOrNull(Options.File.Short, Options.File.Long) ?? "abp-translation.json");
commandLineArgs.Options.GetOrNull(Options.File.Short, Options.File.Long) await ApplyAbpTranslateInfoAsync(currentDirectory, inputFile);
?? "abp-translation.json"); return;
Logger.LogInformation("Abp translate apply...");
Logger.LogInformation("Input file: " + inputFile);
ApplyAbpTranslateInfo(currentDirectory, inputFile);
} }
else
{
var targetCulture = commandLineArgs.Options.GetOrNull(Options.Culture.Short, Options.Culture.Long);
if (targetCulture == null)
{
throw new CliUsageException(
"Target culture is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var referenceCulture = commandLineArgs.Options.GetOrNull(Options.ReferenceCulture.Short, Options.ReferenceCulture.Long)
?? "en";
var outputFile = Path.Combine(currentDirectory,
commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long)
?? "abp-translation.json");
var allValues = commandLineArgs.Options.ContainsKey(Options.AllValues.Short) || var targetCulture = commandLineArgs.Options.GetOrNull(Options.Culture.Short, Options.Culture.Long);
commandLineArgs.Options.ContainsKey(Options.AllValues.Long); if (targetCulture == null)
{
Logger.LogInformation("Abp translate..."); throw new CliUsageException("Target culture is missing!" + Environment.NewLine + Environment.NewLine + GetUsageInfo());
Logger.LogInformation("Target culture: " + targetCulture); }
Logger.LogInformation("Reference culture: " + referenceCulture);
Logger.LogInformation("Output file: " + outputFile);
if (allValues) // Translate online
if (commandLineArgs.Options.ContainsKey(Options.Online.Long))
{
var authKey = commandLineArgs.Options.GetOrNull(Options.DeepLAuthKey.Short, Options.DeepLAuthKey.Short);
if (authKey == null)
{ {
Logger.LogInformation("Include all keys"); throw new CliUsageException("DeepL auth key is missing!" + Environment.NewLine + Environment.NewLine + GetUsageInfo());
} }
await TranslateAbpTranslateInfoAsync(currentDirectory, targetCulture, referenceCulture, allValues, authKey);
return;
}
var translateInfo = GetAbpTranslateInfo(currentDirectory, targetCulture, referenceCulture, allValues); // Generate abp-translation.json file
var outputFile = Path.Combine(currentDirectory, commandLineArgs.Options.GetOrNull(Options.Output.Short, Options.Output.Long) ?? "abp-translation.json");
File.WriteAllText(outputFile, JsonConvert.SerializeObject(translateInfo, Formatting.Indented)); await GenerateAbpTranslateInfoAsync(currentDirectory, targetCulture, referenceCulture, allValues, outputFile);
}
Logger.LogInformation($"The translation file has been created."); private Task GenerateAbpTranslateInfoAsync(string currentDirectory, string targetCulture, string referenceCulture, bool allValues, string outputFile)
{
Logger.LogInformation("Abp translate...");
Logger.LogInformation("Target culture: " + targetCulture);
Logger.LogInformation("Reference culture: " + referenceCulture);
Logger.LogInformation("Output file: " + outputFile);
if (allValues)
{
Logger.LogInformation("Include all keys");
} }
var translateInfo = GetAbpTranslateInfo(currentDirectory, targetCulture, referenceCulture, allValues);
File.WriteAllText(outputFile, JsonConvert.SerializeObject(translateInfo, Formatting.Indented));
Logger.LogInformation($"The translation file has been created.");
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -140,8 +138,151 @@ public class TranslateCommand : IConsoleCommand, ITransientDependency
return translateInfo; return translateInfo;
} }
private void ApplyAbpTranslateInfo(string directory, string filename) private async Task TranslateAbpTranslateInfoAsync(string directory, string targetCulture, string referenceCulture, bool allValues, string authKey)
{
Logger.LogInformation("Abp translate online...");
Logger.LogInformation("Target culture: " + targetCulture);
Logger.LogInformation("Reference culture: " + referenceCulture);
if (allValues)
{
Logger.LogInformation("Include all keys");
}
targetCulture = await GetDeeplLanguageCode(targetCulture);
referenceCulture = await GetDeeplLanguageCode(referenceCulture);
var translateInfo = GetAbpTranslateInfo(directory, targetCulture, referenceCulture, allValues);
foreach (var resource in translateInfo.Resources)
{
var targetFile = Path.Combine(resource.ResourcePath, translateInfo.TargetCulture + ".json");
var targetLocalizationInfo = File.Exists(targetFile)
? GetAbpLocalizationInfoOrNull(targetFile)
: new AbpLocalizationInfo()
{
Culture = translateInfo.TargetCulture,
Texts = new List<NameValue>()
};
if (targetLocalizationInfo == null)
{
throw new CliUsageException(
$"Failed to get localization information from {targetFile} file." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var referenceFile = Path.Combine(resource.ResourcePath, translateInfo.ReferenceCulture + ".json");
if (!File.Exists(referenceFile))
{
throw new CliUsageException(
$"{referenceFile} file does not exist.." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var referenceLocalizationInfo = GetAbpLocalizationInfoOrNull(referenceFile);
if (referenceLocalizationInfo == null)
{
throw new CliUsageException(
$"Failed to get localization information from {referenceFile} file." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var translator = new Translator(authKey);
var texts = resource.Texts.Select(x => x.Reference);
var translations = await translator.TranslateTextAsync(texts, referenceCulture, targetCulture);
for (var i = 0; i < translations.Length; i++)
{
resource.Texts[i].Target = translations[i].Text;
}
foreach (var text in resource.Texts)
{
var targetText = targetLocalizationInfo.Texts.FirstOrDefault(x => x.Name == text.LocalizationKey);
if (targetText != null)
{
if (!text.Target.IsNullOrEmpty())
{
Logger.LogInformation($"Update translation: {targetText.Name} => " + text.Target);
targetText.Value = text.Target;
}
}
else
{
Logger.LogInformation($"Create translation: {text.LocalizationKey} => " + text.Target);
targetLocalizationInfo.Texts.Add(new NameValue(text.LocalizationKey, text.Target));
}
}
Logger.LogInformation($"Write translation json to {targetFile}.");
// sort keys
targetLocalizationInfo = SortLocalizedKeys(targetLocalizationInfo, referenceLocalizationInfo);
File.WriteAllText(targetFile, AbpLocalizationInfoToJsonFile(targetLocalizationInfo));
}
}
private Task<string> GetDeeplLanguageCode(string abpCulture)
{ {
var deeplLanguages = new List<string>()
{
LanguageCode.Bulgarian ,
LanguageCode.Czech ,
LanguageCode.Danish ,
LanguageCode.German ,
LanguageCode.Greek ,
LanguageCode.English ,
LanguageCode.EnglishBritish ,
LanguageCode.EnglishAmerican ,
LanguageCode.Spanish ,
LanguageCode.Estonian ,
LanguageCode.Finnish ,
LanguageCode.French ,
LanguageCode.Hungarian ,
LanguageCode.Indonesian ,
LanguageCode.Italian ,
LanguageCode.Japanese ,
LanguageCode.Korean ,
LanguageCode.Lithuanian ,
LanguageCode.Latvian ,
LanguageCode.Norwegian ,
LanguageCode.Dutch ,
LanguageCode.Polish ,
LanguageCode.Portuguese ,
LanguageCode.PortugueseBrazilian ,
LanguageCode.PortugueseEuropean ,
LanguageCode.Romanian ,
LanguageCode.Russian ,
LanguageCode.Slovak ,
LanguageCode.Slovenian ,
LanguageCode.Swedish ,
LanguageCode.Turkish ,
LanguageCode.Ukrainian,
LanguageCode.Chinese
};
var deeplCulture = deeplLanguages.FirstOrDefault(x => x.Equals(abpCulture, StringComparison.OrdinalIgnoreCase));
if (deeplCulture == null)
{
throw new CliUsageException(
$"DeepL does not support {abpCulture} culture." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
return Task.FromResult(deeplCulture);
}
private Task ApplyAbpTranslateInfoAsync(string directory, string filename)
{
Logger.LogInformation("Abp translate apply...");
Logger.LogInformation("Input file: " + filename);
var translateJsonPath = Path.Combine(directory, filename); var translateJsonPath = Path.Combine(directory, filename);
if (!File.Exists(translateJsonPath)) if (!File.Exists(translateJsonPath))
{ {
@ -220,6 +361,8 @@ public class TranslateCommand : IConsoleCommand, ITransientDependency
File.Delete(translateJsonPath); File.Delete(translateJsonPath);
Logger.LogInformation($"Delete the {translateJsonPath} file, if you need to translate again, please re-run the [abp translate] command."); Logger.LogInformation($"Delete the {translateJsonPath} file, if you need to translate again, please re-run the [abp translate] command.");
} }
return Task.CompletedTask;
} }
private static IEnumerable<string> GetCultureJsonFiles(string path, string cultureName) private static IEnumerable<string> GetCultureJsonFiles(string path, string cultureName)
@ -357,13 +500,17 @@ public class TranslateCommand : IConsoleCommand, ITransientDependency
sb.AppendLine("--all-values|-all Include all keys. Default false"); sb.AppendLine("--all-values|-all Include all keys. Default false");
sb.AppendLine("--apply|-a Creates or updates the file for the translated culture."); sb.AppendLine("--apply|-a Creates or updates the file for the translated culture.");
sb.AppendLine("--file|-f <file-name> Default: abp-translation.json"); sb.AppendLine("--file|-f <file-name> Default: abp-translation.json");
sb.AppendLine("--online|-o Translate online.");
sb.AppendLine("--deepl-auth-key <auth-key> DeepL auth key for online translation.");
sb.AppendLine(""); sb.AppendLine("");
sb.AppendLine("Examples:"); sb.AppendLine("Examples:");
sb.AppendLine(""); sb.AppendLine("");
sb.AppendLine(" abp translate -c zh-Hans"); sb.AppendLine(" abp translate -c zh-Hans");
sb.AppendLine(" abp translate -c zh-Hans -r en -a"); sb.AppendLine(" abp translate -c zh-Hans -r en");
sb.AppendLine(" abp translate --apply"); sb.AppendLine(" abp translate --apply");
sb.AppendLine(" abp translate -a -f my-translation.json"); sb.AppendLine(" abp translate -a -f my-translation.json");
sb.AppendLine(" abp translate -c zh-Hans --deepl-auth-key <auth-key>");
sb.AppendLine(" abp translate -c zh-Hans -r tr --online --deepl-auth-key <auth-key>");
sb.AppendLine(""); sb.AppendLine("");
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
@ -412,6 +559,16 @@ public class TranslateCommand : IConsoleCommand, ITransientDependency
public const string Short = "f"; public const string Short = "f";
public const string Long = "file"; public const string Long = "file";
} }
public static class Online
{
public const string Long = "online";
}
public static class DeepLAuthKey
{
public const string Short = "deepl-auth-key";
}
} }
public class AbpTranslateInfo public class AbpTranslateInfo

Loading…
Cancel
Save