From 8cdd040f34656ad6c2b53507848a7ba26e4ba2dd Mon Sep 17 00:00:00 2001 From: valdis iljuconoks Date: Sat, 28 Dec 2024 22:01:07 +0200 Subject: [PATCH] refactored translator service API design --- .../Pages/AdminUI.cshtml | 4 +- .../Pages/AdminUITree.cshtml | 4 +- .../ServiceController.cs | 7 +++- .../ITranslatorService.cs | 6 ++- .../TranslationResult.cs | 40 +++++++++++++++++++ .../CognitiveServiceTranslator.cs | 23 ++++++++--- 6 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 common/src/DbLocalizationProvider.Abstractions/TranslationResult.cs diff --git a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUI.cshtml b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUI.cshtml index 1b0db8bd..4f83b3f7 100644 --- a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUI.cshtml +++ b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUI.cshtml @@ -831,8 +831,8 @@ axios .get('api/service/auto-translate?inputText=' + this.model.currentResource.invariant + '&targetLanguage=' + this.model.currentResource.language) .then(response => { - if (response) { - this.model.currentResource.translation = response.data; + if (response && response.data.isSuccessful) { + this.model.currentResource.translation = response.data.result; } }); }, diff --git a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUITree.cshtml b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUITree.cshtml index 31f7d3ad..15306c4c 100644 --- a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUITree.cshtml +++ b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/Areas/4D5A2189D188417485BF6C70546D34A1/Pages/AdminUITree.cshtml @@ -532,8 +532,8 @@ axios .get('../api/service/auto-translate?inputText=' + this.currentResource.invariant + '&targetLanguage=' + this.currentResource.language) .then(response => { - if (response) { - this.currentResource.translation = response.data; + if (response && response.data.isSuccessful) { + this.currentResource.translation = response.data.result; } }); }, diff --git a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/ServiceController.cs b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/ServiceController.cs index 19f52252..15490e40 100644 --- a/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/ServiceController.cs +++ b/aspnetcore/src/DbLocalizationProvider.AdminUI.AspNetCore/ServiceController.cs @@ -154,9 +154,12 @@ public async Task AutoTranslate(string inputText, string targetLa return BadRequest("Translator service is not configured."); } - var resultText = await translator.TranslateAsync(inputText, targetLanguage); + var result = await translator.TranslateAsync( + inputText, + CultureInfo.GetCultureInfo(targetLanguage), + CultureInfo.InvariantCulture); - return Ok(resultText); + return Ok(result); } private LocalizationResourceApiModel PrepareViewModel(string keyword) diff --git a/common/src/DbLocalizationProvider.Abstractions/ITranslatorService.cs b/common/src/DbLocalizationProvider.Abstractions/ITranslatorService.cs index 048b92a2..ce8c8adc 100644 --- a/common/src/DbLocalizationProvider.Abstractions/ITranslatorService.cs +++ b/common/src/DbLocalizationProvider.Abstractions/ITranslatorService.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Threading.Tasks; namespace DbLocalizationProvider.Abstractions; @@ -11,7 +12,8 @@ public interface ITranslatorService /// Translates text from one language to another. /// /// Text to translate. - /// Target language code to translate text to. + /// Target language to translate text to. + /// Source language to translate text from. /// Translated text if all is good; otherwise null. - Task TranslateAsync(string inputText, string targetLanguage); + Task TranslateAsync(string inputText, CultureInfo targetLanguage, CultureInfo sourceLanguage); } diff --git a/common/src/DbLocalizationProvider.Abstractions/TranslationResult.cs b/common/src/DbLocalizationProvider.Abstractions/TranslationResult.cs new file mode 100644 index 00000000..0bc0cb2a --- /dev/null +++ b/common/src/DbLocalizationProvider.Abstractions/TranslationResult.cs @@ -0,0 +1,40 @@ +namespace DbLocalizationProvider.Abstractions; + +/// +/// Result of the translation operation from AI service. +/// +/// Is operation successful? +/// Translated text to target language. +/// Filled in with problem details if any. +public record TranslationResult(bool IsSuccessful, string? Result, Problem? Error = null) +{ + /// + /// Translation was successful. + /// + /// Translated text to target language. + /// Successful translation result. + public static TranslationResult Ok(string text) + { + return new TranslationResult(true, text); + } + + /// + /// Translation was failing. + /// + /// Error details if translation failed. + /// More details about an error. + /// Failed translation result. + public static TranslationResult Failed(string message, string? details = null) + { + return new TranslationResult(false, null, new Problem(message, details)); + } +} + +/// +/// More details about failed translation. +/// +/// Message about an error. +/// More information about an error. +public record Problem(string? Message, string? Details) +{ +} diff --git a/common/src/DbLocalizationProvider.Translator.Azure/CognitiveServiceTranslator.cs b/common/src/DbLocalizationProvider.Translator.Azure/CognitiveServiceTranslator.cs index 4190781c..959ff71b 100644 --- a/common/src/DbLocalizationProvider.Translator.Azure/CognitiveServiceTranslator.cs +++ b/common/src/DbLocalizationProvider.Translator.Azure/CognitiveServiceTranslator.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Azure; using Azure.AI.Translation.Text; using DbLocalizationProvider.Abstractions; @@ -26,24 +27,34 @@ public CognitiveServiceTranslator(IOptions options, IL } /// - public async Task TranslateAsync(string inputText, string targetLanguage) + public async Task TranslateAsync(string inputText, CultureInfo targetLanguage, CultureInfo sourceLanguage) { AzureKeyCredential credential = new(_options.AccessKey); TextTranslationClient client = new(credential, _options.Region); try { - var response = await client.TranslateAsync(targetLanguage, inputText).ConfigureAwait(false); + var response = await client.TranslateAsync(targetLanguage.Name, inputText).ConfigureAwait(false); var translations = response.Value; - var translation = translations.FirstOrDefault(); - return translation?.Translations?.FirstOrDefault()?.Text; + if (translations == null) + { + return TranslationResult.Failed("Failed to translate. Result from Azure Cognitive Service is null."); + } + + var translation = translations[0]!; + + if (translation.Translations == null || translation.Translations?.Count == 0) + { + return TranslationResult.Failed("Failed to translate. Translations from Azure Cognitive Service is null."); + } + + return TranslationResult.Ok(translation.Translations[0].Text); } catch (RequestFailedException exception) { _logger.Error($"Failed to auto-translate to `{targetLanguage}`.", exception); + return TranslationResult.Failed($"Failed to translate. {exception.Message}"); } - - return default; } }