From 548989f9aeefe96ef12ec60208ed6a99c828e239 Mon Sep 17 00:00:00 2001 From: "DESKTOP-GENO133\\IvanPlex" Date: Sun, 4 Feb 2024 10:09:57 -0700 Subject: [PATCH] keyed admin panel --- .gitignore | 1 + Controllers/FilesController.cs | 22 +++- Controllers/HomeController.cs | 13 +- Helper/ConfigHelper.cs | 1 + Helper/FileHelper.cs | 40 +++++- Views/Admin/Index.cshtml | 29 +++-- Views/Home/_Settings.cshtml | 222 +++++++++++++++++++++------------ wwwroot/defaults/en_US.json | 2 +- 8 files changed, 232 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index d8c2da9..d830b57 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ data/cartracker.db wwwroot/documents/ wwwroot/temp/ wwwroot/imports/ +wwwroot/translations/ diff --git a/Controllers/FilesController.cs b/Controllers/FilesController.cs index 176373e..2d9e8f7 100644 --- a/Controllers/FilesController.cs +++ b/Controllers/FilesController.cs @@ -33,6 +33,26 @@ namespace CarCareTracker.Controllers return Json(fileName); } + [HttpPost] + public IActionResult HandleTranslationFileUpload(IFormFile file) + { + var originalFileName = Path.GetFileNameWithoutExtension(file.FileName); + if (originalFileName == "en_US") + { + return Json(new OperationResponse { Success = false, Message = "The translation file name en_US is reserved." }); + } + var fileName = UploadFile(file); + //move file from temp to translation folder. + var uploadedFilePath = _fileHelper.MoveFileFromTemp(fileName, "translations/"); + //rename uploaded file so that it preserves original name. + if (!string.IsNullOrWhiteSpace(uploadedFilePath)) + { + var result = _fileHelper.RenameFile(uploadedFilePath, originalFileName); + return Json(new OperationResponse { Success = result, Message = string.Empty }); + } + return Json(new OperationResponse { Success = false, Message = StaticHelper.GenericErrorMessage }); + } + [HttpPost] public IActionResult HandleMultipleFileUpload(List file) { @@ -44,7 +64,7 @@ namespace CarCareTracker.Controllers } return Json(uploadedFiles); } - + [Authorize(Roles = nameof(UserData.IsRootUser))] [HttpPost] public IActionResult DeleteFiles(string fileLocation) { diff --git a/Controllers/HomeController.cs b/Controllers/HomeController.cs index 981177d..9f37207 100644 --- a/Controllers/HomeController.cs +++ b/Controllers/HomeController.cs @@ -15,17 +15,20 @@ namespace CarCareTracker.Controllers private readonly ILogger _logger; private readonly IVehicleDataAccess _dataAccess; private readonly IUserLogic _userLogic; + private readonly IFileHelper _fileHelper; private readonly IConfigHelper _config; public HomeController(ILogger logger, IVehicleDataAccess dataAccess, IUserLogic userLogic, - IConfigHelper configuration) + IConfigHelper configuration, + IFileHelper fileHelper) { _logger = logger; _dataAccess = dataAccess; _config = configuration; _userLogic = userLogic; + _fileHelper = fileHelper; } private int GetUserID() { @@ -47,7 +50,13 @@ namespace CarCareTracker.Controllers public IActionResult Settings() { var userConfig = _config.GetUserConfig(User); - return PartialView("_Settings", userConfig); + var languages = _fileHelper.GetLanguages(); + var viewModel = new SettingsViewModel + { + UserConfig = userConfig, + UILanguages = languages + }; + return PartialView("_Settings", viewModel); } [HttpPost] public IActionResult WriteToSettings(UserConfig userConfig) diff --git a/Helper/ConfigHelper.cs b/Helper/ConfigHelper.cs index 91efe84..326fb6b 100644 --- a/Helper/ConfigHelper.cs +++ b/Helper/ConfigHelper.cs @@ -110,6 +110,7 @@ namespace CarCareTracker.Helper EnableAutoOdometerInsert = bool.Parse(_config[nameof(UserConfig.EnableAutoOdometerInsert)]), PreferredGasMileageUnit = _config[nameof(UserConfig.PreferredGasMileageUnit)], PreferredGasUnit = _config[nameof(UserConfig.PreferredGasUnit)], + UserLanguage = _config[nameof(UserConfig.UserLanguage)], VisibleTabs = _config.GetSection("VisibleTabs").Get>(), DefaultTab = (ImportMode)int.Parse(_config[nameof(UserConfig.DefaultTab)]) }; diff --git a/Helper/FileHelper.cs b/Helper/FileHelper.cs index 4b26727..b22d331 100644 --- a/Helper/FileHelper.cs +++ b/Helper/FileHelper.cs @@ -7,10 +7,12 @@ namespace CarCareTracker.Helper { string GetFullFilePath(string currentFilePath, bool mustExist = true); string MoveFileFromTemp(string currentFilePath, string newFolder); + bool RenameFile(string currentFilePath, string newName); bool DeleteFile(string currentFilePath); string MakeBackup(); bool RestoreBackup(string fileName, bool clearExisting = false); string MakeAttachmentsExport(List exportData); + List GetLanguages(); } public class FileHelper : IFileHelper { @@ -21,6 +23,40 @@ namespace CarCareTracker.Helper _webEnv = webEnv; _logger = logger; } + public List GetLanguages() + { + var languagePath = Path.Combine(_webEnv.WebRootPath, "translations"); + var defaultList = new List() { "en_US" }; + if (Directory.Exists(languagePath)) + { + var listOfLanguages = Directory.GetFiles(languagePath); + if (listOfLanguages.Any()) + { + defaultList.AddRange(listOfLanguages.Select(x => Path.GetFileNameWithoutExtension(x))); + } + } + return defaultList; + } + public bool RenameFile(string currentFilePath, string newName) + { + var fullFilePath = GetFullFilePath(currentFilePath); + if (!string.IsNullOrWhiteSpace(fullFilePath)) + { + try + { + var originalFileName = Path.GetFileNameWithoutExtension(fullFilePath); + var newFilePath = fullFilePath.Replace(originalFileName, newName); + File.Move(fullFilePath, newFilePath); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + return false; + } + } + return false; + } public string GetFullFilePath(string currentFilePath, bool mustExist = true) { if (currentFilePath.StartsWith("/")) @@ -132,9 +168,9 @@ namespace CarCareTracker.Helper if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); int fileIndex = 0; - foreach(GenericReportModel reportModel in exportData) + foreach (GenericReportModel reportModel in exportData) { - foreach(UploadedFiles file in reportModel.Files) + foreach (UploadedFiles file in reportModel.Files) { var fileToCopy = GetFullFilePath(file.Location); var destFileName = $"{tempPath}/{fileIndex}{Path.GetExtension(file.Location)}"; diff --git a/Views/Admin/Index.cshtml b/Views/Admin/Index.cshtml index c863b0a..ab8cf69 100644 --- a/Views/Admin/Index.cshtml +++ b/Views/Admin/Index.cshtml @@ -1,10 +1,13 @@ -@{ +@using CarCareTracker.Helper +@{ ViewData["Title"] = "Admin"; } @inject IConfiguration config; +@inject ITranslationHelper translator @{ bool emailServerIsSetup = true; var mailConfig = config.GetSection("MailConfig").Get(); + var userLanguage = config[nameof(UserConfig.UserLanguage)] ?? "en_US"; if (mailConfig is null || string.IsNullOrWhiteSpace(mailConfig.EmailServer)) { emailServerIsSetup = false; @@ -17,31 +20,31 @@
- Admin Panel + @translator.Translate(userLanguage, "Admin Panel")

- Tokens + @translator.Translate(userLanguage, "Tokens")
- +
- +
- - - + + + @@ -59,15 +62,15 @@
TokenIssued ToDelete@translator.Translate(userLanguage, "Token")@translator.Translate(userLanguage, "Issued To")@translator.Translate(userLanguage, "Delete")
- Users + @translator.Translate(userLanguage, "Users")
- - - - + + + + diff --git a/Views/Home/_Settings.cshtml b/Views/Home/_Settings.cshtml index 463db36..c783fd7 100644 --- a/Views/Home/_Settings.cshtml +++ b/Views/Home/_Settings.cshtml @@ -1,143 +1,154 @@ @using CarCareTracker.Helper -@model UserConfig +@model SettingsViewModel @inject ITranslationHelper translator @{ - var userLanguage = Model.UserLanguage; + var userLanguage = Model.UserConfig.UserLanguage; }
-
@translator.Translate(userLanguage,"Settings")
+
@translator.Translate(userLanguage, "Settings")

- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
@if (User.IsInRole(nameof(UserData.IsRootUser))) {
- - + +
}
- @translator.Translate(userLanguage,"Visible Tabs") + @translator.Translate(userLanguage, "Visible Tabs")
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
  • - - + +
-
+
- @translator.Translate(userLanguage,"Default Tab") + @translator.Translate(userLanguage, "Default Tab")
- @if (User.IsInRole(nameof(UserData.IsRootUser))) - { +
+ @translator.Translate(userLanguage, "Language") + +
+
+ @if (User.IsInRole(nameof(UserData.IsRootUser))) + { +
@translator.Translate(userLanguage, "Backups")
@@ -148,10 +159,22 @@
+
+
+
+ @translator.Translate(userLanguage, "Manage Languages") +
+
+ +
-
- } -
+
+ +
+
+
+
+ }
@@ -177,7 +200,7 @@
Hometown Shoutout

- Do you work remotely and are looking for a new place to call home? Consider looking into the rural Eastern Utah town of Price. Price and Carbon County + Do you work remotely and are looking for a new place to call home? Consider looking into the rural Eastern Utah town of Price. Price and Carbon County has experienced pronounced decline in both population and economic activity within the past decade whereas the rest of the state experienced exponential growth. It is conveniently located in between Salt Lake City and Moab Utah. Amenities are relatively complete in terms of big box stores and high speed fiber Internet. Price and its surrounding towns as a whole could really benefit from in-migration. Thank you! @@ -208,10 +231,18 @@ }); return visibleTabs.toArray(); } - function updateSettings(){ + function deleteLanguage() { + var languageFileLocation = `/translations/${$("#defaultLanguage").val()}.json`; + $.post('/Files/DeleteFiles', { fileLocation: languageFileLocation }, function (data) { + //reset user language back to en_US + $("#defaultLanguage").val('en_US'); + updateSettings(); + }); + } + function updateSettings() { var visibleTabs = getCheckedTabs(); var defaultTab = $("#defaultTab").val(); - if (!visibleTabs.includes(defaultTab)){ + if (!visibleTabs.includes(defaultTab)) { defaultTab = "Dashboard"; //default to dashboard. } var userConfigObject = { @@ -227,11 +258,12 @@ enableAutoOdometerInsert: $("#enableAutoOdometerInsert").is(":checked"), preferredGasUnit: $("#preferredGasUnit").val(), preferredGasMileageUnit: $("#preferredFuelMileageUnit").val(), + userLanguage: $("#defaultLanguage").val(), visibleTabs: visibleTabs, defaultTab: defaultTab } sloader.show(); - $.post('/Home/WriteToSettings', { userConfig: userConfigObject}, function(data){ + $.post('/Home/WriteToSettings', { userConfig: userConfigObject }, function (data) { sloader.hide(); if (data) { setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500); @@ -245,9 +277,37 @@ window.location.href = data; }); } - function openRestoreBackup(){ + function openUploadLanguage(){ + $("#inputLanguage").click(); + } + function openRestoreBackup() { $("#inputBackup").click(); } + function uploadLanguage(event){ + let formData = new FormData(); + formData.append("file", event.files[0]); + sloader.show(); + $.ajax({ + url: "/Files/HandleTranslationFileUpload", + data: formData, + cache: false, + processData: false, + contentType: false, + type: 'POST', + success: function (response) { + sloader.hide(); + if (response.success) { + setTimeout(function () { window.location.href = '/Home/Index?tab=settings' }, 500); + } else { + errorToast(response.message); + } + }, + error: function(){ + sloader.hide(); + errorToast("An error has occurred, please check the file size and try again later."); + } + }); + } function restoreBackup(event) { let formData = new FormData(); formData.append("file", event.files[0]); @@ -261,9 +321,9 @@ type: 'POST', success: function (response) { if (response.trim() != '') { - $.post('/Files/RestoreBackup', { fileName : response}, function (data) { + $.post('/Files/RestoreBackup', { fileName: response }, function (data) { sloader.hide(); - if (data){ + if (data) { successToast("Backup Restored"); setTimeout(function () { window.location.href = '/Home/Index' }, 500); } else { @@ -271,19 +331,23 @@ } }); } + }, + error: function () { + sloader.hide(); + errorToast("An error has occurred, please check the file size and try again later."); } }); } - function enableAuthCheckChanged(){ + function enableAuthCheckChanged() { var enableAuth = $("#enableAuth").is(":checked"); if (enableAuth) { //swal dialog to set up username and password. Swal.fire({ title: 'Setup Credentials', html: ` - - - `, + + + `, confirmButtonText: 'Setup', focusConfirm: false, preConfirm: () => { diff --git a/wwwroot/defaults/en_US.json b/wwwroot/defaults/en_US.json index 8863196..36032b1 100644 --- a/wwwroot/defaults/en_US.json +++ b/wwwroot/defaults/en_US.json @@ -1 +1 @@ -{"Garage":"Garage","Settings":"Settings","Admin_Panel":"Admin Panel","Logout":"Logout","Dark_Mode":"Dark Mode","Enable_CSV_Imports":"Enable CSV Imports","Use_Imperial_Calculation_for_Fuel_Economy_Calculations(MPG)":"Use Imperial Calculation for Fuel Economy Calculations(MPG)","This_Will_Also_Change_Units_to_Miles_and_Gallons":"This Will Also Change Units to Miles and Gallons","Use_UK_MPG_Calculation":"Use UK MPG Calculation","Input_Gas_Consumption_in_Liters,_it_will_be_converted_to_UK_Gals_for_MPG_Calculation":"Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation","Sort_lists_in_Descending_Order(Newest_to_Oldest)":"Sort lists in Descending Order(Newest to Oldest)","Replace_$0.00_Costs_with_---":"Replace $0.00 Costs with ---","Use_Three_Decimals_For_Fuel_Cost":"Use Three Decimals For Fuel Cost","Display_Saved_Notes_in_Markdown":"Display Saved Notes in Markdown","Auto_Refresh_Lapsed_Recurring_Reminders":"Auto Refresh Lapsed Recurring Reminders","Auto_Insert_Odometer_Records":"Auto Insert Odometer Records","Only_when_Adding_Service/Repair/Upgrade/Fuel_Record_or_Completing_a_Plan":"Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan","Enable_Authentication":"Enable Authentication","Visible_Tabs":"Visible Tabs","Service_Records":"Service Records","Dashboard":"Dashboard","Repairs":"Repairs","Upgrades":"Upgrades","Fuel":"Fuel","Odometer":"Odometer","Taxes":"Taxes","Notes":"Notes","Reminder":"Reminder","Supplies":"Supplies","Planner":"Planner","Default_Tab":"Default Tab","Service_Record":"Service Record","Tax":"Tax","Reminders":"Reminders","Backups":"Backups","Make":"Make","Restore":"Restore","About":"About","Add_New_Vehicle":"Add New Vehicle","Year":"Year","Year(must_be_after_1900)":"Year(must be after 1900)","Model":"Model","License_Plate":"License Plate","Electric_Vehicle":"Electric Vehicle","Use_Engine_Hours":"Use Engine Hours","Tags(optional)":"Tags(optional)","Upload_a_picture(optional)":"Upload a picture(optional)","Cancel":"Cancel","Edit_Vehicle":"Edit Vehicle","Delete_Vehicle":"Delete Vehicle","Manage_Vehicle":"Manage Vehicle","Expenses_by_Type":"Expenses by Type","Service":"Service","Expenses_by_Month":"Expenses by Month","As_of_Today":"As of Today","\u002B30_Days":"\u002B30 Days","\u002B60_Days":"\u002B60 Days","\u002B90_Days":"\u002B90 Days","Not_Urgent":"Not Urgent","Urgent":"Urgent","Very_Urgent":"Very Urgent","Past_Due":"Past Due","Reminders_by_Category":"Reminders by Category","Reminders_by_Urgency":"Reminders by Urgency","Collaborators":"Collaborators","Username":"Username","Delete":"Delete","Fuel_Mileage_by_Month":"Fuel Mileage by Month","Vehicle_Maintenance_Report":"Vehicle Maintenance Report","Export_Attachments":"Export Attachments","Gasoline":"Gasoline","Last_Reported_Odometer_Reading":"Last Reported Odometer Reading","Average_Fuel_Economy":"Average Fuel Economy","Total_Spent(excl._fuel)":"Total Spent(excl. fuel)","Total_Spent_on_Fuel":"Total Spent on Fuel","Type":"Type","Date":"Date","Description":"Description","Cost":"Cost","Repair":"Repair","Upgrade":"Upgrade","#_of_Odometer_Records":"# of Odometer Records","Add_Odometer_Record":"Add Odometer Record","Import_via_CSV":"Import via CSV","Export_to_CSV":"Export to CSV","Print":"Print","Add_New_Odometer_Record":"Add New Odometer Record","Date_recorded":"Date recorded","Odometer_reading":"Odometer reading","Notes(optional)":"Notes(optional)","Upload_documents(optional)":"Upload documents(optional)","Max_File_Size:_28.6MB":"Max File Size: 28.6MB","#_of_Service_Records":"# of Service Records","Total":"Total","Add_Service_Record":"Add Service Record","No_data_found,_create_reminders_to_see_visualizations_here.":"No data found, create reminders to see visualizations here.","No_data_found,_insert/select_some_data_to_see_visualizations_here.":"No data found, insert/select some data to see visualizations here.","Edit_Odometer_Record":"Edit Odometer Record","Import_Data_from_CSV":"Import Data from CSV","In_order_for_this_utility_to_function_properly,_your_CSV_file_MUST_be_formatted_exactly_like_the_provided_sample._Dates_must_be_supplied_in_a_string._Numbers_must_be_supplied_as_numbers_without_currency_formatting.":"In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. Dates must be supplied in a string. Numbers must be supplied as numbers without currency formatting.","Failure_to_format_the_data_correctly_can_cause_data_corruption._Please_make_sure_you_make_a_copy_of_the_local_database_before_proceeding.":"Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.","Download_Sample":"Download Sample","Upload_CSV_File":"Upload CSV File","Import":"Import","Edit_Service_Record":"Edit Service Record","Date_service_was_performed":"Date service was performed","Odometer_reading_when_serviced":"Odometer reading when serviced","Description_of_item(s)_serviced(i.e._Oil_Change)":"Description of item(s) serviced(i.e. Oil Change)","Cost_of_the_service":"Cost of the service","Move_To":"Move To","#_of_Repair_Records":"# of Repair Records","Add_Repair_Record":"Add Repair Record","Add_New_Repair_Record":"Add New Repair Record","Date_repair_was_performed":"Date repair was performed","Odometer_reading_when_repaired":"Odometer reading when repaired","Description_of_item(s)_repaired(i.e._Alternator)":"Description of item(s) repaired(i.e. Alternator)","Cost_of_the_repair":"Cost of the repair","Choose_Supplies":"Choose Supplies","Add_Reminder":"Add Reminder","Select_Supplies":"Select Supplies","No_supplies_with_quantities_greater_than_0_is_found.":"No supplies with quantities greater than 0 is found.","Select":"Select","#_of_Upgrade_Records":"# of Upgrade Records","Add_Upgrade_Record":"Add Upgrade Record","Add_New_Upgrade_Record":"Add New Upgrade Record","Date_upgrade/mods_was_installed":"Date upgrade/mods was installed","Odometer_reading_when_upgraded/modded":"Odometer reading when upgraded/modded","Description_of_item(s)_upgraded/modded":"Description of item(s) upgraded/modded","Cost_of_the_upgrade/mods":"Cost of the upgrade/mods","#_of_Gas_Records":"# of Gas Records","Total_Fuel_Consumed":"Total Fuel Consumed","Total_Cost":"Total Cost","Add_Gas_Record":"Add Gas Record","Date_Refueled":"Date Refueled","Consumption":"Consumption","Fuel_Economy":"Fuel Economy","Unit_Cost":"Unit Cost","#_of_Supply_Records":"# of Supply Records","Add_Supply_Record":"Add Supply Record","Part_#":"Part #","Supplier":"Supplier","Quantity":"Quantity","Add_New_Supply_Record":"Add New Supply Record","Date_purchased":"Date purchased","Part_Number":"Part Number","Part_#/Model_#/SKU_#":"Part #/Model #/SKU #","Description_of_the_Part/Supplies":"Description of the Part/Supplies","Supplier/Vendor":"Supplier/Vendor","Part_Supplier":"Part Supplier","Edit_Supply_Record":"Edit Supply Record","Add_New_Service_Record":"Add New Service Record","Supplies_are_requisitioned_immediately_after_the_record_is_created_and_cannot_be_modified._If_you_have_incorrectly_entered_the_amount_you_needed_you_will_need_to_correct_it_in_the_Supplies_tab.":"Supplies are requisitioned immediately after the record is created and cannot be modified. If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.","In_Stock":"In Stock","Edit_Repair_Record":"Edit Repair Record","Edit_Upgrade_Record":"Edit Upgrade Record","Save_Vehicle":"Save Vehicle","Add_New_Gas_Record":"Add New Gas Record","Date_refueled":"Date refueled","Odometer_Reading":"Odometer Reading","Odometer_reading_when_refueled":"Odometer reading when refueled","Fuel_Consumption":"Fuel Consumption","Amount_of_gas_refueled":"Amount of gas refueled","Is_Filled_To_Full":"Is Filled To Full","Missed_Fuel_Up(Skip_MPG_Calculation)":"Missed Fuel Up(Skip MPG Calculation)","Cost_of_gas_refueled":"Cost of gas refueled","Unit":"Unit","#_of_Tax_Records":"# of Tax Records","Add_Tax_Record":"Add Tax Record","Add_New_Tax_Record":"Add New Tax Record","Date_tax_was_paid":"Date tax was paid","Description_of_tax_paid(i.e._Registration)":"Description of tax paid(i.e. Registration)","Cost_of_tax_paid":"Cost of tax paid","Is_Recurring":"Is Recurring","Month":"Month","1_Month":"1 Month","3_Months":"3 Months","6_Months":"6 Months","1_Year":"1 Year","2_Years":"2 Years","3_Years":"3 Years","5_Years":"5 Years","Edit_Tax_Record":"Edit Tax Record","#_of_Notes":"# of Notes","Add_Note":"Add Note","Note":"Note","Add_New_Note":"Add New Note","Pinned":"Pinned","Description_of_the_note":"Description of the note","Min_Fuel_Economy":"Min Fuel Economy","Max_Fuel_Economy":"Max Fuel Economy","Edit_Gas_Record":"Edit Gas Record","#_of_Plan_Records":"# of Plan Records","Add_Plan_Record":"Add Plan Record","Planned":"Planned","Doing":"Doing","Testing":"Testing","Done":"Done","Add_New_Plan_Record":"Add New Plan Record","Describe_the_Plan":"Describe the Plan","Cost_of_the_Plan":"Cost of the Plan","Priority":"Priority","Critical":"Critical","Normal":"Normal","Low":"Low","Current_Stage":"Current Stage","#_of_Reminders":"# of Reminders","Urgency":"Urgency","Metric":"Metric","Add_New_Reminder":"Add New Reminder","Reminder_Description":"Reminder Description","Remind_me_on":"Remind me on","Future_Date":"Future Date","Future_Odometer_Reading":"Future Odometer Reading","Whichever_comes_first":"Whichever comes first","Other":"Other","Edit_Reminder":"Edit Reminder","Replace_picture(optional)":"Replace picture(optional)"} \ No newline at end of file +{"Garage":"Garage","Settings":"Settings","Admin_Panel":"Admin Panel","Logout":"Logout","Dark_Mode":"Dark Mode","Enable_CSV_Imports":"Enable CSV Imports","Use_Imperial_Calculation_for_Fuel_Economy_Calculations(MPG)":"Use Imperial Calculation for Fuel Economy Calculations(MPG)","This_Will_Also_Change_Units_to_Miles_and_Gallons":"This Will Also Change Units to Miles and Gallons","Use_UK_MPG_Calculation":"Use UK MPG Calculation","Input_Gas_Consumption_in_Liters,_it_will_be_converted_to_UK_Gals_for_MPG_Calculation":"Input Gas Consumption in Liters, it will be converted to UK Gals for MPG Calculation","Sort_lists_in_Descending_Order(Newest_to_Oldest)":"Sort lists in Descending Order(Newest to Oldest)","Replace_$0.00_Costs_with_---":"Replace $0.00 Costs with ---","Use_Three_Decimals_For_Fuel_Cost":"Use Three Decimals For Fuel Cost","Display_Saved_Notes_in_Markdown":"Display Saved Notes in Markdown","Auto_Refresh_Lapsed_Recurring_Reminders":"Auto Refresh Lapsed Recurring Reminders","Auto_Insert_Odometer_Records":"Auto Insert Odometer Records","Only_when_Adding_Service/Repair/Upgrade/Fuel_Record_or_Completing_a_Plan":"Only when Adding Service/Repair/Upgrade/Fuel Record or Completing a Plan","Enable_Authentication":"Enable Authentication","Visible_Tabs":"Visible Tabs","Service_Records":"Service Records","Dashboard":"Dashboard","Repairs":"Repairs","Upgrades":"Upgrades","Fuel":"Fuel","Odometer":"Odometer","Taxes":"Taxes","Notes":"Notes","Reminder":"Reminder","Supplies":"Supplies","Planner":"Planner","Default_Tab":"Default Tab","Service_Record":"Service Record","Tax":"Tax","Reminders":"Reminders","Backups":"Backups","Make":"Make","Restore":"Restore","About":"About","Add_New_Vehicle":"Add New Vehicle","Year":"Year","Year(must_be_after_1900)":"Year(must be after 1900)","Model":"Model","License_Plate":"License Plate","Electric_Vehicle":"Electric Vehicle","Use_Engine_Hours":"Use Engine Hours","Tags(optional)":"Tags(optional)","Upload_a_picture(optional)":"Upload a picture(optional)","Cancel":"Cancel","Edit_Vehicle":"Edit Vehicle","Delete_Vehicle":"Delete Vehicle","Manage_Vehicle":"Manage Vehicle","Expenses_by_Type":"Expenses by Type","Service":"Service","Expenses_by_Month":"Expenses by Month","As_of_Today":"As of Today","\u002B30_Days":"\u002B30 Days","\u002B60_Days":"\u002B60 Days","\u002B90_Days":"\u002B90 Days","Not_Urgent":"Not Urgent","Urgent":"Urgent","Very_Urgent":"Very Urgent","Past_Due":"Past Due","Reminders_by_Category":"Reminders by Category","Reminders_by_Urgency":"Reminders by Urgency","Collaborators":"Collaborators","Username":"Username","Delete":"Delete","Fuel_Mileage_by_Month":"Fuel Mileage by Month","Vehicle_Maintenance_Report":"Vehicle Maintenance Report","Export_Attachments":"Export Attachments","Gasoline":"Gasoline","Last_Reported_Odometer_Reading":"Last Reported Odometer Reading","Average_Fuel_Economy":"Average Fuel Economy","Total_Spent(excl._fuel)":"Total Spent(excl. fuel)","Total_Spent_on_Fuel":"Total Spent on Fuel","Type":"Type","Date":"Date","Description":"Description","Cost":"Cost","Repair":"Repair","Upgrade":"Upgrade","#_of_Odometer_Records":"# of Odometer Records","Add_Odometer_Record":"Add Odometer Record","Import_via_CSV":"Import via CSV","Export_to_CSV":"Export to CSV","Print":"Print","Add_New_Odometer_Record":"Add New Odometer Record","Date_recorded":"Date recorded","Odometer_reading":"Odometer reading","Notes(optional)":"Notes(optional)","Upload_documents(optional)":"Upload documents(optional)","Max_File_Size:_28.6MB":"Max File Size: 28.6MB","#_of_Service_Records":"# of Service Records","Total":"Total","Add_Service_Record":"Add Service Record","No_data_found,_create_reminders_to_see_visualizations_here.":"No data found, create reminders to see visualizations here.","No_data_found,_insert/select_some_data_to_see_visualizations_here.":"No data found, insert/select some data to see visualizations here.","Edit_Odometer_Record":"Edit Odometer Record","Import_Data_from_CSV":"Import Data from CSV","In_order_for_this_utility_to_function_properly,_your_CSV_file_MUST_be_formatted_exactly_like_the_provided_sample._Dates_must_be_supplied_in_a_string._Numbers_must_be_supplied_as_numbers_without_currency_formatting.":"In order for this utility to function properly, your CSV file MUST be formatted exactly like the provided sample. Dates must be supplied in a string. Numbers must be supplied as numbers without currency formatting.","Failure_to_format_the_data_correctly_can_cause_data_corruption._Please_make_sure_you_make_a_copy_of_the_local_database_before_proceeding.":"Failure to format the data correctly can cause data corruption. Please make sure you make a copy of the local database before proceeding.","Download_Sample":"Download Sample","Upload_CSV_File":"Upload CSV File","Import":"Import","Edit_Service_Record":"Edit Service Record","Date_service_was_performed":"Date service was performed","Odometer_reading_when_serviced":"Odometer reading when serviced","Description_of_item(s)_serviced(i.e._Oil_Change)":"Description of item(s) serviced(i.e. Oil Change)","Cost_of_the_service":"Cost of the service","Move_To":"Move To","#_of_Repair_Records":"# of Repair Records","Add_Repair_Record":"Add Repair Record","Add_New_Repair_Record":"Add New Repair Record","Date_repair_was_performed":"Date repair was performed","Odometer_reading_when_repaired":"Odometer reading when repaired","Description_of_item(s)_repaired(i.e._Alternator)":"Description of item(s) repaired(i.e. Alternator)","Cost_of_the_repair":"Cost of the repair","Choose_Supplies":"Choose Supplies","Add_Reminder":"Add Reminder","Select_Supplies":"Select Supplies","No_supplies_with_quantities_greater_than_0_is_found.":"No supplies with quantities greater than 0 is found.","Select":"Select","#_of_Upgrade_Records":"# of Upgrade Records","Add_Upgrade_Record":"Add Upgrade Record","Add_New_Upgrade_Record":"Add New Upgrade Record","Date_upgrade/mods_was_installed":"Date upgrade/mods was installed","Odometer_reading_when_upgraded/modded":"Odometer reading when upgraded/modded","Description_of_item(s)_upgraded/modded":"Description of item(s) upgraded/modded","Cost_of_the_upgrade/mods":"Cost of the upgrade/mods","#_of_Gas_Records":"# of Gas Records","Total_Fuel_Consumed":"Total Fuel Consumed","Total_Cost":"Total Cost","Add_Gas_Record":"Add Gas Record","Date_Refueled":"Date Refueled","Consumption":"Consumption","Fuel_Economy":"Fuel Economy","Unit_Cost":"Unit Cost","#_of_Supply_Records":"# of Supply Records","Add_Supply_Record":"Add Supply Record","Part_#":"Part #","Supplier":"Supplier","Quantity":"Quantity","Add_New_Supply_Record":"Add New Supply Record","Date_purchased":"Date purchased","Part_Number":"Part Number","Part_#/Model_#/SKU_#":"Part #/Model #/SKU #","Description_of_the_Part/Supplies":"Description of the Part/Supplies","Supplier/Vendor":"Supplier/Vendor","Part_Supplier":"Part Supplier","Edit_Supply_Record":"Edit Supply Record","Add_New_Service_Record":"Add New Service Record","Supplies_are_requisitioned_immediately_after_the_record_is_created_and_cannot_be_modified._If_you_have_incorrectly_entered_the_amount_you_needed_you_will_need_to_correct_it_in_the_Supplies_tab.":"Supplies are requisitioned immediately after the record is created and cannot be modified. If you have incorrectly entered the amount you needed you will need to correct it in the Supplies tab.","In_Stock":"In Stock","Edit_Repair_Record":"Edit Repair Record","Edit_Upgrade_Record":"Edit Upgrade Record","Save_Vehicle":"Save Vehicle","Add_New_Gas_Record":"Add New Gas Record","Date_refueled":"Date refueled","Odometer_Reading":"Odometer Reading","Odometer_reading_when_refueled":"Odometer reading when refueled","Fuel_Consumption":"Fuel Consumption","Amount_of_gas_refueled":"Amount of gas refueled","Is_Filled_To_Full":"Is Filled To Full","Missed_Fuel_Up(Skip_MPG_Calculation)":"Missed Fuel Up(Skip MPG Calculation)","Cost_of_gas_refueled":"Cost of gas refueled","Unit":"Unit","#_of_Tax_Records":"# of Tax Records","Add_Tax_Record":"Add Tax Record","Add_New_Tax_Record":"Add New Tax Record","Date_tax_was_paid":"Date tax was paid","Description_of_tax_paid(i.e._Registration)":"Description of tax paid(i.e. Registration)","Cost_of_tax_paid":"Cost of tax paid","Is_Recurring":"Is Recurring","Month":"Month","1_Month":"1 Month","3_Months":"3 Months","6_Months":"6 Months","1_Year":"1 Year","2_Years":"2 Years","3_Years":"3 Years","5_Years":"5 Years","Edit_Tax_Record":"Edit Tax Record","#_of_Notes":"# of Notes","Add_Note":"Add Note","Note":"Note","Add_New_Note":"Add New Note","Pinned":"Pinned","Description_of_the_note":"Description of the note","Min_Fuel_Economy":"Min Fuel Economy","Max_Fuel_Economy":"Max Fuel Economy","Edit_Gas_Record":"Edit Gas Record","#_of_Plan_Records":"# of Plan Records","Add_Plan_Record":"Add Plan Record","Planned":"Planned","Doing":"Doing","Testing":"Testing","Done":"Done","Add_New_Plan_Record":"Add New Plan Record","Describe_the_Plan":"Describe the Plan","Cost_of_the_Plan":"Cost of the Plan","Priority":"Priority","Critical":"Critical","Normal":"Normal","Low":"Low","Current_Stage":"Current Stage","#_of_Reminders":"# of Reminders","Urgency":"Urgency","Metric":"Metric","Add_New_Reminder":"Add New Reminder","Reminder_Description":"Reminder Description","Remind_me_on":"Remind me on","Future_Date":"Future Date","Future_Odometer_Reading":"Future Odometer Reading","Whichever_comes_first":"Whichever comes first","Other":"Other","Edit_Reminder":"Edit Reminder","Replace_picture(optional)":"Replace picture(optional)","Language":"Language","Manage_Languages":"Manage Languages","Upload":"Upload","Tokens":"Tokens","Generate_User_Token":"Generate User Token","Auto_Notify(via_Email)":"Auto Notify(via Email)","Token":"Token","Issued_To":"Issued To","Users":"Users","Email":"Email","Is_Admin":"Is Admin"} \ No newline at end of file

UsernameEmailIs AdminDelete@translator.Translate(userLanguage, "Username")@translator.Translate(userLanguage, "Email")@translator.Translate(userLanguage, "Is Admin")@translator.Translate(userLanguage, "Delete")