diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/CATEGORIES.json b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/CATEGORIES.json deleted file mode 100644 index 394ebd71a5..0000000000 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/CATEGORIES.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "categories": [ - { - "key": "Detect", - "value": "Виявляти", - "category1": "[UK]Detect" - }, - { - "key": "Govern", - "value": "Керувати", - "category1": "[UK]Govern" - }, - { - "key": "Identify", - "value": "Ідентифікувати", - "category1": "[UK]Identify" - }, - { - "key": "Protect", - "value": "Захищати", - "category1": "[UK]Protect" - }, - { - "key": "Recover", - "value": "Відновити", - "category1": "[UK]Recover" - }, - { - "key": "Respond", - "value": "Відповісти", - "category1": "[UK]Respond" - }, - { - "key": "Access Control", - "value": "Управління доступом", - "category1": "[UK]Access Control" - }, - { - "key": "Analysis", - "value": "Аналіз", - "category1": "[UK]Analysis" - }, - { - "key": "Anomalies and Events", - "value": "Аномалії та події", - "category1": "[UK]Anomalies and Events" - }, - { - "key": "Asset Management", - "value": "Управління активами", - "category1": "[UK]Asset Management" - }, - { - "key": "Awareness and Training", - "value": "Обізнаність і навчання", - "category1": "[UK]Awareness and Training" - }, - { - "key": "Business Environment", - "value": "Бізнес середовище", - "category1": "[UK]Business Environment" - }, - { - "key": "Data Security", - "value": "Безпека даних", - "category1": "[UK]Data Security" - }, - { - "key": "Detection Processes", - "value": "Процеси виявлення", - "category1": "[UK]Detection Processes" - }, - { - "key": "Governance", - "value": "Управління", - "category1": "[UK]Governance" - }, - { - "key": "Improvements", - "value": "Покращення", - "category1": "[UK]Improvements" - }, - { - "key": "Information Protection Processes and Procedures", - "value": "Процеси та процедури захисту інформації", - "category1": "[UK]Information Protection Processes and Procedures" - }, - { - "key": "Maintenance", - "value": "Технічне обслуговування", - "category1": "[UK]Maintenance" - }, - { - "key": "Mitigation", - "value": "Пом'якшення", - "category1": "[UK]Mitigation" - }, - { - "key": "Protective Technology", - "value": "Захисна техніка", - "category1": "[UK]Protective Technology" - }, - { - "key": "Recovery Communications", - "value": "Відновлення комунікацій", - "category1": "[UK]Recovery Communications" - }, - { - "key": "Recovery Planning", - "value": "Планування відновлення", - "category1": "[UK]Recovery Planning" - }, - { - "key": "Response Communications", - "value": "Комунікації у відповідь", - "category1": "[UK]Response Communications" - }, - { - "key": "Response Planning", - "value": "Планування реагування", - "category1": "[UK]Response Planning" - }, - { - "key": "Risk Assessment", - "value": "Оцінка ризиків", - "category1": "[UK]Risk Assessment" - }, - { - "key": "Risk Management", - "value": "Управління ризиками", - "category1": "[UK]Risk Management" - }, - { - "key": "Risk Management Strategy", - "value": "Стратегія управління ризиками", - "category1": "[UK]Risk Management Strategy" - }, - { - "key": "Security Continuous Monitoring", - "value": "Постійний моніторинг безпеки", - "category1": "[UK]Security Continuous Monitoring" - } - ] -} diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/GENERIC.json b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/GENERIC.json index 858c2f3ad7..09c98f3740 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/GENERIC.json +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/GENERIC.json @@ -1,20 +1,6 @@ { - "pairs": [ - { - "key": "overall", - "value": "Загалом" - }, - { - "key": "standards", - "value": "Стандарти" - }, - { - "key": "default exec summ", - "value": "[UK]Cyber terrorism is a real and growing threat. Standards and guides have been developed, vetted, and widely accepted to assist with protection from cyber attacks. The Cyber Security Evaluation Tool (CSET) includes a selectable array of these standards for a tailored assessment of cyber vulnerabilities. Once the standards were selected and the resulting question sets answered, the CSET created a compliance summary, compiled variance statistics, ranked top areas of concern, and generated security recommendations." - }, - { - "key": "default assessment name", - "value": "Нова оцінка" - } - ] + "overall": "Загалом", + "standards": "Стандарти", + "default exec summ": "[UK]Cyber terrorism is a real and growing threat. Standards and guides have been developed, vetted, and widely accepted to assist with protection from cyber attacks. The Cyber Security Evaluation Tool (CSET) includes a selectable array of these standards for a tailored assessment of cyber vulnerabilities. Once the standards were selected and the resulting question sets answered, the CSET created a compliance summary, compiled variance statistics, ranked top areas of concern, and generated security recommendations.", + "default assessment name": "Нова оцінка" } \ No newline at end of file diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/STANDARD_CATEGORY.json b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/STANDARD_CATEGORY.json new file mode 100644 index 0000000000..810faed181 --- /dev/null +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/App_Data/LanguagePacks/UK/STANDARD_CATEGORY.json @@ -0,0 +1,30 @@ +{ + "detect": "Виявляти", + "govern": "Керувати", + "identify": "Ідентифікувати", + "protect": "Захищати", + "recover": "Відновити", + "respond": "Відповісти", + "access control": "Управління доступом", + "analysis": "Аналіз", + "anomalies and events": "Аномалії та події", + "asset management": "Управління активами", + "awareness and training": "Обізнаність і навчання", + "business environment": "Бізнес середовище", + "data security": "Безпека даних", + "detection processes": "Процеси виявлення", + "governance": "Управління", + "improvements": "Покращення", + "information protection processes and procedures": "Процеси та процедури захисту інформації", + "maintenance": "Технічне обслуговування", + "mitigation": "Пом'якшення", + "protective technology": "Захисна техніка", + "recovery communications": "Відновлення комунікацій", + "recovery planning": "Планування відновлення", + "response communications": "Комунікації у відповідь", + "response planning": "Планування реагування", + "risk assessment": "Оцінка ризиків", + "risk management": "Управління ризиками", + "risk management strategy": "Стратегія управління ризиками", + "security continuous monitoring": "Постійний моніторинг безпеки" +} diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs index b9597b90ef..fd6f45e5f2 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs @@ -72,13 +72,13 @@ public AssessmentDetail CreateNewAssessment(int? currentUserId, string workflow, var lang = _tokenManager.GetCurrentLanguage(); if (lang != "en") { - var msg = _overlay.GetValue("GENERIC", "default exec summ", lang)?.Value; + var msg = _overlay.GetPropertyValue("GENERIC", "default exec summ", lang); if (msg != null) { defaultExecSumm = msg; } - msg = _overlay.GetValue("GENERIC", "default assessment name", lang)?.Value; + msg = _overlay.GetPropertyValue("GENERIC", "default assessment name", lang); if (msg != null) { defaultAssessmentName = msg; diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/CSETWebCore.Business.csproj b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/CSETWebCore.Business.csproj index 3d4b561560..19f5456e99 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/CSETWebCore.Business.csproj +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/CSETWebCore.Business.csproj @@ -138,9 +138,6 @@ Always - - Always - Always @@ -177,6 +174,9 @@ Always + + Always + Always diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/ModuleBuilder/ModuleBuilderBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/ModuleBuilder/ModuleBuilderBusiness.cs index cdb3d50460..27861dbde6 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/ModuleBuilder/ModuleBuilderBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/ModuleBuilder/ModuleBuilderBusiness.cs @@ -1261,16 +1261,16 @@ from r in _context.NEW_REQUIREMENT.Where(x => x.Requirement_Id == rs.Requirement foreach (NEW_REQUIREMENT rq in reqs) { // overlay - var translatedCategory = _overlay.GetCat(rq.Standard_Category, _lang); + var translatedCategory = _overlay.GetPropertyValue("STANDARD_CATEGORY", rq.Standard_Category.ToLower(), _lang); if (translatedCategory != null) { - rq.Standard_Category = translatedCategory.Value; + rq.Standard_Category = translatedCategory; } - var translatedSubcat = _overlay.GetCat(rq.Standard_Sub_Category, _lang); + var translatedSubcat = _overlay.GetPropertyValue("STANDARD_CATEGORY", rq.Standard_Sub_Category.ToLower(), _lang); if (translatedSubcat != null) { - rq.Standard_Sub_Category = translatedSubcat.Value; + rq.Standard_Sub_Category = translatedSubcat; } Requirement r = new Requirement() diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/QuestionInformationTabData.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/QuestionInformationTabData.cs index dadcda2179..0d6f7310a7 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/QuestionInformationTabData.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/QuestionInformationTabData.cs @@ -28,6 +28,8 @@ public class QuestionInformationTabData private readonly ITokenManager _tokenManager; + private readonly TranslationOverlay _overlay; + public String RequirementFrameworkTitle { get; set; } public String RelatedFrameworkCategory { get; set; } @@ -104,9 +106,14 @@ public QuestionInformationTabData(CSETWebCore.Interfaces.Common.IHtmlFromXamlCon _converter = converter; _context = context; _tokenManager = token; + + _overlay = new TranslationOverlay(); } + /// + /// + /// public void BuildQuestionTab(QuestionInfoData infoData, SETS set) { ShowRequirementFrameworkTitle = true; @@ -114,14 +121,28 @@ public void BuildQuestionTab(QuestionInfoData infoData, SETS set) } + /// + /// + /// internal void BuildRelatedQuestionTab(RelatedQuestionInfoData questionInfoData, SETS set) { BuildFromNewQuestion(questionInfoData, set); ShowRelatedFrameworkCategory = true; ShowRequirementFrameworkTitle = true; RelatedFrameworkCategory = questionInfoData.Category; + + var lang = _tokenManager.GetCurrentLanguage(); + var cat = _overlay.GetPropertyValue("STANDARD_CATEGORY", questionInfoData.Category.ToLower(), lang); + if (cat != null) + { + RelatedFrameworkCategory = cat; + } } + + /// + /// + /// private NEW_QUESTION BuildFromNewQuestion(BaseQuestionInfoData infoData, SETS set) { NEW_QUESTION question = infoData.Question; @@ -257,10 +278,20 @@ join q in _context.NEW_QUESTION on rq.Question_Id equals q.Question_Id } if (!IsComponent) + { RequirementFrameworkTitle = requirement.Requirement_Title; + } RelatedFrameworkCategory = requirement.Standard_Sub_Category; + // translate category + var cat = _overlay.GetPropertyValue("STANDARD_CATEGORY", requirement.Standard_Sub_Category.ToLower(), lang); + if (cat != null) + { + RelatedFrameworkCategory = cat; + } + + if (requirementData.SetName == StandardConstants.CNSSI_1253_DB || requirementData.SetName == StandardConstants.CNSSI_ICS_PIT_DB || requirementData.SetName == StandardConstants.CNSSI_ICS_V1_DB || requirementData.SetName == StandardConstants.CNSSI_1253_V2_DB) { diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/RequirementBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/RequirementBusiness.cs index fdbe8d352e..68315f2f0d 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/RequirementBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/RequirementBusiness.cs @@ -149,10 +149,10 @@ public QuestionResponse BuildResponse(List requirements, // translate the Category - var translatedCategory = overlay.GetCat(dbR.Standard_Category, lang); + var translatedCategory = overlay.GetPropertyValue("STANDARD_CATEGORY", dbR.Standard_Category.ToLower(), lang); if (translatedCategory != null) { - dbR.Standard_Category = translatedCategory.Value; + dbR.Standard_Category = translatedCategory; } @@ -172,10 +172,10 @@ public QuestionResponse BuildResponse(List requirements, // translate the Subcategory using the CATEGORIES translation object - var translatedSubcategory = overlay.GetCat(dbR.Standard_Sub_Category, lang); + var translatedSubcategory = overlay.GetPropertyValue("STANDARD_CATEGORY", dbR.Standard_Sub_Category.ToLower(), lang); if (translatedSubcategory != null) { - dbR.Standard_Sub_Category = translatedSubcategory.Value; + dbR.Standard_Sub_Category = translatedSubcategory; } diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/TranslationOverlay.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/TranslationOverlay.cs index c09f51a3a4..6da379edd5 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/TranslationOverlay.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/TranslationOverlay.cs @@ -1,28 +1,41 @@ -using CSETWebCore.Interfaces.Helpers; -using CSETWebCore.Model.Edm; -using CSETWebCore.Model.Question; -using CSETWebCore.Model.Set; -using Microsoft.EntityFrameworkCore; +using CSETWebCore.Model.Question; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Org.BouncyCastle.Asn1.Pkcs; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; + namespace CSETWebCore.Helpers { /// /// Manages translation lookup based on language pack - /// information stored in App_Data/LanguagePacks + /// information stored in App_Data/LanguagePacks. + /// + /// Provides several methods to get at the data, depending on + /// how it is stored in the language pack. /// public class TranslationOverlay { - private Dictionary dict = new Dictionary(); + /// + /// A dictionary of loaded JArray language packs + /// + private Dictionary dictJA = new Dictionary(); + + /// + /// A dictionary of loaded JObject language packs + /// + private Dictionary dictJO = new Dictionary(); + + /// + /// A dictionary of loaded RequirementTranslations language packs + /// private Dictionary dReq = new Dictionary(); - private Dictionary dCat = new Dictionary(); - private Dictionary dKVP = new Dictionary(); + + /// + /// A dictionary of loaded GenericTranslation language packs + /// + private Dictionary dictGeneric = new Dictionary(); /// @@ -39,11 +52,10 @@ public JObject GetJObject(string collection, string keyFieldName, string key, st } lang = lang.ToLower(); - collection = collection.ToLower(); - var kvpKey = $"{lang}|{collection}"; + var dictKey = $"{lang}|{collection.ToLower()}"; - if (!dict.ContainsKey(kvpKey)) + if (!dictJA.ContainsKey(dictKey)) { var rh = new ResourceHelper(); var json = rh.GetCopiedResource(System.IO.Path.Combine("app_data", "LanguagePacks", lang, $"{collection}.json")); @@ -53,13 +65,13 @@ public JObject GetJObject(string collection, string keyFieldName, string key, st return null; } - langPack = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + langPack = JsonConvert.DeserializeObject(json); - dict.Add(kvpKey, langPack); + dictJA.Add(dictKey, langPack); } else { - langPack = dict[kvpKey]; + langPack = dictJA[dictKey]; } var target = langPack.Children().FirstOrDefault(x => x.SelectToken(keyFieldName).Value().Equals(key, StringComparison.InvariantCultureIgnoreCase)); @@ -69,25 +81,27 @@ public JObject GetJObject(string collection, string keyFieldName, string key, st /// - /// Generically gets a value for the specified key and collection. - /// Collection indicates the name of the JSON file. + /// Returns the string value of the property name. This works on a JSON file + /// that represents a single object with multiple properties. + /// + /// This JSON layout is similar to a transloco language file. + /// + /// Returns null if the property is not defined. /// - public Model.Question.KeyValuePair GetValue(string collection, string key, string lang) + /// + public string GetPropertyValue(string collection, string propertyName, string lang) { - GenericTranslation langPack = null; - - // trying to get out cheaply and not waste time looking up English if (lang == "en") { return null; } lang = lang.ToLower(); - collection = collection.ToLower(); - var kvpKey = $"{lang}|{collection}"; + var dictKey = $"{lang}|{collection.ToLower()}"; - if (!dKVP.ContainsKey(kvpKey)) + JObject langPack; + if (!dictJO.ContainsKey(dictKey)) { var rh = new ResourceHelper(); var json = rh.GetCopiedResource(System.IO.Path.Combine("app_data", "LanguagePacks", lang, $"{collection}.json")); @@ -97,58 +111,70 @@ public Model.Question.KeyValuePair GetValue(string collection, string key, strin return null; } - langPack = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + langPack = JsonConvert.DeserializeObject(json); - dKVP.Add(kvpKey, langPack); + dictJO.Add(dictKey, langPack); } else { - langPack = dKVP[kvpKey]; + langPack = dictJO[dictKey]; } - - return langPack.Pairs.FirstOrDefault(x => x.Key.ToLower() == key.ToLower()); + // adjust propertyName if segments have spaces to make SelectToken happy + var segs = propertyName.Split('.'); + for (var i = 0; i < segs.Length; i++) + { + if (segs[i].Contains(' ')) + { + segs[i] = $"['{segs[i]}']"; + } + } + propertyName = string.Join(".", segs); + + + return langPack.SelectToken(propertyName)?.Value() ?? null; } /// - /// Lazy loads the CATEGORIES language pack and tries to get - /// a value for the specified key. + /// Generically gets a value for the specified key and collection. + /// Collection indicates the name of the JSON file. /// - /// - /// - /// - public Model.Question.KeyValuePair GetCat(string category, string lang) + public Model.Question.KeyValuePair GetValue(string collection, string key, string lang) { - CategoryTranslation langPack = null; + GenericTranslation langPack = null; + // trying to get out cheaply and not waste time looking up English if (lang == "en") { return null; } - if (!dCat.ContainsKey(lang)) + lang = lang.ToLower(); + + var dictKey = $"{lang}|{collection.ToLower()}"; + + if (!dictGeneric.ContainsKey(dictKey)) { var rh = new ResourceHelper(); - var json = rh.GetCopiedResource(System.IO.Path.Combine("app_data", "LanguagePacks", lang, "CATEGORIES.json")); + var json = rh.GetCopiedResource(System.IO.Path.Combine("app_data", "LanguagePacks", lang, $"{collection}.json")); - // safety in case the language pack doesn't exist if (json == null) { return null; } + langPack = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - langPack = Newtonsoft.Json.JsonConvert.DeserializeObject(json); - - dCat.Add(lang, langPack); + dictGeneric.Add(dictKey, langPack); } else { - langPack = dCat[lang]; + langPack = dictGeneric[dictKey]; } - return langPack.Categories.FirstOrDefault(x => x.Key.ToLower() == category.ToLower()); + + return langPack.Pairs.FirstOrDefault(x => x.Key.ToLower() == key.ToLower()); } @@ -165,7 +191,7 @@ public RequirementTranslation GetReq(int requirementId, string lang) return null; } - if (!dReq.ContainsKey(lang)) + if (!dReq.TryGetValue(lang, out RequirementTranslations value)) { var rh = new ResourceHelper(); var json = rh.GetCopiedResource(System.IO.Path.Combine("app_data", "LanguagePacks", lang, "NEW_REQUIREMENT.json")); @@ -176,13 +202,13 @@ public RequirementTranslation GetReq(int requirementId, string lang) return null; } - langPack = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + langPack = JsonConvert.DeserializeObject(json); dReq.Add(lang, langPack); } else { - langPack = dReq[lang]; + langPack = value; } return langPack.Requirements.FirstOrDefault(x => x.RequirementId == requirementId); diff --git a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AnalysisController.cs b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AnalysisController.cs index 317b3f9a4c..b5206a8456 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AnalysisController.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AnalysisController.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using CSETWebCore.Business.Authorization; using CSETWebCore.DataLayer.Model; using CSETWebCore.Helpers; @@ -18,6 +17,7 @@ using CSETWebCore.Model.Analysis; using CSETWebCore.Model.Question; using Snickler.EFCore; +using Newtonsoft.Json.Linq; using Microsoft.EntityFrameworkCore; namespace CSETWebCore.Api.Controllers @@ -73,13 +73,34 @@ public IActionResult GetAnswerColors() [Route("api/analysis/RankedQuestions")] public IActionResult GetRankedQuestions() { + var lang = _tokenManager.GetCurrentLanguage(); + int assessmentId = _tokenManager.AssessmentForUser(); _requirement.SetRequirementAssessmentId(assessmentId); + string mode = GetAssessmentMode(assessmentId); + var rankedQuestionList = _context.usp_GetRankedQuestions(assessmentId).ToList(); foreach (usp_GetRankedQuestions_Result q in rankedQuestionList) { + // Currently we only translate text for REQUIREMENTS + if (mode == "R") + { + var translatedReq = _overlay.GetReq(q.QuestionOrRequirementID, lang); + if (translatedReq != null) + { + q.QuestionText = translatedReq.RequirementText; + + var translatedCategory = _overlay.GetPropertyValue("STANDARD_CATEGORY", q.Category.ToLower(), lang); + if (translatedCategory != null) + { + q.Category = translatedCategory; + } + } + } + + q.QuestionText = _requirement.ResolveParameters(q.QuestionOrRequirementID, q.AnswerID, q.QuestionText); } @@ -329,7 +350,7 @@ public IActionResult GetDashboard() string label = j.Item1; overallBars.EnglishLabels.Add(j.Item1); - overallBars.Labels.Add(_overlay.GetValue("GENERIC", j.Item1, lang)?.Value ?? j.Item1); + overallBars.Labels.Add(_overlay.GetPropertyValue("GENERIC", j.Item1.ToLower(), lang) ?? j.Item1); overallBars.data.Add(j.Item2); } diff --git a/CSETWebNg/src/assets/i18n/uk.json b/CSETWebNg/src/assets/i18n/uk.json index 69baaebe8d..849c6ca167 100644 --- a/CSETWebNg/src/assets/i18n/uk.json +++ b/CSETWebNg/src/assets/i18n/uk.json @@ -508,8 +508,8 @@ "text": "Ця діаграма показує відсотки відповідей на основі компонентів або діаграм мережі для кожного окремого типу відповіді." }, "results by category": { - "title": "[UK]Results by Category", - "text": "[UK]This chart shows the individual scores for each of the categories from a positive perspective. High scores on this chart show areas of strength." + "title": "Результати за категоріями", + "text": "Ця діаграма показує індивідуальні бали для кожної категорії з позитивної точки зору. Високі показники на цій діаграмі вказують на сильні сторони." }, "no ranking": "Інформацію про рейтинг не можна визначити для поточного набору запитань. Неможливо відобразити діаграму рейтингових категорій.", "disclaimer": "Цей звіт було підготовлено як звіт про роботу, спонсоровану агентством уряду США. Ані уряд США, ані будь-яке його агентство, ані будь-який працівник не надає жодних гарантій, явних чи неявних, і не бере на себе жодної юридичної відповідальності за будь-яке використання третіми особами чи результати такого використання чи будь-яку інформацію, пристрій, продукт, або процес, описаний у цій публікації, або заявляє, що його використання такою третьою стороною не порушуватиме права приватної власності."