diff --git a/.gitignore b/.gitignore index 4d8e5d72f..90e2dd891 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ **/node_modules/ .vscode *.sqlite3 +django_secret_key temp/ db/ diff --git a/backend/core/helpers.py b/backend/core/helpers.py index 4592de23e..fe2b09699 100644 --- a/backend/core/helpers.py +++ b/backend/core/helpers.py @@ -1,4 +1,5 @@ from datetime import date, timedelta +from re import sub from django.db.models import Count from django.shortcuts import get_object_or_404 @@ -23,6 +24,11 @@ "transfer": "#91cc75", } +def camel_case(s): + s = sub(r"(_|-)+", " ", s).title().replace(" ", "") + + return ''.join([s[0].lower(), s[1:]]) + def security_measure_priority(user: User): def get_quadrant(security_measure): @@ -410,6 +416,7 @@ def risk_per_status(user: User): def security_measure_per_status(user: User): values = list() labels = list() + local_lables = list() color_map = { "--": "#93c5fd", "planned": "#fdba74", @@ -432,7 +439,8 @@ def security_measure_per_status(user: User): v = {"value": count, "itemStyle": {"color": color_map[st[0]]}} values.append(v) labels.append(st[1]) - return {"labels": labels, "values": values} + local_lables = [camel_case(str(l)) for l in labels] + return {"localLables": local_lables,"labels": labels, "values": values} def security_measure_per_cur_risk(user: User): @@ -526,7 +534,6 @@ def aggregate_risks_per_field( values[m["risk"][i][field]]["count"] += count return values - def risks_count_per_level(user: User, risk_assessments: list | None = None): current_level = list() residual_level = list() @@ -535,14 +542,14 @@ def risks_count_per_level(user: User, risk_assessments: list | None = None): user, "name", risk_assessments=risk_assessments ).items(): current_level.append( - {"name": r[0], "value": r[1]["count"], "color": r[1]["color"]} + {"name": r[0], "value": r[1]["count"], "color": r[1]["color"], "localName": camel_case(r[0])} ) for r in aggregate_risks_per_field( user, "name", residual=True, risk_assessments=risk_assessments ).items(): residual_level.append( - {"name": r[0], "value": r[1]["count"], "color": r[1]["color"]} + {"name": r[0], "value": r[1]["count"], "color": r[1]["color"], "localName": camel_case(r[0])} ) return {"current": current_level, "residual": residual_level} diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 5816b0994..faecb3f4e 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,5 +1,177 @@ { "$schema": "https://inlang.com/schema/inlang-message-format", - "Home": "Home", - "Overview": "Overview" + "addButton": "Add {model}", + "associatedObject": "Associated {model}", + "french": "French", + "english": "English", + "home": "Home", + "edit": "Edit", + "overview": "Overview", + "context": "Context", + "governance": "Governance", + "risk": "Risk", + "compliance": "Compliance", + "organization": "Organisation", + "extra": "Extra", + "analytics": "Analytics", + "calendar": "Calendar", + "threats": "Threats", + "securityFunctions": "Security functions", + "securityMeasures": "Security measures", + "assets": "Assets", + "asset": "Asset", + "policies": "Policies", + "riskMatrices": "Risk matrices", + "riskAssessments": "Risk assessments", + "riskScenarios": "Risk scenarios", + "riskScenario": "Risk scenario", + "riskAcceptances": "Risk acceptances", + "riskAcceptance": "Risk acceptance", + "complianceAssessments": "Compliance assessments", + "complianceAssessment": "Compliance assessment", + "evidences": "Evidences", + "evidence": "Evidence", + "frameworks": "Frameworks", + "domains": "Domains", + "projects": "Projects", + "users": "Users", + "user": "User", + "userGroups": "User groups", + "roleAssignments": "Role assignments", + "xRays": "X-rays", + "scoringAssistant": "Scoring assistant", + "libraries": "Libraries", + "backupRestore": "Backup & restore", + "myProfile": "My profile", + "aboutCiso": "About CISO Assistant", + "Logout": "Log out", + "name": "Name", + "description": "Description", + "parentDomain": "Parent domain", + "ref": "Ref", + "refId": "Ref ID", + "businessValue": "Business value", + "email": "Email", + "firstName": "First name", + "lastName": "Last name", + "category": "Category", + "eta": "ETA", + "securityFunction": "Security function", + "securityMeasure": "Security measure", + "provider": "Provider", + "domain": "Domain", + "urn": "URN", + "id": "ID", + "treatmentStatus": "Treatment status", + "currentLevel": "Current level", + "residualLevel": "Residual level", + "riskMatrix": "Risk matrix", + "project": "Project", + "folder": "Folder", + "riskAssessment": "Risk assessment", + "threat": "Threat", + "framework": "Framework", + "file": "File", + "language": "Language", + "builtin": "Builtin", + "next": "Next", + "previous": "Previous", + "show": "Show", + "entries": "entries", + "searchPlaceholder": "Search...", + "noEntriesFound": "No entries found", + "rowCount": "Showing {start} to {end} of {total}", + "status": "Status", + "effort": "Effort", + "impact": "Impact", + "expiryDate": "Expiry date", + "link": "Link", + "createdAt": "Created at", + "updatedAt": "Updated at", + "acceptedAt": "Accepted at", + "rejectedAt": "Rejected at", + "revokedAt": "Revoked at", + "locale": "Locale", + "defaultLocale": "Default locale", + "annotation": "Annotation", + "library": "Library", + "typicalEvidence": "Typical evidence", + "parentAsset": "Parent asset", + "parentAssets": "Parent assets", + "approver": "Approver", + "state": "State", + "justification": "Justification", + "parentFolder": "Parent folder", + "contentType": "Content type", + "lcStatus": "Status", + "internalReference": "Internal reference", + "isActive": "Is active", + "dateJoined": "Date joined", + "version": "Version", + "treatment": "Treatment", + "currentProba": "Current probability", + "currentImpact": "Current impact", + "residualProba": "Residual probability", + "residualImpact": "Residual impact", + "existingMeasures": "Existing measures", + "strengthOfKnowledge": "Strength of knowledge", + "dueDate": "Due date", + "attachment": "Attachment", + "observation": "Observation", + "importMatrices": "Import matrices", + "importFrameworks": "Import frameworks", + "summary": "Summary", + "composer": "Composer", + "statistics": "Statistics", + "myProjects": "My projects", + "scenarios": "Scenarios", + "assignedObjects": "Assigned to {number} {object}", + "currentRiskLevelPerScenario": "Current risk level per risk scenario", + "residualRiskLevelPerScenario": "Residual risk level per risk scenario", + "securityMeasuresStatus": "Security measures status", + "currentRisk": "Current risk", + "residualRisk": "Residual risk", + "veryLow": "Very low", + "low": "Low", + "medium": "Medium", + "high": "High", + "veryHigh": "Very high", + "planned": "Planned", + "active": "Active", + "inactive": "Inactive", + "watchlist": "Watch list", + "watchlistDescription": "Items that have expired or with close ETA", + "measuresToReview": "Measures to review", + "exceptionsToReview": "Exceptions to review", + "expired": "Expired", + "upcoming": "Upcoming", + "today": "Today", + "actionRequested": "Action requested", + "noObjectYet": "No {object} yet", + "authors": "Authors", + "reviewers": "Reviewers", + "process": "Process", + "selectTargets": "Select your targets", + "composerDescription": "This will help you aggregate multiple components (projects) to get the compiled view on your risk. This is particularly useful for two use cases", + "composerDescription1": "business intelligence approach to focus on a specific subset across different project domains (eg. across divisions)", + "composerDescription2": "you are interested in the risk assessment of a specific system, for which you need the risk assessment of the underlying components", + "overallCompliance": "Overall compliance", + "exportButton": "Export", + "treatmentProgressOverview": "Treatment progress overview", + "pendingMeasures": "Your pending measures", + "orderdByRankingScore": "Ordered by ranking score", + "rankingScore": "Ranking score", + "noPendingObject": "No pending {object}", + "rankingScoreDefintion": "Ranking score is an adaptive metric that combines the information of effort and current risk level, and crosses it with the other data to assist you for the prioritization", + "actions": "Actions", + "projectsSummaryEmpty": "Projects summary is empty", + "riskOpen": "Risk: open", + "riskMitigate": "Risk: mitigate", + "riskAccept": "Risk: accept", + "riskAvoid": "Risk: avoid", + "measureOpen": "Measure: open", + "measureProgress": "Measure: in progress", + "measureHold": "Measure: on hold", + "measureDone": "Measure: done" + } diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json index 4d4a17a3f..124e7f29a 100644 --- a/frontend/messages/fr.json +++ b/frontend/messages/fr.json @@ -1,5 +1,177 @@ { "$schema": "https://inlang.com/schema/inlang-message-format", - "Home": "Accueil", - "Overview": "Vue d'ensemble" + "addButton": "Ajouter {determinant} {model}", + "associatedObject": "{model} associé{e}s", + "french": "Français", + "english": "Anglais", + "home": "Accueil", + "edit": "Modifier", + "overview": "Vue d'ensemble", + "context": "Contexte", + "governance": "Gouvernance", + "risk": "Risque", + "compliance": "Conformité", + "organization": "Organisation", + "extra": "Extra", + "analytics": "Analytiques", + "calendar": "Calendrier", + "threats": "Menaces", + "securityFunctions": "Fonctions de sécurité", + "securityMeasures": "Mesures de sécurité", + "assets": "Biens sensibles", + "asset": "Bien sensible", + "policies": "Politiques", + "riskMatrices": "Matrices de risque", + "riskAssessments": "Évaluations de risque", + "riskScenarios": "Scénarios de risque", + "riskScenario": "Scénario de risque", + "riskAcceptances": "Acceptations de risque", + "riskAcceptance": "Acceptation de risque", + "complianceAssessments": "Évaluations de conformité", + "complianceAssessment": "Évaluation de conformité", + "evidences": "Preuves", + "evidence": "Preuve", + "frameworks": "Cadres", + "domains": "Domaines", + "projects": "Projets", + "users": "Utilisateurs", + "user": "Utilisateur", + "userGroups": "Groupes d'utilisateurs", + "roleAssignments": "Affectations de rôle", + "xRays": "X-rays", + "scoringAssistant": "Assistat d'évaluation", + "libraries": "Bibliothèques", + "backupRestore": "Sauvegarde et restauration", + "myProfile": "Mon profil", + "aboutCiso": "À propos de CISO Assistant", + "Logout": "Se déconnecter", + "name": "Nom", + "description": "Description", + "parentDomain": "Domaine parent", + "ref": "Réf", + "refId": "ID de référence", + "businessValue": "Valeur commerciale", + "email": "E-mail", + "firstName": "Prénom", + "lastName": "Nom de famille", + "category": "Catégorie", + "eta": "ETA", + "securityFunction": "Fonction de sécurité", + "securityMeasure": "Mesure de sécurité", + "provider": "Fournisseur", + "domain": "Domaine", + "urn": "URN", + "id": "ID", + "treatmentStatus": "Statut de traitement", + "currentLevel": "Niveau actuel", + "residualLevel": "Niveau résiduel", + "riskMatrix": "Matrice de risque", + "project": "Projet", + "folder": "Domaine", + "riskAssessment": "Évaluation de risque", + "threat": "Menace", + "framework": "Cadre", + "file": "Fichier", + "language": "Langue", + "builtin": "Intégré", + "next": "Suivant", + "previous": "Précédent", + "show": "Afficher", + "entries": "entrées", + "searchPlaceholder": "Rechercher...", + "noEntriesFound": "Aucune entrée trouvée", + "rowCount": "Affichage de {start} à {end} sur {total}", + "status": "Statut", + "effort": "Effort", + "impact": "Impact", + "expiryDate": "Date d'expiration", + "link": "Lien", + "createdAt": "Créé le", + "updatedAt": "Mis à jour le", + "acceptedAt": "Accepté le", + "rejectedAt": "Rejeté le", + "revokedAt": "Révoqué le", + "locale": "Locale", + "defaultLocale": "Locale par défaut", + "annotation": "Annotation", + "library": "Bibliothèque", + "typicalEvidence": "Preuve typique", + "parentAsset": "Bien sensible parent", + "parentAssets": "Biens sensibles parents", + "approver": "Approbateur", + "state": "État", + "justification": "Justification", + "parentFolder": "Domaine parent", + "contentType": "Type de contenu", + "lcStatus": "Statut", + "internalReference": "Référence interne", + "isActive": "Est actif", + "dateJoined": "Date d'adhésion", + "version": "Version", + "treatment": "Traitement", + "currentProba": "Probabilité actuelle", + "currentImpact": "Impact actuel", + "residualProba": "Probabilité résiduelle", + "residualImpact": "Impact résiduel", + "existingMeasures": "Mesures existantes", + "strengthOfKnowledge": "Expertise", + "dueDate": "Date d'échéance", + "attachment": "Pièce jointe", + "observation": "Observation", + "importMatrices": "Importer des matrices", + "importFrameworks": "Importer des cadres", + "summary": "Synthèse", + "composer": "Compositeur", + "statistics": "Statistiques", + "myProjects": "Mes projets", + "scenarios": "Scénarios", + "assignedObjects": "Assigné à {number} {object}", + "currentRiskLevelPerScenario": "Niveau de risque courant par scénario de risque", + "residualRiskLevelPerScenario": "Niveau de risque résiduel par scénario de risque", + "securityMeasuresStatus": "Statut des mesures de sécurité", + "currentRisk": "Risque courant", + "residualRisk": "Risque résiduel", + "veryLow": "Très faible", + "low": "Faible", + "medium": "Moyen", + "high": "Élevé", + "veryHigh": "Très élevé", + "planned": "Planifié", + "active": "Active", + "inactive": "Inactive", + "watchlist": "Liste de surveillance", + "watchlistDescription": "Objets expirés ou ayant une ETA proche", + "measuresToReview": "Mesures à revoir", + "exceptionsToReview": "Exceptions à revoir", + "expired": "Expiré", + "upcoming": "À venir", + "today": "Aujourd'hui", + "actionRequested": "Action requise", + "noObjectYet": "Aucun{e} {object} pour le moment", + "authors": "Auteurs", + "reviewers": "Relecteurs", + "process": "Traiter", + "selectTargets": "Selectionnez vos cibles", + "composerDescription": "Cela vous aidera à agréger plusieurs composants (projets) pour obtenir une vue d'ensemble de vos risques. Ceci est particulièrement utile pour deux cas d'utilisation", + "composerDescription1": "une approche de veille stratégique pour se concentrer sur un sous-ensemble spécifique à travers différents domaines de projet (par exemple, à travers les divisions)", + "composerDescription2": "vous êtes intéressé par l'évaluation des risques d'un système spécifique, pour lequel vous avez besoin de l'évaluation des risques des composants sous-jacents", + "overallCompliance": "Conformité globale", + "exportButton": "Exporter", + "treatmentProgressOverview": "Vue d'ensemble de l'avancement du traitement", + "pendingMeasures": "Vos mesures en attente", + "orderdByRankingScore": "Classées par score", + "rankingScore": "Score de classement", + "noPendingObject": "Aucun{e} {objet} en attente", + "rankingScoreDefintion": "Le score de classement est une mesure adaptative qui combine les informations relatives à l'effort et au niveau de risque actuel, et les croise avec d'autres données pour vous aider à établir des priorités", + "actions": "Actions", + "projectsSummaryEmpty": "Le résumé des projets est vide", + "riskOpen": "Risque: ouvert", + "riskMitigate": "Risque: atténué", + "riskAccept": "Risque: accepté", + "riskAvoid": "Risque: évité", + "measureOpen": "Mesure: ouverte", + "measureProgress": "Mesure: en cours", + "measureHold": "Mesure: en attente", + "measureDone": "Mesure: terminée" } + diff --git a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte index c6bcd2690..6c72faf1d 100644 --- a/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte +++ b/frontend/src/lib/components/Breadcrumbs/Breadcrumbs.svelte @@ -1,11 +1,24 @@ @@ -41,7 +54,11 @@ {#if c.icon} {/if} - {c.label} + {#if localItems(languageTag())[c.label]} + {localItems(languageTag())[c.label]} + {:else} + {c.label} + {/if} {:else}
  • @@ -53,14 +70,22 @@ {#if c.icon} {/if} - {c.label} + {#if localItems(languageTag())[c.label]} + {localItems(languageTag())[c.label]} + {:else} + {c.label} + {/if} {:else} {#if c.icon} {/if} - {c.label} + {#if localItems(languageTag())[c.label]} + {localItems(languageTag())[c.label]} + {:else} + {c.label} + {/if} {/if}
  • diff --git a/frontend/src/lib/components/Chart/DonutChart.svelte b/frontend/src/lib/components/Chart/DonutChart.svelte index b479d867e..684edde32 100644 --- a/frontend/src/lib/components/Chart/DonutChart.svelte +++ b/frontend/src/lib/components/Chart/DonutChart.svelte @@ -1,11 +1,17 @@
    @@ -145,7 +181,7 @@ {#each Object.entries(source.head) as [key, heading]} - {heading} + {headTranslate[heading]} {/each} {#if displayActions} diff --git a/frontend/src/lib/components/ModelTable/Pagination.svelte b/frontend/src/lib/components/ModelTable/Pagination.svelte index 0f9272a7a..6151c070e 100644 --- a/frontend/src/lib/components/ModelTable/Pagination.svelte +++ b/frontend/src/lib/components/ModelTable/Pagination.svelte @@ -1,5 +1,6 @@ diff --git a/frontend/src/lib/components/ModelTable/RowsPerPage.svelte b/frontend/src/lib/components/ModelTable/RowsPerPage.svelte index 060388b05..8378067ef 100644 --- a/frontend/src/lib/components/ModelTable/RowsPerPage.svelte +++ b/frontend/src/lib/components/ModelTable/RowsPerPage.svelte @@ -1,12 +1,13 @@ diff --git a/frontend/src/lib/components/ModelTable/Search.svelte b/frontend/src/lib/components/ModelTable/Search.svelte index 9744f686a..98caf7ee0 100644 --- a/frontend/src/lib/components/ModelTable/Search.svelte +++ b/frontend/src/lib/components/ModelTable/Search.svelte @@ -1,13 +1,14 @@ handler.search(value)} /> diff --git a/frontend/src/lib/components/SideBar/SideBarCategory.svelte b/frontend/src/lib/components/SideBar/SideBarCategory.svelte index 24c5a2ceb..f0db86274 100644 --- a/frontend/src/lib/components/SideBar/SideBarCategory.svelte +++ b/frontend/src/lib/components/SideBar/SideBarCategory.svelte @@ -1,7 +1,9 @@ -{item.name} + + {localItems(languageTag())[item.name]} + diff --git a/frontend/src/lib/components/SideBar/SideBarFooter.svelte b/frontend/src/lib/components/SideBar/SideBarFooter.svelte index c65d48b56..3f32995d0 100644 --- a/frontend/src/lib/components/SideBar/SideBarFooter.svelte +++ b/frontend/src/lib/components/SideBar/SideBarFooter.svelte @@ -7,6 +7,11 @@ import { LOCALE_MAP } from '$lib/utils/locales'; import * as m from '$paraglide/messages'; + const language: any = { + french: m.french(), + english: m.english() + } + const modalStore = getModalStore(); let value = languageTag(); @@ -63,7 +68,7 @@ My profile{m.myProfile()} @@ -80,13 +85,13 @@ on:click={modalBuildInfo} class="cursor-pointer flex items-center gap-2 w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100 disabled:text-gray-500 text-gray-800" data-testid="about-button" - >About CISO Assistant{m.aboutCiso()}
    diff --git a/frontend/src/lib/components/SideBar/SideBarItem.svelte b/frontend/src/lib/components/SideBar/SideBarItem.svelte index 760167962..fb3bfd3d5 100644 --- a/frontend/src/lib/components/SideBar/SideBarItem.svelte +++ b/frontend/src/lib/components/SideBar/SideBarItem.svelte @@ -1,6 +1,7 @@ @@ -22,7 +50,13 @@ - {$pageTitle} + + {#if items[$pageTitle]} + {items[$pageTitle]} + {:else} + {$pageTitle} + {/if} +
    diff --git a/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte b/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte index d84b8db92..de77be9c7 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte +++ b/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte @@ -11,6 +11,9 @@ import { getModalStore, getToastStore } from '@skeletonlabs/skeleton'; import { superForm } from 'sveltekit-superforms/client'; import type { PageData } from './$types'; + import * as m from '$paraglide/messages'; + import { localItems, getDeterminant } from '$lib/utils/locales'; + import { languageTag } from '$paraglide/runtime'; export let data: PageData; @@ -91,15 +94,17 @@ class="btn variant-filled-primary self-end" data-testid="add-button" on:click={modalCreateForm} - >New {data.model.verboseName.toLowerCase()} + {m.addButton({determinant:getDeterminant(languageTag(), "undefined", data.model), model: localItems(languageTag())[data.model.localName].toLowerCase()})} + {:else if data.URLModel === 'risk-matrices'} Import matrices{m.importMatrices()} {:else if data.URLModel === 'frameworks'} Import framework{m.importFrameworks()} {/if}
    diff --git a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/+page.svelte index 332c08cb3..da964e510 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/+page.svelte +++ b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/+page.svelte @@ -15,6 +15,9 @@ import { getModelInfo } from '$lib/utils/crud.js'; import { URL_MODEL_MAP } from '$lib/utils/crud'; import { isURL } from '$lib/utils/helpers'; + import { localItems, toCamelCase, getDeterminant } from '$lib/utils/locales.js'; + import { languageTag } from '$paraglide/runtime.js'; + import * as m from '$paraglide/messages.js'; const modalStore: ModalStore = getModalStore(); const toastStore: ToastStore = getToastStore(); @@ -172,30 +175,33 @@
    {#each Object.entries(data.data).filter(([key, _]) => !['id', 'is_published'].includes(key)) as [key, value]}
    -
    - {key.replace('_', ' ')} +
    + {localItems(languageTag())[toCamelCase(key.toLowerCase())]}
    • {#if value} {#if Array.isArray(value)} -
        - {#each value as val} -
      • - {#if val.str && val.id} - {@const itemHref = `/${ - URL_MODEL_MAP[data.urlModel]['foreignKeyFields']?.find( - (item) => item.field === key - )?.urlModel - }/${val.id}`} - {val.str} - {:else} - {value} - {/if} -
      • - {/each} -
      + {#if Object.keys(value).length > 0} +
        + {#each value as val} +
      • + {#if val.str && val.id} + {@const itemHref = `/${ + URL_MODEL_MAP[data.urlModel]['foreignKeyFields']?.find( + (item) => item.field === key + )?.urlModel + }/${val.id}`} + {val.str} + {:else} + {value} + {/if} +
      • + {/each} +
      + {:else} + -- + {/if} {:else if value.id} {@const itemHref = `/${ URL_MODEL_MAP[data.urlModel]['foreignKeyFields']?.find( @@ -220,8 +226,7 @@ Edit{m.edit()} {/if}
    @@ -232,7 +237,7 @@ {#each Object.entries(data.relatedModels) as [urlmodel, model], index} - {model.info.verboseNamePlural} + {localItems(languageTag())[model.info.localNamePlural]} {#if model.table.body.length > 0} {model.table.body.length} {/if} @@ -243,12 +248,16 @@ {#if tabSet === index}

    - Associated {model.info.verboseNamePlural} + {#if model.info.localFrGender === 'f'} + {m.associatedObject({model: localItems(languageTag())[model.info.localNamePlural].toLowerCase(), e: 'e'})} + {:else} + {m.associatedObject({model: localItems(languageTag())[model.info.localNamePlural].toLowerCase(), e: ''})} + {/if}

    {m.addButton({determinant:getDeterminant(languageTag(), "undefined", model.info), model: localItems(languageTag())[model.info.localName].toLowerCase()})}
    {#if model.table} diff --git a/frontend/src/routes/(app)/analytics/+page.svelte b/frontend/src/routes/(app)/analytics/+page.svelte index f8881cf56..827f2747e 100644 --- a/frontend/src/routes/(app)/analytics/+page.svelte +++ b/frontend/src/routes/(app)/analytics/+page.svelte @@ -11,6 +11,10 @@ import { RISK_COLOR_PALETTE } from '$lib/utils/constants'; + import * as m from '$paraglide/messages'; + import { localItems } from '$lib/utils/locales.js'; + import { languageTag } from '$paraglide/runtime'; + export let data; let user: User = data.user; @@ -29,11 +33,15 @@ let openTab = 1; - const cur_rsk_label = 'Current risk'; - const rsd_rsk_label = 'Residual risk'; + const cur_rsk_label = m.currentRisk(); + const rsd_rsk_label = m.residualRisk(); let dropdown_selected_values: any; + for (const item in security_measure_status.labels) { + security_measure_status.labels[item] = localItems(languageTag())[security_measure_status.localLables[item]]; + } + onMount(async () => { const echarts = await import('echarts'); let echart_element = document.getElementById('security_measures_status_div'); @@ -179,6 +187,10 @@ let dropdown = new Dropdown(); + + {m.analytics()} + + { if (openTab === 3 && dropdown.show) { @@ -199,7 +211,7 @@ -
    Summary
    +
    {m.summary()}
    - Statistics + {m.statistics()}
    {counters.RiskAssessment}
    -
    Risk assessments
    +
    {m.riskAssessments()}
    {counters.RiskScenario}
    -
    Scenarios
    +
    {m.scenarios()}
    {counters.SecurityMeasure}
    -
    Security measures
    +
    {m.securityMeasures()}
    {counters.RiskAcceptance}
    -
    Risk acceptances
    +
    {m.riskAcceptances()}
    @@ -278,14 +290,18 @@
    -
    My projects
    +
    {m.myProjects()}
    - Assigned to {counters.Project} projects + {#if counters.Project > 1} + {m.assignedObjects({number: counters.Project, object: m.projects()})} + {:else} + {m.assignedObjects({number: counters.Project, object: m.project()})} + {/if}
    - Current risk level per risk scenario + {m.currentRiskLevelPerScenario()}
    - Residual risk level per risk scenario + {m.residualRiskLevelPerScenario()}
    - Security measures status + {m.securityMeasuresStatus()} @@ -316,19 +332,19 @@
    -
    Watch list
    +
    {m.watchlist()}
    - Items that have expired or with close ETA + {m.watchlistDescription()}
    - Measures to review + {m.measuresToReview()}
    - Exceptions to review + {m.exceptionsToReview()}
    @@ -338,23 +354,20 @@
    -
    Composer
    +
    {m.composer()}
    - This will help you aggregate multiple components (projects) to get the compiled view on - your risk. This is particularly useful for two use cases: + {m.composerDescription()}:
    • - business intelligence approach to focus on a specific subset across different project - domains (eg. across divisions) + {m.composerDescription1()}
    • - you are interested in the risk assessment of a specific system, for which you need the - risk assessment of the underlying components + {m.composerDescription2()}
    @@ -372,7 +385,7 @@ {m.process()}
    @@ -491,24 +504,24 @@ c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271, {#if agg_data.names.length}
    -
    Treatment progress overview
    +
    {m.treatmentProgressOverview()}
    -
    Your pending measures:
    -
    ordered by ranking score
    +
    {m.pendingMeasures()}
    +
    {m.orderdByRankingScore()}
    - - - - - - + + + + + + {#if measures} @@ -542,21 +555,19 @@ c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271, {/if}
    DomainMeasureRanking scoreStatusETAActions{m.domain()}{m.securityMeasure()}{m.rankingScore()}{m.status()}{m.eta()}{m.actions()}
    -

    No pending measure.

    +

    {m.noPendingObject({object:m.securityMeasure().toLowerCase(), e:'e'})}.

    - Ranking score is an adaptive metric that combines the - information of effort and current risk level, and crosses it with the other data to assist - you for the prioritization. + {m.rankingScoreDefintion()}.
    {:else}
    -
    Projects summary is empty.
    +
    {m.projectsSummaryEmpty()}.
    {/if}
    @@ -567,7 +578,7 @@ c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271, {#if openTab === 2}
    - Overall compliance + {m.overallCompliance()}
    {#each data.projects as project}
    @@ -591,18 +602,18 @@ c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271,
    -

    Name

    +

    {m.name()}

    {compliance_assessment.name}

    -

    Framework

    +

    {m.framework()}

    {compliance_assessment.framework.str}

    @@ -610,12 +621,12 @@ c0.27-0.268,0.707-0.268,0.979,0l7.908,7.83c0.27,0.268,0.27,0.701,0,0.969c-0.271, Export + > {m.exportButton()} Edit + > {m.edit()}