Files
nis2-agile/public/js/i18n.js
T
DevEnv nis2-agileandClaude Opus 4.8 4e7e75582a [FEAT] Rischi #500 fase 2 (frontend): elenco rischi = requisiti Lex&ISO
La pagina Gestione Rischi mostra come tabella primaria (read-only) i requisiti
del framework Lex&ISO come rischi, codice RSK-<misura>Com.N via /api/risks/derived,
filtrati per classe (importante All.1 / essenziale All.2). Framing normativo
(validato nis2-expert): ogni voce = "rischio derivante dal mancato/parziale
soddisfacimento del requisito", mai "requisito = rischio"; RSK e "92" NON come
codici/numeri ufficiali ACN; matrice = strumento di rappresentazione (art.24).
- Rischi CUSTOM mantenuti in sezione "Rischi aggiuntivi (all-hazard)".
- Tasti "Nuovo Rischio"/"AI Suggerisci" limitati a super_admin/org_admin (non
  rimossi): l'inserimento libero serve al multirischio (art.24 D.Lgs.138/2024).
- api.js derivedRisks(); help.js + i18n aggiornati; version 1.25.4; SW v1.25.4.
- Cache-buster api/help/i18n ?v=20260727r. Backend/DB non toccati.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 14:15:03 +02:00

