using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Web.Script.Serialization; using System.Windows; namespace Metadata_Translator { public class TranslatorService { List Languages { get; set; } string SourceLanguage { get; set; } string SubscriptionKey { get; set; } string Endpoint { get; set; } string Location { get; set; } /// /// /// /// /// /// /// /// public TranslatorService(List languages, string sourceLanguage, string subscriptionKey, string endpoint, string location) { Languages = languages; SourceLanguage = sourceLanguage; SubscriptionKey = subscriptionKey; Endpoint = endpoint; Location = location; } public void Translate(List dataRows, bool replaceExistingTranslations) { /// No languages, or only the one source language? Nothing to translate! /// if (Languages == null || Languages.Count < 2) return; /// Get the target languages (i.e. not the SourceLanguage). /// List targetLanguages = Languages.Where(l => !l.LanguageTag.Equals(SourceLanguage)).ToList(); /// Filter down the data rows to those with values in the source language. /// List filteredRows = dataRows.Where(dr => !string.IsNullOrEmpty(dr.GetValue(SourceLanguage)))?.ToList(); /// No rows? Nothing to translate! /// if (filteredRows == null || filteredRows.Count == 0) return; /// Iterate over the TranslationGroups, all languages within the same group /// share the same translation id. /// foreach(string id in targetLanguages.Select(tl => tl.TranslationId).Distinct()) { Translate(filteredRows, targetLanguages.Where(tl => tl.TranslationId.Equals(id)), id, replaceExistingTranslations); } } private void Translate(List dataRows, IEnumerable targetLanguages, string translationId, bool replaceExistingTranslations) { List rowsToTranslate = new List(); /// Don't replace existing translations? /// Filter down the data rows to those that are empty for at least one of the target languages. /// if (!replaceExistingTranslations) { foreach(Language language in targetLanguages) { rowsToTranslate.AddRange(dataRows.Where(dr => string.IsNullOrEmpty(dr.GetValue(language.LanguageTag)))); } rowsToTranslate = rowsToTranslate.Distinct()?.ToList(); } else { /// Otherwise translate all data rows. /// rowsToTranslate = dataRows; } /// Now translate the source strings recursively. /// Translate(rowsToTranslate, targetLanguages, translationId, replaceExistingTranslations, 0); } private void Translate(List dataRows, IEnumerable targetLanguages, string translationId, bool replaceExistingTranslations, int iterationId) { int maxBatchSize = 100; int batchStart = maxBatchSize * iterationId; /// Check if all strings have been translated. /// if (dataRows.Count <= batchStart) return; /// Assemble a translation batch of up to maxBatchSize. /// maxBatchSize = (dataRows.Count - batchStart) < maxBatchSize? dataRows.Count - batchStart : maxBatchSize; List translationBatch = new List(); for (int i = 0; i < maxBatchSize; i++) { translationBatch.Add(new { Text = dataRows[batchStart + i].GetValue(SourceLanguage) }); } /// Translate the batch and assign the translated strings to the target languages. /// var translatedStrings = TranslateBatch(translationBatch, translationId); if (translatedStrings.Count > 0) { for (int i = 0; i < maxBatchSize; i++) { foreach (Language language in targetLanguages) { dataRows[batchStart + i].SetValue(language.LanguageTag, translatedStrings[i], replaceExistingTranslations); } } Translate(dataRows, targetLanguages, translationId, replaceExistingTranslations, ++iterationId); } } private List TranslateBatch(List sourceObjects, string targetLanguage) { List translatedPhrases = new List(); var requestBody = new JavaScriptSerializer().Serialize(sourceObjects); using (var client = new HttpClient()) using (var request = new HttpRequestMessage()) { /// Build the Web request. /// request.Method = HttpMethod.Post; request.RequestUri = new Uri($"{Endpoint}/translate?api-version=3.0&from={SourceLanguage}&to={targetLanguage}"); request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); request.Headers.Add("Ocp-Apim-Subscription-Key", SubscriptionKey); request.Headers.Add("Ocp-Apim-Subscription-Region", Location); /// Send the translation request and get the response. /// HttpResponseMessage response = client.SendAsync(request).Result; string result = response.Content.ReadAsStringAsync().Result; /// Display an error message if the Web request was not successful. /// if (!response.IsSuccessStatusCode) { MessageBox.Show( Application.Current.FindResource("UnableToAccessTranslatorEndpoint") as string, Application.Current.FindResource("WebRequestError") as string, MessageBoxButton.OK); } else { /// Parse the results and add the strings to the translated phrases if there was no error, /// i.e. the target language was returned together with the translated string, which is /// not the case if the service gives back an error message. /// List parsedResults = new JavaScriptSerializer().Deserialize>(result); if (parsedResults != null) { for (int n = 0; n < parsedResults.Count; n++) { translatedPhrases.Add((string.IsNullOrEmpty(parsedResults[n].translations[0].to)) ? "" : parsedResults[n].translations[0].text); } } } } return translatedPhrases; } } }