- help.js: aggiunta sezione workflow (Compliance Journey) + pageMap entry - i18n.js: 16 chiavi IT/EN per workflow (fasi, stati, etichette) - docs/AI_LEVELS_SCHEMA.md: schema architettura 5 livelli AI con privacy matrix L1 Guida (safe), L2 Operativo, L3 Aziendale (anonimizzato), L4 Cross-Org (k-anonymity), L5 Normativo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
284 lines
16 KiB
JavaScript
284 lines
16 KiB
JavaScript
/**
|
|
* 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.management': { it: 'Gestione', en: 'Management' },
|
|
'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: 'Asset', en: 'Assets' },
|
|
'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' },
|
|
|
|
// ── 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.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' },
|
|
|
|
// ── 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 (30gg)', en: 'Final Report (30d)' },
|
|
'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 Asset', en: 'Asset Inventory' },
|
|
'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.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' },
|
|
|
|
// ── 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);
|
|
}
|
|
|
|
return { init, getLang, setLang, t, applyTranslations, addTranslations };
|
|
})();
|
|
|
|
// Shortcut globale
|
|
function t(key, params) { return I18n.t(key, params); }
|