617 lines
49 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* NIS2 Agile - i18n (Internationalization)
*
* Sistema di traduzione leggero IT/EN.
* - Lingua di default: 'it'
* - Salva preferenza in localStorage
* - Applica traduzioni via attributo data-i18n
* - Funzione t('chiave') per traduzione programmatica
*/
const I18n = (function () {
'use strict';
let _lang = 'it';
// ── Dizionario traduzioni ─────────────────────────────────────────
const _dict = {
// ── Navigazione / Sidebar ──────────────────────
'nav.main': { it: 'Principale', en: 'Main' },
'nav.dashboard': { it: 'Dashboard', en: 'Dashboard' },
'nav.gap_analysis': { it: 'Gap Analysis', en: 'Gap Analysis' },
'nav.framework': { it: 'Misure e Requisiti', en: 'Measures & Requirements' },
// ── Modello Organizzativo SGSI (ISO 27001) ──
'nav.isms': { it: 'Modello SGSI (ISO 27001)', en: 'ISMS Model (ISO 27001)' },
'isms.title': { it: 'Modello Organizzativo SGSI (ISO 27001)', en: 'ISMS Organizational Model (ISO 27001)' },
'isms.export': { it: 'Esporta SGSI', en: 'Export ISMS' },
'isms.intro.title': { it: 'Costruisci il tuo Sistema di Gestione della Sicurezza delle Informazioni.', en: 'Build your Information Security Management System.' },
'isms.intro.body': { it: 'Procedura guidata ISO/IEC 27001:2022 (clausole 4-10 + Statement of Applicability). Lo Statement of Applicability viene pre-popolato dalle tue risposte alla Gap Analysis NIS2. Attiva le estensioni cloud ISO 27017/27018 dove pertinenti.', en: 'Guided ISO/IEC 27001:2022 procedure (clauses 4-10 + Statement of Applicability). The Statement of Applicability is pre-populated from your NIS2 Gap Analysis answers. Enable the ISO 27017/27018 cloud extensions where relevant.' },
'isms.disclaimer': { it: 'Strumento di supporto e pre-audit: non costituisce una certificazione ISO 27001 né un parere professionale vincolante. Gli obblighi normativi in Italia derivano da NIS2 / D.Lgs. 138/2024 / Determinazioni ACN; ISO 27001/27017/27018 sono best practice.', en: 'Support and pre-audit tool: it is not an ISO 27001 certification nor binding professional advice. Regulatory obligations in Italy stem from NIS2 / Legislative Decree 138/2024 / ACN Determinations; ISO 27001/27017/27018 are best practices.' },
'isms.step1': { it: 'Contesto', en: 'Context' },
'isms.step2': { it: 'Leadership', en: 'Leadership' },
'isms.step3': { it: 'Risk', en: 'Risk' },
'isms.step4': { it: 'SoA', en: 'SoA' },
'isms.step5': { it: 'Documenti', en: 'Documents' },
'isms.step6': { it: 'Monitoraggio', en: 'Monitoring' },
'isms.save_next': { it: 'Salva e continua', en: 'Save and continue' },
'isms.next': { it: 'Continua', en: 'Continue' },
'isms.s1.title': { it: '1. Contesto e Ambito (cl. 4)', en: '1. Context and Scope (cl. 4)' },
'isms.s1.scope': { it: 'Ambito del SGSI (scope statement)', en: 'ISMS scope statement' },
'isms.s1.ctx_int': { it: 'Contesto interno', en: 'Internal context' },
'isms.s1.ctx_ext': { it: 'Contesto esterno', en: 'External context' },
'isms.s1.parties': { it: 'Parti interessate (una per riga)', en: 'Interested parties (one per line)' },
'isms.s1.boundaries': { it: 'Confini del SGSI', en: 'ISMS boundaries' },
'isms.s1.exclusions': { it: 'Esclusioni motivate', en: 'Justified exclusions' },
'isms.s1.cloud': { it: 'Estensioni cloud (attivano i controlli condizionali nel SoA)', en: 'Cloud extensions (enable conditional controls in the SoA)' },
'isms.s1.uses_cloud': { it: 'Usiamo servizi cloud pubblici (Microsoft 365, AWS, Google...) → ISO 27017', en: 'We use public cloud services (Microsoft 365, AWS, Google...) → ISO 27017' },
'isms.s1.cloud_provider': { it: 'Siamo fornitori di servizi cloud → ISO 27017 (lato provider)', en: 'We are cloud service providers → ISO 27017 (provider side)' },
'isms.s1.pii_cloud': { it: 'Trattiamo dati personali (PII) in cloud pubblico come responsabili → ISO 27018', en: 'We process personal data (PII) in public cloud as processors → ISO 27018' },
'isms.s2.title': { it: '2. Leadership: ruoli e responsabilità (cl. 5)', en: '2. Leadership: roles and responsibilities (cl. 5)' },
'isms.s2.hint': { it: 'Definisci i ruoli del SGSI con la matrice RACI (Responsible, Accountable, Consulted, Informed).', en: 'Define the ISMS roles with the RACI matrix (Responsible, Accountable, Consulted, Informed).' },
'isms.s2.add': { it: 'Aggiungi ruolo', en: 'Add role' },
'isms.s3.title': { it: '3. Risk: metodologia e obiettivi (cl. 6)', en: '3. Risk: methodology and objectives (cl. 6)' },
'isms.s3.method': { it: 'Metodologia di risk assessment', en: 'Risk assessment methodology' },
'isms.s3.objectives': { it: 'Obiettivi del SGSI (uno per riga)', en: 'ISMS objectives (one per line)' },
'isms.s3.link': { it: 'Il registro dei rischi vive nel modulo Rischi: questo passo ne dichiara la metodologia.', en: 'The risk register lives in the Risks module: this step declares its methodology.' },
'isms.s4.title': { it: '4. Statement of Applicability', en: '4. Statement of Applicability' },
'isms.s4.hint': { it: 'I controlli sono pre-popolati dalle risposte NIS2 dove esiste corrispondenza (badge "da NIS2"). Conferma applicabilità, stato e motivazione per ciascuno.', en: 'Controls are pre-populated from NIS2 answers where a mapping exists ("from NIS2" badge). Confirm applicability, status and justification for each.' },
'isms.s4.derive': { it: 'Ri-deriva dal NIS2', en: 'Re-derive from NIS2' },
'isms.s5.title': { it: '5. Documented Information (cl. 7-8)', en: '5. Documented Information (cl. 7-8)' },
'isms.s5.aigen': { it: 'Genera bozza con AI', en: 'Generate draft with AI' },
'isms.s6.title': { it: '6. Monitoraggio e Miglioramento (cl. 9-10)', en: '6. Monitoring and Improvement (cl. 9-10)' },
'isms.s6.hint': { it: 'Gli audit interni e le non conformità si gestiscono nei moduli esistenti: Audit & Report e NCR/CAPA.', en: 'Internal audits and non-conformities are managed in the existing modules: Audit & Reports and NCR/CAPA.' },
'isms.s6.readiness': { it: 'Completamento del SGSI', en: 'ISMS completion' },
'nav.management': { it: 'Gestione', en: 'Management' },
'nav.org_chart': { it: 'Organigramma', en: 'Org Chart' },
'nav.competences': { it: 'Competenze', en: 'Skills' },
'nav.raci': { it: 'Matrice RACI', en: 'RACI Matrix' },
'org.title': { it: 'Organigramma', en: 'Org Chart' },
'org.subtitle': { it: 'Ruoli, responsabilità e organi di governance', en: 'Roles, responsibilities and governance bodies' },
'org.new_role': { it: 'Nuovo ruolo', en: 'New role' },
'comp.title': { it: 'Competenze', en: 'Skills' },
'raci.title': { it: 'Matrice RACI', en: 'RACI Matrix' },
'nav.review_schedule': { it: 'Scadenziario', en: 'Review schedule' },
'nav.stakeholders': { it: 'Stakeholder', en: 'Stakeholders' },
'nav.stk_activities': { it: 'Attività stakeholder', en: 'Stakeholder activities' },
'rev.title': { it: 'Scadenziario', en: 'Review Schedule' },
'stk.title': { it: 'Stakeholder', en: 'Stakeholders' },
'sact.title': { it: 'Attività stakeholder', en: 'Stakeholder activities' },
'nav.calendar': { it: 'Calendario', en: 'Calendar' },
'cal.title': { it: 'Calendario scadenze', en: 'Deadlines calendar' },
'nav.internal_audits': { it: 'Audit interni', en: 'Internal audits' },
'iaud.title': { it: 'Audit interni', en: 'Internal audits' },
'nav.management_review': { it: 'Riesame di Direzione', en: 'Management Review' },
'mreview.title': { it: 'Riesame di Direzione', en: 'Management Review' },
'nav.periodic_controls': { it: 'Controlli periodici', en: 'Periodic controls' },
'pctl.title': { it: 'Controlli periodici', en: 'Periodic controls' },
'nav.risks': { it: 'Rischi', en: 'Risks' },
'nav.incidents': { it: 'Incidenti', en: 'Incidents' },
'nav.policies': { it: 'Policy', en: 'Policies' },
'nav.supply_chain': { it: 'Supply Chain', en: 'Supply Chain' },
'nav.operations': { it: 'Operativo', en: 'Operations' },
'nav.training': { it: 'Formazione', en: 'Training' },
'nav.assets': { it: 'Inventario', en: 'Inventory' },
'nav.audit': { it: 'Audit & Report', en: 'Audit & Reports' },
'nav.system': { it: 'Sistema', en: 'System' },
'nav.settings': { it: 'Impostazioni', en: 'Settings' },
'nav.help': { it: 'Guida', en: 'Help' },
'nav.logout': { it: 'Esci', en: 'Logout' },
// ── Voci nav UI V3 (top-nav mega-menu) ──
'nav.register_incident': { it: 'Registra incidente', en: 'Report incident' },
'nav.connectors': { it: 'Connettori Discovery', en: 'Discovery Connectors' },
'nav.whistleblowing': { it: 'Segnalazioni ricevute', en: 'Reports received' },
'nav.normative': { it: 'Normative', en: 'Regulations' },
'nav.cross_analysis': { it: 'AI Cross-Analysis', en: 'AI Cross-Analysis' },
'nav.kb': { it: 'Knowledge Base', en: 'Knowledge Base' },
'nav.architecture': { it: 'Architettura', en: 'Architecture' },
'nav.simulate': { it: 'Simulazione Demo', en: 'Demo Simulation' },
'nav.integrations': { it: 'Integrazioni Esterne', en: 'External Integrations' },
'nav.workflow': { it: 'Compliance Journey', en: 'Compliance Journey' },
'nav.audit_acn': { it: 'Audit ACN', en: 'ACN Audit' },
// ── Etichette gruppi mega-menu V3 ──
'nav.grp_stakeholders': { it: 'Stakeholders', en: 'Stakeholders' },
'nav.grp_internal': { it: 'Struttura interna', en: 'Internal structure' },
'nav.grp_risks': { it: 'Rischi', en: 'Risks' },
'nav.grp_monitoring': { it: 'Monitoraggio', en: 'Monitoring' },
'nav.grp_lexiso': { it: 'Lex e ISO', en: 'Law & ISO' },
'nav.grp_ai': { it: 'AI', en: 'AI' },
'nav.grp_guide': { it: 'Guida', en: 'Guide' },
// ── Titoli pagina aggiunti dalla flotta V3 (mancavano → si vedeva la chiave) ──
'mr.title': { it: 'Misure e Requisiti', en: 'Measures & Requirements' },
'normative.title': { it: 'Aggiornamenti Normativi', en: 'Regulatory Updates' },
// ── Dashboard ──────────────────────────────────
'dashboard.title': { it: 'Dashboard', en: 'Dashboard' },
'dashboard.compliance_score': { it: 'Punteggio Compliance', en: 'Compliance Score' },
'dashboard.open_risks': { it: 'Rischi Aperti', en: 'Open Risks' },
'dashboard.active_incidents': { it: 'Incidenti Attivi', en: 'Active Incidents' },
'dashboard.overdue_tasks': { it: 'Scadenze Superate', en: 'Overdue Tasks' },
'dashboard.recent_activity': { it: 'Attivita\' Recente', en: 'Recent Activity' },
'dashboard.upcoming_deadlines': { it: 'Prossime Scadenze', en: 'Upcoming Deadlines' },
'dashboard.risk_heatmap': { it: 'Mappa Rischi', en: 'Risk Heatmap' },
'dashboard.quick_actions': { it: 'Azioni Rapide', en: 'Quick Actions' },
// ── Assessment ─────────────────────────────────
'assessment.title': { it: 'Gap Analysis NIS2', en: 'NIS2 Gap Analysis' },
'assessment.new': { it: 'Nuovo Assessment', en: 'New Assessment' },
'assessment.start': { it: 'Inizia Assessment', en: 'Start Assessment' },
'assessment.complete': { it: 'Completa', en: 'Complete' },
'assessment.results': { it: 'Risultati Assessment', en: 'Assessment Results' },
'assessment.ai_analysis': { it: 'Analisi AI', en: 'AI Analysis' },
'assessment.generate_ncr': { it: 'Genera Non Conformita\' dai Gap', en: 'Generate NCRs from Gaps' },
'assessment.categories': { it: 'Categorie', en: 'Categories' },
'assessment.progress': { it: 'Avanzamento', en: 'Progress' },
'assessment.not_implemented': { it: 'Non Implementato', en: 'Not Implemented' },
'assessment.partial': { it: 'Parzialmente Implementato', en: 'Partially Implemented' },
'assessment.implemented': { it: 'Implementato', en: 'Implemented' },
'assessment.not_applicable': { it: 'Non Applicabile', en: 'Not Applicable' },
// ── Rischi ─────────────────────────────────────
'risks.title': { it: 'Gestione Rischi', en: 'Risk Management' },
'risks.fair_tab': { it: 'Quantitativo (FAIR)', en: 'Quantitative (FAIR)' },
'risks.kri_tab': { it: 'KRI', en: 'KRI' },
'risks.new': { it: 'Nuovo Rischio', en: 'New Risk' },
'risks.matrix': { it: 'Matrice Rischi', en: 'Risk Matrix' },
'risks.likelihood': { it: 'Probabilita\'', en: 'Likelihood' },
'risks.impact': { it: 'Impatto', en: 'Impact' },
'risks.treatment': { it: 'Trattamento', en: 'Treatment' },
'risks.mitigate': { it: 'Mitigare', en: 'Mitigate' },
'risks.accept': { it: 'Accettare', en: 'Accept' },
'risks.transfer': { it: 'Trasferire', en: 'Transfer' },
'risks.avoid': { it: 'Evitare', en: 'Avoid' },
'risks.derived_heading': { it: 'Rischi dai requisiti del framework di sicurezza', en: 'Risks from security framework requirements' },
'risks.derived_code_legend': { it: 'RSK-‹misura›Com.‹n› è una codifica interna di NIS2 Agile; ‹misura› (es. GV.OC-04) è il codice della misura del Framework Nazionale richiamato dalla Determinazione ACN 164179/2025. Elenco in sola lettura.', en: 'RSK-‹measure›Com.‹n› is an internal NIS2 Agile code; ‹measure› (e.g. GV.OC-04) is the National Framework measure code referenced by ACN Determination 164179/2025. Read-only list.' },
'risks.col_code': { it: 'Codice', en: 'Code' },
'risks.col_risk': { it: 'Rischio', en: 'Risk' },
'risks.col_measure': { it: 'Misura', en: 'Measure' },
'risks.col_conformity': { it: 'Conformità', en: 'Conformity' },
'risks.col_evaluation': { it: 'Valutazione', en: 'Evaluation' },
'risks.custom_heading': { it: 'Rischi aggiuntivi (approccio multirischio / all-hazard)', en: 'Additional risks (multi-risk / all-hazard approach)' },
'risks.custom_help': { it: 'Oltre ai rischi derivati dai requisiti, i profili amministrativi possono aggiungere rischi non coperti da un singolo requisito (es. minacce fisiche, catena di fornitura, eventi naturali): copre l\'approccio multirischio/all-hazard (art. 24 D.Lgs. 138/2024).', en: 'Beyond the requirement-derived risks, administrative profiles can add risks not covered by a single requirement (e.g. physical threats, supply chain, natural events): this covers the multi-risk/all-hazard approach (art. 24 Legislative Decree 138/2024).' },
'risks.matrix_caption': { it: 'La matrice 5×5 è uno strumento di rappresentazione, non un obbligo normativo (art. 24 D.Lgs. 138/2024).', en: 'The 5×5 matrix is a representation tool, not a regulatory obligation (art. 24 Legislative Decree 138/2024).' },
// ── Incidenti ──────────────────────────────────
'incidents.title': { it: 'Gestione Incidenti', en: 'Incident Management' },
'incidents.new': { it: 'Nuovo Incidente', en: 'New Incident' },
'incidents.early_warning': { it: 'Early Warning (24h)', en: 'Early Warning (24h)' },
'incidents.notification': { it: 'Notifica (72h)', en: 'Notification (72h)' },
'incidents.final_report': { it: 'Report Finale (1 mese)', en: 'Final Report (1 month)' },
'incidents.timeline': { it: 'Cronologia', en: 'Timeline' },
'incidents.severity': { it: 'Gravita\'', en: 'Severity' },
'incidents.low': { it: 'Bassa', en: 'Low' },
'incidents.medium': { it: 'Media', en: 'Medium' },
'incidents.high': { it: 'Alta', en: 'High' },
'incidents.critical': { it: 'Critica', en: 'Critical' },
// ── Policy ─────────────────────────────────────
'policies.title': { it: 'Gestione Policy', en: 'Policy Management' },
'policies.new': { it: 'Nuova Policy', en: 'New Policy' },
'policies.ai_generate': { it: 'Genera con AI', en: 'Generate with AI' },
'policies.approve': { it: 'Approva', en: 'Approve' },
'policies.draft': { it: 'Bozza', en: 'Draft' },
'policies.review': { it: 'In Revisione', en: 'Under Review' },
'policies.approved': { it: 'Approvata', en: 'Approved' },
'policies.published': { it: 'Pubblicata', en: 'Published' },
// ── Supply Chain ───────────────────────────────
'supply_chain.title': { it: 'Sicurezza Supply Chain', en: 'Supply Chain Security' },
'supply_chain.new_supplier': { it: 'Nuovo Fornitore', en: 'New Supplier' },
'supply_chain.risk_overview': { it: 'Panoramica Rischi', en: 'Risk Overview' },
'supply_chain.assess': { it: 'Valuta Fornitore', en: 'Assess Supplier' },
// ── Formazione ─────────────────────────────────
'training.title': { it: 'Formazione e Awareness', en: 'Training & Awareness' },
'training.courses': { it: 'Corsi', en: 'Courses' },
'training.my_assignments': { it: 'I Miei Corsi', en: 'My Assignments' },
'training.assign': { it: 'Assegna Corso', en: 'Assign Course' },
'training.completed': { it: 'Completato', en: 'Completed' },
'training.overdue': { it: 'Scaduto', en: 'Overdue' },
// ── Asset ──────────────────────────────────────
'assets.title': { it: 'Inventario', en: 'Inventory' },
'assets.import_btn': { it: 'Importa', en: 'Import' },
'assets.new': { it: 'Nuovo Asset', en: 'New Asset' },
'assets.dependency_map': { it: 'Mappa Dipendenze', en: 'Dependency Map' },
'assets.hardware': { it: 'Hardware', en: 'Hardware' },
'assets.software': { it: 'Software', en: 'Software' },
'assets.network': { it: 'Rete', en: 'Network' },
'assets.data': { it: 'Dati', en: 'Data' },
// ── Audit ──────────────────────────────────────
'audit.title': { it: 'Audit & Report', en: 'Audit & Reports' },
'audit.monitoring_tab': { it: 'Monitoraggio Continuo', en: 'Continuous Monitoring' },
'audit.controls': { it: 'Controlli di Compliance', en: 'Compliance Controls' },
'audit.evidence': { it: 'Evidenze', en: 'Evidence' },
'audit.logs': { it: 'Log di Audit', en: 'Audit Logs' },
'audit.export': { it: 'Esporta Report', en: 'Export Report' },
// ── Impostazioni ───────────────────────────────
'settings.title': { it: 'Impostazioni', en: 'Settings' },
'settings.organization': { it: 'Organizzazione', en: 'Organization' },
'settings.profile': { it: 'Profilo Utente', en: 'User Profile' },
'settings.members': { it: 'Membri Team', en: 'Team Members' },
'settings.security': { it: 'Sicurezza', en: 'Security' },
// ── Classificazione NIS2 ───────────────────────
'classification.essential': { it: 'Soggetto Essenziale', en: 'Essential Entity' },
'classification.important': { it: 'Soggetto Importante', en: 'Important Entity' },
'classification.not_applicable': { it: 'Non Applicabile', en: 'Not Applicable' },
'classification.voluntary': { it: 'Adesione Volontaria', en: 'Voluntary Compliance' },
// ── Azioni comuni ──────────────────────────────
'action.save': { it: 'Salva', en: 'Save' },
'action.cancel': { it: 'Annulla', en: 'Cancel' },
'action.delete': { it: 'Elimina', en: 'Delete' },
'action.edit': { it: 'Modifica', en: 'Edit' },
'action.create': { it: 'Crea', en: 'Create' },
'action.close': { it: 'Chiudi', en: 'Close' },
'action.back': { it: 'Indietro', en: 'Back' },
'action.next': { it: 'Avanti', en: 'Next' },
'action.confirm': { it: 'Conferma', en: 'Confirm' },
'action.search': { it: 'Cerca', en: 'Search' },
'action.filter': { it: 'Filtra', en: 'Filter' },
'action.export': { it: 'Esporta', en: 'Export' },
'action.loading': { it: 'Caricamento...', en: 'Loading...' },
// ── Stato ──────────────────────────────────────
'status.draft': { it: 'Bozza', en: 'Draft' },
'status.in_progress': { it: 'In Corso', en: 'In Progress' },
'status.completed': { it: 'Completato', en: 'Completed' },
'status.open': { it: 'Aperto', en: 'Open' },
'status.closed': { it: 'Chiuso', en: 'Closed' },
'status.active': { it: 'Attivo', en: 'Active' },
'status.archived': { it: 'Archiviato', en: 'Archived' },
// ── Messaggi ───────────────────────────────────
'msg.save_success': { it: 'Salvato con successo!', en: 'Saved successfully!' },
'msg.delete_confirm': { it: 'Sei sicuro di voler eliminare?', en: 'Are you sure you want to delete?' },
'msg.error_generic': { it: 'Si e\' verificato un errore.', en: 'An error occurred.' },
'msg.error_connection': { it: 'Errore di connessione al server.', en: 'Server connection error.' },
'msg.no_data': { it: 'Nessun dato disponibile.', en: 'No data available.' },
// ── Sessione / Idle timeout ─────────────────────
'session.expiring_title': { it: 'Sessione in scadenza', en: 'Session expiring' },
'session.expiring_msg': { it: 'Per motivi di sicurezza, verrai disconnesso tra', en: 'For security reasons, you will be logged out in' },
'session.idle_reason': { it: 'a causa di inattivita\'.', en: 'due to inactivity.' },
'session.stay': { it: 'Rimani connesso', en: 'Stay connected' },
'session.logout_now': { it: 'Disconnetti', en: 'Log out' },
// ── Multi-device Sessions (Fase 2) ──────────────
'sessions.title': { it: 'Sessioni Attive', en: 'Active Sessions' },
'sessions.desc': { it: 'Dispositivi attualmente loggati al tuo account. Puoi disconnetterli singolarmente o tutti tranne questo.', en: 'Devices currently logged into your account. You can disconnect them individually or all but this one.' },
'sessions.current_device': { it: 'Questo dispositivo', en: 'This device' },
'sessions.revoke': { it: 'Disconnetti', en: 'Disconnect' },
'sessions.revoke_all': { it: 'Disconnetti gli altri', en: 'Disconnect others' },
'sessions.ip': { it: 'IP', en: 'IP' },
'sessions.last_activity': { it: 'Ultimo accesso', en: 'Last activity' },
'sessions.login': { it: 'Login', en: 'Login' },
'sessions.empty': { it: 'Nessuna sessione attiva.', en: 'No active sessions.' },
'sessions.confirm_revoke': { it: 'Disconnettere questo dispositivo?', en: 'Disconnect this device?' },
'sessions.confirm_revoke_all': { it: 'Disconnettere tutti gli altri dispositivi?', en: 'Disconnect all other devices?' },
// ── Password Reset (Fase 3) ─────────────────────
'pwreset.forgot_link': { it: 'Password dimenticata?', en: 'Forgot password?' },
'pwreset.forgot_title': { it: 'Reimposta la tua password', en: 'Reset your password' },
'pwreset.forgot_helper': { it: 'Inserisci l\'indirizzo email associato al tuo account. Ti invieremo un link valido 30 minuti.', en: 'Enter the email associated with your account. We will send you a link valid for 30 minutes.' },
'pwreset.send_link': { it: 'Invia link', en: 'Send link' },
'pwreset.set_new': { it: 'Imposta una nuova password', en: 'Set a new password' },
'pwreset.new_password': { it: 'Nuova password', en: 'New password' },
'pwreset.confirm': { it: 'Conferma password', en: 'Confirm password' },
'pwreset.submit': { it: 'Imposta password', en: 'Set password' },
'pwreset.back_login': { it: 'Torna al login', en: 'Back to login' },
'pwreset.strength_weak': { it: 'Debole', en: 'Weak' },
'pwreset.strength_medium': { it: 'Media', en: 'Medium' },
'pwreset.strength_good': { it: 'Buona', en: 'Good' },
'pwreset.strength_excellent':{ it: 'Ottima', en: 'Excellent' },
// ── Tenant switcher (Fase 3) ────────────────────
'tenant.select': { it: 'Seleziona azienda', en: 'Select company' },
'tenant.all': { it: '← Tutte le aziende', en: '← All companies' },
// ── Preferenze (Fase 4) ─────────────────────────
'preferences.title': { it: 'Preferenze utente', en: 'User preferences' },
'preferences.desc': { it: 'Personalizzazione interfaccia e notifiche.', en: 'Interface and notifications personalization.' },
'preferences.language': { it: 'Lingua', en: 'Language' },
'preferences.theme': { it: 'Tema', en: 'Theme' },
'preferences.theme_auto': { it: 'Auto (segue sistema)', en: 'Auto (follows system)' },
'preferences.theme_light': { it: 'Chiaro', en: 'Light' },
'preferences.theme_dark': { it: 'Scuro', en: 'Dark' },
'preferences.timezone': { it: 'Timezone', en: 'Timezone' },
'preferences.notif_email': { it: 'Ricevi notifiche via email (incidenti, deadline, training)', en: 'Receive email notifications (incidents, deadlines, training)' },
'preferences.notif_inapp': { it: 'Mostra notifiche in-app (badge sidebar)', en: 'Show in-app notifications (sidebar badges)' },
'preferences.save': { it: 'Salva preferenze', en: 'Save preferences' },
'preferences.saved': { it: '✓ Salvato', en: '✓ Saved' },
// ── Impersonate (Fase 4) ────────────────────────
'impersonate.btn': { it: 'Impersonate', en: 'Impersonate' },
'impersonate.tooltip': { it: 'Entra come questo utente per 1 ora', en: 'Enter as this user for 1 hour' },
'impersonate.confirm': { it: 'Entrare come {email} per 1 ora?', en: 'Enter as {email} for 1 hour?' },
'impersonate.banner': { it: 'Modalità Impersonate — stai usando l\'account di', en: 'Impersonate mode — you are using the account of' },
'impersonate.exit': { it: 'Esci impersonate', en: 'Exit impersonate' },
// ── Branding white-label (Fase 5) ───────────────
'branding.title': { it: 'Branding white-label', en: 'White-label branding' },
'branding.desc': { it: 'Personalizza colori, logo e nome prodotto per il tuo studio. Visibile a tutti i tuoi clienti loggati.', en: 'Customize colors, logo and product name for your firm. Visible to all your logged-in clients.' },
'branding.brand_name': { it: 'Nome prodotto custom (opzionale)', en: 'Custom product name (optional)' },
'branding.logo_url': { it: 'URL Logo (opzionale)', en: 'Logo URL (optional)' },
'branding.primary': { it: 'Colore primario', en: 'Primary color' },
'branding.secondary': { it: 'Colore secondario', en: 'Secondary color' },
'branding.save': { it: 'Salva branding', en: 'Save branding' },
'branding.saved': { it: '✓ Salvato — ricarica per vedere', en: '✓ Saved — reload to see' },
// ── Settings tabs (Fase 4-5) ────────────────────
'settings.preferences': { it: 'Preferenze', en: 'Preferences' },
'settings.branding': { it: 'Branding', en: 'Branding' },
// ── Tempo relativo ─────────────────────────────
'time.now': { it: 'Adesso', en: 'Just now' },
'time.min_ago': { it: 'min fa', en: 'min ago' },
'time.hours_ago': { it: 'ore fa', en: 'hours ago' },
'time.yesterday': { it: 'Ieri', en: 'Yesterday' },
'time.days_ago': { it: 'giorni fa', en: 'days ago' },
// ── Compliance Journey / Workflow ──────────────
'workflow.title': { it: 'Compliance Journey', en: 'Compliance Journey' },
'workflow.progress': { it: 'Progresso Art.21 NIS2', en: 'NIS2 Art.21 Progress' },
'workflow.implementation': { it: 'implementazione misure', en: 'measures implementation' },
'workflow.next_action': { it: 'Prossima azione consigliata', en: 'Recommended next action' },
'workflow.phase': { it: 'Fase', en: 'Phase' },
'workflow.go_to_module': { it: 'Vai al modulo', en: 'Go to module' },
'workflow.ph1': { it: 'Preparazione', en: 'Preparation' },
'workflow.ph2': { it: 'Valutazione', en: 'Assessment' },
'workflow.ph3': { it: 'Rischi', en: 'Risks' },
'workflow.ph4': { it: 'Implementazione', en: 'Implementation' },
'workflow.ph5': { it: 'Monitoraggio', en: 'Monitoring' },
'workflow.ph6': { it: 'Reportistica', en: 'Reporting' },
'workflow.status_done': { it: 'Completato', en: 'Completed' },
'workflow.status_partial': { it: 'In corso', en: 'In progress' },
'workflow.status_active': { it: 'Attivo', en: 'Active' },
'workflow.status_todo': { it: 'Da iniziare', en: 'To do' },
'nav.workflow': { it: 'Compliance Journey', en: 'Compliance Journey' },
};
// ── API Pubblica ──────────────────────────────────────────────────
/**
* Inizializza i18n: carica lingua da localStorage o parametro.
*/
function init(defaultLang) {
_lang = localStorage.getItem('nis2_lang') || defaultLang || 'it';
applyTranslations();
}
/**
* Ritorna la lingua corrente.
*/
function getLang() {
return _lang;
}
/**
* Cambia lingua e ri-applica traduzioni.
*/
function setLang(lang) {
if (lang !== 'it' && lang !== 'en') return;
_lang = lang;
localStorage.setItem('nis2_lang', lang);
applyTranslations();
}
/**
* Traduce una chiave.
* @param {string} key - Chiave di traduzione (es. 'nav.dashboard')
* @param {object} [params] - Parametri per interpolazione {name: 'valore'}
* @returns {string}
*/
function t(key, params) {
const entry = _dict[key];
if (!entry) return key;
let text = entry[_lang] || entry['it'] || key;
if (params) {
Object.keys(params).forEach(k => {
text = text.replace(new RegExp('\\{' + k + '\\}', 'g'), params[k]);
});
}
return text;
}
/**
* Applica traduzioni a tutti gli elementi con data-i18n.
* Attributo data-i18n="chiave" → traduce textContent
* Attributo data-i18n-placeholder="chiave" → traduce placeholder
* Attributo data-i18n-title="chiave" → traduce title
*/
function applyTranslations() {
document.querySelectorAll('[data-i18n]').forEach(el => {
const key = el.getAttribute('data-i18n');
el.textContent = t(key);
});
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
el.placeholder = t(el.getAttribute('data-i18n-placeholder'));
});
document.querySelectorAll('[data-i18n-title]').forEach(el => {
el.title = t(el.getAttribute('data-i18n-title'));
});
document.querySelectorAll('[data-i18n-html]').forEach(el => {
el.innerHTML = t(el.getAttribute('data-i18n-html'));
});
}
/**
* Registra nuove traduzioni (merge).
*/
function addTranslations(entries) {
Object.assign(_dict, entries);
}
// ── Feedback & Segnalazioni ─────────────────────────────────
addTranslations({
'feedback.fab_title': { it: 'Segnala un problema o un miglioramento', en: 'Report an issue or improvement' },
'feedback.tab_new': { it: 'Nuova segnalazione', en: 'New report' },
'feedback.tab_mine': { it: 'Le mie segnalazioni', en: 'My reports' },
'feedback.tipo_label': { it: 'Tipo', en: 'Type' },
'feedback.tipo_bug': { it: 'Bug / Errore', en: 'Bug / Error' },
'feedback.tipo_ux': { it: 'Miglioramento interfaccia', en: 'UX improvement' },
'feedback.tipo_funzionalita':{ it: 'Nuova funzionalità', en: 'New feature' },
'feedback.tipo_domanda': { it: 'Domanda / Supporto', en: 'Question / Support' },
'feedback.tipo_altro': { it: 'Altro', en: 'Other' },
'feedback.priorita_label': { it: 'Priorità percepita', en: 'Perceived priority' },
'feedback.priorita_alta': { it: 'Alta', en: 'High' },
'feedback.priorita_media': { it: 'Media', en: 'Medium' },
'feedback.priorita_bassa': { it: 'Bassa', en: 'Low' },
'feedback.desc_label': { it: 'Descrizione', en: 'Description' },
'feedback.desc_hint': { it: 'Sii specifico: cosa hai fatto, cosa ti aspettavi, cosa è successo', en: 'Be specific: what you did, what you expected, what happened' },
'feedback.attach_label': { it: 'Screenshot (opzionale)', en: 'Screenshot (optional)' },
'feedback.submit_btn': { it: 'Invia segnalazione', en: 'Submit report' },
'feedback.submitting': { it: 'Analisi AI in corso…', en: 'AI analysis in progress…' },
'feedback.ai_badge': { it: 'Analisi AI completata', en: 'AI analysis complete' },
'feedback.resolve_question': { it: 'Il problema è stato risolto grazie a questo suggerimento?', en: 'Was the problem resolved by this suggestion?' },
'feedback.resolve_yes': { it: 'Sì, problema risolto', en: 'Yes, problem resolved' },
'feedback.resolve_no': { it: 'No, il problema persiste', en: 'No, problem persists' },
'feedback.resolve_password': { it: 'Conferma con password di verifica', en: 'Confirm with verification password' },
'feedback.resolve_confirm': { it: 'Conferma', en: 'Confirm' },
'feedback.resolved_ok': { it: 'Segnalazione marcata come risolta. Grazie per il feedback.', en: 'Report marked as resolved. Thank you for your feedback.' },
'feedback.status_aperto': { it: 'Aperto', en: 'Open' },
'feedback.status_lavorazione': { it: 'In lavorazione', en: 'In progress' },
'feedback.status_risolto': { it: 'Risolto', en: 'Resolved' },
'feedback.status_chiuso': { it: 'Chiuso', en: 'Closed' },
'feedback.empty': { it: 'Nessuna segnalazione ancora. Usala per segnalare problemi!', en: 'No reports yet. Use it to report issues!' },
'feedback.error_short': { it: 'Descrizione troppo breve (minimo 10 caratteri).', en: 'Description too short (minimum 10 characters).' },
'feedback.error_password': { it: 'Password non corretta.', en: 'Incorrect password.' },
'feedback.notif_open': { it: 'Segnalazione registrata. Il team la prenderà in carico.', en: 'Report registered. The team will handle it.' },
});
// ── Supply Chain / Fornitori (modulo questionari Fase 1) ────────────
addTranslations({
'sp.import_btn': { it: 'Importa', en: 'Import' },
'sp.categories_btn': { it: 'Categorie', en: 'Categories' },
'sp.templates_btn': { it: 'Template', en: 'Templates' },
'sp.new_supplier': { it: '+ Nuovo Fornitore', en: '+ New Supplier' },
'sp.category_field': { it: 'Categoria fornitore', en: 'Supplier category' },
'sp.category_none': { it: '— Nessuna —', en: '— None —' },
'sp.category_hint': { it: 'Classifica il fornitore (es. Cloud Provider). Gestisci le categorie dal pulsante "Categorie".', en: 'Classify the supplier (e.g. Cloud Provider). Manage categories from the "Categories" button.' },
// Categorie
'sp.cat_title': { it: 'Categorie fornitore', en: 'Supplier categories' },
'sp.cat_new': { it: '+ Nuova categoria', en: '+ New category' },
'sp.cat_preset': { it: 'Preset', en: 'Preset' },
'sp.cat_custom': { it: 'Personalizzata', en: 'Custom' },
'sp.cat_not_editable': { it: 'non modificabile', en: 'not editable' },
'sp.cat_name': { it: 'Nome categoria', en: 'Category name' },
'sp.cat_desc': { it: 'Descrizione', en: 'Description' },
'sp.cat_preset_note': { it: 'Le categorie preset sono fornite dal sistema e non sono modificabili. Puoi creare categorie personalizzate per la tua organizzazione.', en: 'Preset categories are provided by the system and cannot be modified. You can create custom categories for your organization.' },
'sp.cat_name_required': { it: 'Il nome della categoria è obbligatorio.', en: 'Category name is required.' },
'sp.cat_created': { it: 'Categoria creata.', en: 'Category created.' },
'sp.cat_updated': { it: 'Categoria aggiornata.', en: 'Category updated.' },
'sp.cat_deleted': { it: 'Categoria eliminata.', en: 'Category deleted.' },
'sp.cat_delete_confirm': { it: 'Eliminare la categoria?', en: 'Delete this category?' },
'sp.cat_in_use': { it: 'Impossibile eliminare (categoria in uso?).', en: 'Cannot delete (category in use?).' },
// Template
'sp.tpl_title': { it: 'Template questionari', en: 'Questionnaire templates' },
'sp.tpl_empty': { it: 'Nessun template questionario per questa organizzazione.', en: 'No questionnaire template for this organization.' },
'sp.tpl_active': { it: 'Attivo', en: 'Active' },
'sp.tpl_default': { it: 'Default', en: 'Default' },
'sp.tpl_view_questions': { it: 'Vedi domande', en: 'View questions' },
'sp.tpl_back': { it: '← Torna ai template', en: '← Back to templates' },
'sp.tpl_readonly': { it: "Sola lettura. L'editor delle domande sarà disponibile in una prossima versione.", en: 'Read-only. The question editor will be available in a future version.' },
'sp.tpl_required': { it: 'Obbligatoria', en: 'Required' },
'sp.tpl_high_crit': { it: 'Solo alta criticità', en: 'High criticality only' },
'sp.tpl_weight': { it: 'Peso', en: 'Weight' },
'sp.tpl_questions': { it: 'domande', en: 'questions' },
// Import
'sp.import_title': { it: 'Importa fornitori', en: 'Import suppliers' },
'sp.import_run': { it: 'Importa', en: 'Import' },
'sp.import_no_rows': { it: 'Nessuna riga valida (serve intestazione + almeno un fornitore con "name").', en: 'No valid rows (header + at least one supplier with "name" required).' },
'sp.import_too_many': { it: 'Troppi record (max 1000).', en: 'Too many records (max 1000).' },
'sp.import_done': { it: 'Completato: creati {created}, aggiornati {updated}, saltati {skipped}.', en: 'Done: {created} created, {updated} updated, {skipped} skipped.' },
'sp.conn_error': { it: 'Errore di connessione.', en: 'Connection error.' },
// ── Supply Chain / Fornitori — i18n estesa pagina interna (2026-06-21) ──
'sp.stat_total': { it: 'Totale Fornitori', en: 'Total Suppliers' },
'sp.stat_critical': { it: 'Critici Non Conformi', en: 'Critical Non-Compliant' },
'sp.stat_expiring': { it: 'Contratti in Scadenza', en: 'Expiring Contracts' },
'sp.stat_avg_score': { it: 'Score Rischio Medio', en: 'Average Risk Score' },
'sp.crit_distribution': { it: 'Distribuzione Criticità', en: 'Criticality Distribution' },
'sp.crit_critical': { it: 'Critico', en: 'Critical' },
'sp.crit_high': { it: 'Alto', en: 'High' },
'sp.crit_medium': { it: 'Medio', en: 'Medium' },
'sp.crit_low': { it: 'Basso', en: 'Low' },
'sp.filter_all_crit': { it: 'Tutte le Criticità', en: 'All Criticalities' },
'sp.filter_all_status': { it: 'Tutti gli Stati', en: 'All Statuses' },
'sp.status_active': { it: 'Attivo', en: 'Active' },
'sp.status_under_review':{ it: 'In Revisione', en: 'Under Review' },
'sp.status_suspended': { it: 'Sospeso', en: 'Suspended' },
'sp.status_terminated': { it: 'Terminato', en: 'Terminated' },
'sp.loading_suppliers': { it: 'Caricamento fornitori...', en: 'Loading suppliers...' },
'sp.loading': { it: 'Caricamento...', en: 'Loading...' },
'sp.no_suppliers': { it: 'Nessun fornitore trovato', en: 'No suppliers found' },
'sp.no_suppliers_hint': { it: 'Aggiungi il tuo primo fornitore per iniziare il monitoraggio della supply chain.', en: 'Add your first supplier to start monitoring the supply chain.' },
'sp.col_name': { it: 'Nome', en: 'Name' },
'sp.col_service_type': { it: 'Tipo Servizio', en: 'Service Type' },
'sp.col_criticality': { it: 'Criticità', en: 'Criticality' },
'sp.col_risk_score': { it: 'Score Rischio', en: 'Risk Score' },
'sp.col_status': { it: 'Stato', en: 'Status' },
'sp.col_last_assessment':{ it: 'Ultima Valutazione', en: 'Last Assessment' },
'sp.col_actions': { it: 'Azioni', en: 'Actions' },
'sp.back_to_list': { it: "Torna all'elenco", en: 'Back to list' },
'sp.compliant': { it: 'Conforme', en: 'Compliant' },
'sp.non_compliant': { it: 'Non Conforme', en: 'Non-Compliant' },
'sp.assess_supplier': { it: 'Valuta Fornitore', en: 'Assess Supplier' },
'sp.send_questionnaire': { it: 'Invia questionario', en: 'Send questionnaire' },
'sp.edit': { it: 'Modifica', en: 'Edit' },
'sp.delete': { it: 'Elimina', en: 'Delete' },
'sp.info_title': { it: 'Informazioni Fornitore', en: 'Supplier Information' },
'sp.field_name': { it: 'Nome', en: 'Name' },
'sp.field_vat': { it: 'Partita IVA', en: 'VAT Number' },
'sp.field_contact_name': { it: 'Referente', en: 'Contact Person' },
'sp.field_email': { it: 'Email', en: 'Email' },
'sp.field_service_type': { it: 'Tipo Servizio', en: 'Service Type' },
'sp.field_contract_start':{ it: 'Inizio Contratto', en: 'Contract Start' },
'sp.field_contract_expiry':{ it: 'Scadenza Contratto', en: 'Contract Expiry' },
'sp.service_desc_title': { it: 'Descrizione Servizio', en: 'Service Description' },
'sp.notes_title': { it: 'Note', en: 'Notes' },
'sp.out_of_100': { it: 'su 100', en: 'out of 100' },
'sp.sec_req_met': { it: 'Requisiti di sicurezza soddisfatti', en: 'Security requirements met' },
'sp.sec_req_not_met': { it: 'Requisiti di sicurezza non soddisfatti', en: 'Security requirements not met' },
'sp.no_assessment_done': { it: 'Nessuna valutazione effettuata', en: 'No assessment performed' },
'sp.assessment_label': { it: 'Valutazione', en: 'Assessment' },
'sp.last_assessment': { it: 'Ultima Valutazione', en: 'Last Assessment' },
'sp.next_assessment': { it: 'Prossima Valutazione', en: 'Next Assessment' },
'sp.sec_requirements': { it: 'Requisiti Sicurezza', en: 'Security Requirements' },
'sp.met': { it: 'Soddisfatti', en: 'Met' },
'sp.not_met': { it: 'Non Soddisfatti', en: 'Not Met' },
'sp.created_at': { it: 'Creato il', en: 'Created on' },
'sp.edit_supplier': { it: 'Modifica Fornitore', en: 'Edit Supplier' },
'sp.new_supplier_modal': { it: 'Nuovo Fornitore', en: 'New Supplier' },
'sp.field_supplier_name':{ it: 'Nome Fornitore', en: 'Supplier Name' },
'sp.field_contact_email':{ it: 'Email Contatto', en: 'Contact Email' },
'sp.ph_company_name': { it: "Nome dell'azienda", en: 'Company name' },
'sp.ph_full_name': { it: 'Nome e cognome', en: 'Full name' },
'sp.ph_service_type': { it: 'es. Cloud Hosting, Sviluppo SW, Consulenza', en: 'e.g. Cloud Hosting, SW Development, Consulting' },
'sp.ph_service_desc': { it: 'Descrivi il servizio fornito...', en: 'Describe the service provided...' },
'sp.ph_notes': { it: 'Note aggiuntive...', en: 'Additional notes...' },
'sp.cancel': { it: 'Annulla', en: 'Cancel' },
'sp.save_changes': { it: 'Salva Modifiche', en: 'Save Changes' },
'sp.add_supplier': { it: 'Aggiungi Fornitore', en: 'Add Supplier' },
'sp.assess_modal_title': { it: 'Valutazione Fornitore', en: 'Supplier Assessment' },
'sp.assess_intro': { it: "Rispondi alle domande per valutare il livello di sicurezza del fornitore. Il punteggio di rischio verrà calcolato automaticamente.", en: 'Answer the questions to assess the supplier security level. The risk score will be calculated automatically.' },
'sp.answer_yes': { it: 'Sì', en: 'Yes' },
'sp.answer_partial': { it: 'Parziale', en: 'Partial' },
'sp.answer_no': { it: 'No', en: 'No' },
'sp.calculated_risk_score':{ it: 'Score Rischio Calcolato', en: 'Calculated Risk Score' },
'sp.save_assessment': { it: 'Salva Valutazione', en: 'Save Assessment' },
'sp.cat_empty': { it: 'Nessuna categoria.', en: 'No categories.' },
'sp.cat_new_title': { it: 'Nuova categoria', en: 'New category' },
'sp.cat_edit': { it: 'Modifica categoria', en: 'Edit category' },
'sp.ph_cat_name': { it: 'es. Cloud Provider', en: 'e.g. Cloud Provider' },
'sp.ph_cat_desc': { it: 'Descrizione opzionale...', en: 'Optional description...' },
'sp.save': { it: 'Salva', en: 'Save' },
'sp.create': { it: 'Crea', en: 'Create' },
'sp.close': { it: 'Chiudi', en: 'Close' },
'sp.tpl_back_plain': { it: 'Torna ai template', en: 'Back to templates' },
});
return { init, getLang, setLang, t, applyTranslations, addTranslations };
})();
// Shortcut globale
function t(key, params) { return I18n.t(key, params); }