From 090cbba1a0f97b80e77420660437014d5c864b26 Mon Sep 17 00:00:00 2001 From: "DESKTOP-T0O5CDB\\DESK-555BD" Date: Fri, 25 Oct 2024 11:06:40 -0600 Subject: [PATCH] Added translation editor. --- Controllers/HomeController.cs | 26 +++++- Helper/TranslationHelper.cs | 115 ++++++++++++++++++++++++++- Views/Home/_Settings.cshtml | 34 ++++++-- Views/Home/_TranslationEditor.cshtml | 39 +++++++++ wwwroot/defaults/en_US.json | 2 +- wwwroot/js/settings.js | 70 ++++++++++++++++ 6 files changed, 276 insertions(+), 10 deletions(-) create mode 100644 Views/Home/_TranslationEditor.cshtml diff --git a/Controllers/HomeController.cs b/Controllers/HomeController.cs index d2b1cbe..6b90c4d 100644 --- a/Controllers/HomeController.cs +++ b/Controllers/HomeController.cs @@ -22,6 +22,7 @@ namespace CarCareTracker.Controllers private readonly IExtraFieldDataAccess _extraFieldDataAccess; private readonly IReminderRecordDataAccess _reminderRecordDataAccess; private readonly IReminderHelper _reminderHelper; + private readonly ITranslationHelper _translationHelper; public HomeController(ILogger logger, IVehicleDataAccess dataAccess, IUserLogic userLogic, @@ -31,7 +32,8 @@ namespace CarCareTracker.Controllers IFileHelper fileHelper, IExtraFieldDataAccess extraFieldDataAccess, IReminderRecordDataAccess reminderRecordDataAccess, - IReminderHelper reminderHelper) + IReminderHelper reminderHelper, + ITranslationHelper translationHelper) { _logger = logger; _dataAccess = dataAccess; @@ -43,6 +45,7 @@ namespace CarCareTracker.Controllers _reminderHelper = reminderHelper; _loginLogic = loginLogic; _vehicleLogic = vehicleLogic; + _translationHelper = translationHelper; } private int GetUserID() { @@ -260,6 +263,27 @@ namespace CarCareTracker.Controllers var userName = User.Identity.Name; return PartialView("_RootAccountModal", new UserData() { UserName = userName }); } + [Authorize(Roles = nameof(UserData.IsRootUser))] + [HttpGet] + public IActionResult GetTranslatorEditor(string userLanguage) + { + var translationData = _translationHelper.GetTranslations(userLanguage); + return PartialView("_TranslationEditor", translationData); + } + [Authorize(Roles = nameof(UserData.IsRootUser))] + [HttpPost] + public IActionResult SaveTranslation(string userLanguage, Dictionary translationData) + { + var result = _translationHelper.SaveTranslation(userLanguage, translationData); + return Json(result); + } + [Authorize(Roles = nameof(UserData.IsRootUser))] + [HttpPost] + public IActionResult ExportTranslation(Dictionary translationData) + { + var result = _translationHelper.ExportTranslation(translationData); + return Json(result); + } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { diff --git a/Helper/TranslationHelper.cs b/Helper/TranslationHelper.cs index 4e9b0a6..0c17638 100644 --- a/Helper/TranslationHelper.cs +++ b/Helper/TranslationHelper.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Caching.Memory; +using CarCareTracker.Models; +using Microsoft.Extensions.Caching.Memory; using System.Text.Json; namespace CarCareTracker.Helper @@ -6,17 +7,22 @@ namespace CarCareTracker.Helper public interface ITranslationHelper { string Translate(string userLanguage, string text); + Dictionary GetTranslations(string userLanguage); + OperationResponse SaveTranslation(string userLanguage, Dictionary translations); + string ExportTranslation(Dictionary translations); } public class TranslationHelper : ITranslationHelper { private readonly IFileHelper _fileHelper; private readonly IConfiguration _config; + private readonly ILogger _logger; private IMemoryCache _cache; - public TranslationHelper(IFileHelper fileHelper, IConfiguration config, IMemoryCache memoryCache) + public TranslationHelper(IFileHelper fileHelper, IConfiguration config, IMemoryCache memoryCache, ILogger logger) { _fileHelper = fileHelper; _config = config; _cache = memoryCache; + _logger = logger; } public string Translate(string userLanguage, string text) { @@ -36,11 +42,13 @@ namespace CarCareTracker.Helper return translationDictionary ?? new Dictionary(); } catch (Exception ex) { + _logger.LogError(ex.Message); return new Dictionary(); } } else { + _logger.LogError($"Could not find translation file for {userLanguage}"); return new Dictionary(); } }); @@ -52,10 +60,113 @@ namespace CarCareTracker.Helper { //create entry dictionary.Add(translationKey, text); + _logger.LogInformation($"Translation key added to {userLanguage} for {translationKey} with value {text}"); File.WriteAllText(translationFilePath, JsonSerializer.Serialize(dictionary)); return text; } return text; } + private Dictionary GetDefaultTranslation() + { + //this method always returns en_US translation. + var translationFilePath = _fileHelper.GetFullFilePath($"/defaults/en_US.json"); + if (!string.IsNullOrWhiteSpace(translationFilePath)) + { + //file exists. + try + { + var translationFile = File.ReadAllText(translationFilePath); + var translationDictionary = JsonSerializer.Deserialize>(translationFile); + return translationDictionary ?? new Dictionary(); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return new Dictionary(); + } + } + _logger.LogError($"Could not find translation file for en_US"); + return new Dictionary(); + } + public Dictionary GetTranslations(string userLanguage) + { + var defaultTranslation = GetDefaultTranslation(); + if (userLanguage == "en_US") + { + return defaultTranslation; + } + var translationFilePath = _fileHelper.GetFullFilePath($"/translations/{userLanguage}.json"); + if (!string.IsNullOrWhiteSpace(translationFilePath)) + { + //file exists. + try + { + var translationFile = File.ReadAllText(translationFilePath); + var translationDictionary = JsonSerializer.Deserialize>(translationFile); + if (translationDictionary != null) + { + foreach(var translation in translationDictionary) + { + defaultTranslation[translation.Key] = translation.Value; + } + } + return defaultTranslation ?? new Dictionary(); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return new Dictionary(); + } + } + _logger.LogError($"Could not find translation file for {userLanguage}"); + return new Dictionary(); + } + public OperationResponse SaveTranslation(string userLanguage, Dictionary translations) + { + if (userLanguage == "en_US") + { + return new OperationResponse { Success = false, Message = "The translation file name en_US is reserved." }; + } + var translationFilePath = _fileHelper.GetFullFilePath($"/translations/{userLanguage}.json", false); + try + { + if (File.Exists(translationFilePath)) + { + //write to file + File.WriteAllText(translationFilePath, JsonSerializer.Serialize(translations)); + _cache.Remove($"lang_{userLanguage}"); //clear out cache, force a reload from file. + } else + { + //write to file + File.WriteAllText(translationFilePath, JsonSerializer.Serialize(translations)); + } + return new OperationResponse { Success = true, Message = "Translation Updated" }; + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage }; + } + } + public string ExportTranslation(Dictionary translations) + { + try + { + var tempFileName = $"/temp/{Guid.NewGuid()}.json"; + string uploadDirectory = _fileHelper.GetFullFilePath("temp/", false); + if (!Directory.Exists(uploadDirectory)) + { + Directory.CreateDirectory(uploadDirectory); + } + var saveFilePath = _fileHelper.GetFullFilePath(tempFileName, false); + File.WriteAllText(saveFilePath, JsonSerializer.Serialize(translations)); + return tempFileName; + } + catch(Exception ex) + { + _logger.LogError(ex.Message); + return string.Empty; + } + } } } diff --git a/Views/Home/_Settings.cshtml b/Views/Home/_Settings.cshtml index dd88e20..71499eb 100644 --- a/Views/Home/_Settings.cshtml +++ b/Views/Home/_Settings.cshtml @@ -165,12 +165,28 @@
@translator.Translate(userLanguage, "Language") - + @if (User.IsInRole(nameof(UserData.IsRootUser))) + { +
+ +
+ +
+
+ } else + { + + }
@if (User.IsInRole(nameof(UserData.IsRootUser))) @@ -286,6 +302,12 @@ +