use super::Entry;
pub(super) fn tr(key: &str) -> Option<Entry> {
tr_shared_actions(key)
.or_else(|| tr_shared_labels(key))
.or_else(|| tr_import(key))
.or_else(|| tr_export(key))
.or_else(|| tr_dump(key))
.or_else(|| tr_audit_page(key))
.or_else(|| tr_audit_result(key))
}
fn tr_shared_actions(key: &str) -> Option<Entry> {
Some(match key {
"admin.results_label" => (
"Results:",
"Ergebnisse:",
"Résultats :",
"Resultados:",
"Risultati:",
),
"admin.errors_label" => ("Errors:", "Fehler:", "Erreurs :", "Errores:", "Errori:"),
"admin.error_label" => ("Error:", "Fehler:", "Erreur :", "Error:", "Errore:"),
"admin.view_documents_link" => (
"View Documents",
"Dokumente anzeigen",
"Voir les documents",
"Ver documentos",
"Visualizza documenti",
),
"admin.back_link" => ("Back", "Zurück", "Retour", "Atrás", "Indietro"),
"admin.back_to_export_link" => (
"Back to Export",
"Zurück zu Export",
"Retour à l'export",
"Volver a Exportación",
"Torna a Esportazione",
),
_ => return None,
})
}
fn tr_shared_labels(key: &str) -> Option<Entry> {
Some(match key {
"admin.enabled_label" => ("enabled", "aktiviert", "activé", "habilitado", "abilitato"),
"admin.disabled_label" => (
"disabled",
"deaktiviert",
"désactivé",
"deshabilitado",
"disabilitato",
),
"admin.export_directory_label" => (
"Export directory:",
"Exportverzeichnis:",
"Répertoire d'export :",
"Directorio de exportación:",
"Directory di esportazione:",
),
"admin.sha256_sidecars_label" => (
"SHA-256 sidecars:",
"SHA-256-Sidecars:",
"Sidecars SHA-256 :",
"Sidecars SHA-256:",
"Sidecar SHA-256:",
),
"admin.sha512_sidecars_label" => (
"SHA-512 sidecars:",
"SHA-512-Sidecars:",
"Sidecars SHA-512 :",
"Sidecars SHA-512:",
"Sidecar SHA-512:",
),
"admin.sha3_512_sidecars_label" => (
"SHA3-512 sidecars:",
"SHA3-512-Sidecars:",
"Sidecars SHA3-512 :",
"Sidecars SHA3-512:",
"Sidecar SHA3-512:",
),
"admin.blake3_512_sidecars_label" => (
"BLAKE3-512 sidecars:",
"BLAKE3-512-Sidecars:",
"Sidecars BLAKE3-512 :",
"Sidecars BLAKE3-512:",
"Sidecar BLAKE3-512:",
),
"admin.shake256_512_sidecars_label" => (
"SHAKE256-512 sidecars:",
"SHAKE256-512-Sidecars:",
"Sidecars SHAKE256-512 :",
"Sidecars SHAKE256-512:",
"Sidecar SHAKE256-512:",
),
"admin.bytes_label" => ("bytes", "Bytes", "octets", "bytes", "byte"),
_ => return None,
})
}
fn tr_import(key: &str) -> Option<Entry> {
Some(match key {
"admin.import_heading" => (
"Import CSAF Documents",
"CSAF-Dokumente importieren",
"Importer des documents CSAF",
"Importar documentos CSAF",
"Importa documenti CSAF",
),
"admin.import_intro" => (
"Import CSAF JSON documents from the configured import directory. \
Every file is <strong>validated</strong> before being stored. Files whose \
CSAF schema or semantic rules fail hard validation are skipped with an \
error entry in the result.",
"Importiert CSAF-JSON-Dokumente aus dem konfigurierten Importverzeichnis. \
Jede Datei wird vor der Speicherung <strong>validiert</strong>. Dateien, deren \
CSAF-Schema oder semantische Regeln die strikte Validierung nicht bestehen, \
werden übersprungen und im Ergebnis als Fehler aufgeführt.",
"Importe les documents CSAF JSON depuis le répertoire d'import configuré. \
Chaque fichier est <strong>validé</strong> avant d'être stocké. Les fichiers \
dont le schéma CSAF ou les règles sémantiques échouent à la validation \
stricte sont ignorés et signalés comme erreur dans le résultat.",
"Importa documentos CSAF JSON desde el directorio de importación configurado. \
Cada archivo se <strong>valida</strong> antes de almacenarse. Los archivos \
cuyo esquema CSAF o reglas semánticas no superen la validación estricta se \
omiten y se registran como error en el resultado.",
"Importa documenti CSAF JSON dalla directory di importazione configurata. \
Ogni file viene <strong>validato</strong> prima di essere archiviato. I file \
il cui schema CSAF o le cui regole semantiche non superano la validazione \
rigorosa vengono ignorati e segnalati come errore nel risultato.",
),
"admin.import_directory_label" => (
"Import directory:",
"Importverzeichnis:",
"Répertoire d'import :",
"Directorio de importación:",
"Directory di importazione:",
),
"admin.import_place_hint" => (
"Place <code>*.json</code> CSAF files in the import directory (subdirectories \
are scanned recursively). Files named <code>provider-metadata.json</code> are \
skipped automatically.",
"Legen Sie <code>*.json</code>-CSAF-Dateien im Importverzeichnis ab \
(Unterverzeichnisse werden rekursiv durchsucht). Dateien mit dem Namen \
<code>provider-metadata.json</code> werden automatisch übersprungen.",
"Placez les fichiers CSAF <code>*.json</code> dans le répertoire d'import (les \
sous-répertoires sont parcourus récursivement). Les fichiers nommés \
<code>provider-metadata.json</code> sont ignorés automatiquement.",
"Coloque los archivos CSAF <code>*.json</code> en el directorio de importación \
(los subdirectorios se recorren de forma recursiva). Los archivos llamados \
<code>provider-metadata.json</code> se omiten automáticamente.",
"Posizionare i file CSAF <code>*.json</code> nella directory di importazione \
(le sottodirectory vengono analizzate ricorsivamente). I file denominati \
<code>provider-metadata.json</code> vengono ignorati automaticamente.",
),
"admin.importing_button" => (
"Importing...",
"Importiere...",
"Importation...",
"Importando...",
"Importazione...",
),
"admin.start_import_button" => (
"Start Import",
"Import starten",
"Démarrer l'import",
"Iniciar importación",
"Avvia importazione",
),
"admin.import_complete_title" => (
"Import Complete",
"Import abgeschlossen",
"Import terminé",
"Importación completada",
"Importazione completata",
),
"admin.import_result_line" => (
"{imported} document(s) imported, {skipped} skipped.",
"{imported} Dokument(e) importiert, {skipped} übersprungen.",
"{imported} document(s) importé(s), {skipped} ignoré(s).",
"{imported} documento(s) importado(s), {skipped} omitido(s).",
"{imported} documenti importati, {skipped} ignorati.",
),
"admin.import_again_link" => (
"Import Again",
"Erneut importieren",
"Importer à nouveau",
"Importar de nuevo",
"Importa di nuovo",
),
"admin.import_failed_title" => (
"Import Failed",
"Import fehlgeschlagen",
"Échec de l'import",
"Error al importar",
"Importazione non riuscita",
),
_ => return None,
})
}
fn tr_export(key: &str) -> Option<Entry> {
Some(match key {
"admin.export_heading" => (
"Export CSAF Documents",
"CSAF-Dokumente exportieren",
"Exporter des documents CSAF",
"Exportar documentos CSAF",
"Esporta documenti CSAF",
),
"admin.export_intro" => (
"Export all stored CSAF documents to the filesystem with sidecar hash files. \
Each document is <strong>validated</strong> and its <code>csaf_version</code> \
is rewritten to match the currently active CSAF mode.",
"Exportiert alle gespeicherten CSAF-Dokumente mit Sidecar-Hashdateien in das \
Dateisystem. Jedes Dokument wird <strong>validiert</strong>, und sein \
<code>csaf_version</code>-Feld wird an den aktuell aktiven CSAF-Modus \
angepasst.",
"Exporte tous les documents CSAF stockés vers le système de fichiers avec des \
fichiers de hachage sidecar. Chaque document est <strong>validé</strong> et \
son champ <code>csaf_version</code> est réécrit pour correspondre au mode \
CSAF actuellement actif.",
"Exporta todos los documentos CSAF almacenados al sistema de archivos con \
archivos hash sidecar. Cada documento se <strong>valida</strong> y su campo \
<code>csaf_version</code> se reescribe para coincidir con el modo CSAF \
actualmente activo.",
"Esporta tutti i documenti CSAF archiviati nel filesystem con file hash \
sidecar. Ogni documento viene <strong>validato</strong> e il suo campo \
<code>csaf_version</code> viene riscritto per corrispondere alla modalità \
CSAF attualmente attiva.",
),
"admin.csaf_mode_label" => (
"CSAF mode (written into files):",
"CSAF-Modus (in Dateien geschrieben):",
"Mode CSAF (écrit dans les fichiers) :",
"Modo CSAF (escrito en los archivos):",
"Modalità CSAF (scritta nei file):",
),
"admin.documents_to_export_label" => (
"Documents to export:",
"Zu exportierende Dokumente:",
"Documents à exporter :",
"Documentos a exportar:",
"Documenti da esportare:",
),
"admin.exporting_button" => (
"Exporting...",
"Exportiere...",
"Exportation...",
"Exportando...",
"Esportazione...",
),
"admin.start_export_button" => (
"Start Export",
"Export starten",
"Démarrer l'export",
"Iniciar exportación",
"Avvia esportazione",
),
"admin.export_complete_title" => (
"Export Complete",
"Export abgeschlossen",
"Export terminé",
"Exportación completada",
"Esportazione completata",
),
"admin.export_result_line" => (
"{exported} document(s) exported (CSAF {mode}) to <code>{export_dir}</code>.",
"{exported} Dokument(e) exportiert (CSAF {mode}) nach <code>{export_dir}</code>.",
"{exported} document(s) exporté(s) (CSAF {mode}) vers <code>{export_dir}</code>.",
"{exported} documento(s) exportado(s) (CSAF {mode}) a <code>{export_dir}</code>.",
"{exported} documenti esportati (CSAF {mode}) in <code>{export_dir}</code>.",
),
"admin.export_again_link" => (
"Export Again",
"Erneut exportieren",
"Exporter à nouveau",
"Exportar de nuevo",
"Esporta di nuovo",
),
_ => return None,
})
}
fn tr_dump(key: &str) -> Option<Entry> {
Some(match key {
"admin.dump_heading" => (
"Dump Database",
"Datenbank-Dump",
"Dump de la base de données",
"Volcado de la base de datos",
"Dump del database",
),
"admin.dump_intro" => (
"Snapshot the live <code>csaf.redb</code> and <code>csaf.sqlite</code> \
databases into the configured <strong>Dump Directory</strong> with matching \
SHA-256, SHA-512, SHA3-512, BLAKE3-512 and SHAKE256-512 hash sidecars — \
whichever of the five are enabled in Settings. The sqlite snapshot uses the \
online-backup API so writes in flight are not lost, and the redb copy is \
pinned by an MVCC read transaction for the duration of the copy.",
"Erstellt eine Momentaufnahme der aktiven Datenbanken <code>csaf.redb</code> \
und <code>csaf.sqlite</code> im konfigurierten <strong>Dump-Verzeichnis</strong>, \
mit passenden SHA-256-, SHA-512-, SHA3-512-, BLAKE3-512- und \
SHAKE256-512-Hash-Sidecars — je nachdem, welche der fünf in den Einstellungen \
aktiviert sind. Die sqlite-Momentaufnahme nutzt die Online-Backup-API, sodass \
laufende Schreibvorgänge nicht verloren gehen; die redb-Kopie wird für die \
Dauer des Kopiervorgangs durch eine MVCC-Lesetransaktion fixiert.",
"Effectue un instantané des bases de données actives <code>csaf.redb</code> et \
<code>csaf.sqlite</code> dans le <strong>répertoire de dump</strong> configuré, \
avec les fichiers sidecar de hachage SHA-256, SHA-512, SHA3-512, BLAKE3-512 et \
SHAKE256-512 correspondants — selon celles qui, parmi les cinq, sont activées \
dans les paramètres. L'instantané sqlite utilise l'API de sauvegarde en ligne \
afin qu'aucune écriture en cours ne soit perdue, et la copie redb est figée par \
une transaction de lecture MVCC pendant toute la durée de la copie.",
"Crea una instantánea de las bases de datos activas <code>csaf.redb</code> y \
<code>csaf.sqlite</code> en el <strong>directorio de volcado</strong> \
configurado, con los archivos hash sidecar SHA-256, SHA-512, SHA3-512, \
BLAKE3-512 y SHAKE256-512 correspondientes — según cuáles de los cinco estén \
habilitados en Configuración. La instantánea de sqlite utiliza la API de copia \
de seguridad en línea para que no se pierda ninguna escritura en curso, y la \
copia de redb queda fijada mediante una transacción de lectura MVCC durante \
toda la copia.",
"Crea uno snapshot dei database attivi <code>csaf.redb</code> e \
<code>csaf.sqlite</code> nella <strong>directory di dump</strong> configurata, \
con i corrispondenti sidecar hash SHA-256, SHA-512, SHA3-512, BLAKE3-512 e \
SHAKE256-512 — a seconda di quali dei cinque sono abilitati nelle Impostazioni. \
Lo snapshot sqlite utilizza l'API di backup online in modo che le scritture in \
corso non vadano perse, mentre la copia redb viene bloccata da una transazione \
di lettura MVCC per l'intera durata della copia.",
),
"admin.dump_directory_label" => (
"Dump directory:",
"Dump-Verzeichnis:",
"Répertoire de dump :",
"Directorio de volcado:",
"Directory di dump:",
),
"admin.dumping_button" => (
"Dumping...",
"Erstelle Dump...",
"Dump en cours...",
"Volcando...",
"Dump in corso...",
),
"admin.start_dump_button" => (
"Start Dump",
"Dump starten",
"Démarrer le dump",
"Iniciar volcado",
"Avvia dump",
),
"admin.dump_complete_title" => (
"Dump Complete",
"Dump abgeschlossen",
"Dump terminé",
"Volcado completado",
"Dump completato",
),
"admin.dump_result_line" => (
"database snapshot written to <code>{dump_dir}</code> with timestamp <code>{ts}</code>.",
"Datenbank-Momentaufnahme geschrieben nach <code>{dump_dir}</code> mit Zeitstempel <code>{ts}</code>.",
"instantané de la base de données écrit dans <code>{dump_dir}</code> avec l'horodatage <code>{ts}</code>.",
"instantánea de la base de datos escrita en <code>{dump_dir}</code> con marca de tiempo <code>{ts}</code>.",
"snapshot del database scritto in <code>{dump_dir}</code> con timestamp <code>{ts}</code>.",
),
"admin.sidecar_files_heading" => (
"Sidecar files",
"Sidecar-Dateien",
"Fichiers sidecar",
"Archivos sidecar",
"File sidecar",
),
"admin.dump_failed_title" => (
"Dump Failed",
"Dump fehlgeschlagen",
"Échec du dump",
"Error al volcar",
"Dump non riuscito",
),
_ => return None,
})
}
fn tr_audit_page(key: &str) -> Option<Entry> {
Some(match key {
"admin.audit_export_heading" => (
"Export Audit Log",
"Audit-Protokoll exportieren",
"Exporter le journal d'audit",
"Exportar registro de auditoría",
"Esporta registro di audit",
),
"admin.audit_export_intro" => (
"Export every row of the <code>audit_log</code> table (CRUD, settings \
changes, import / export events) in four formats, each with matching hash \
sidecars. Outputs land in the <strong>Export Directory</strong> under an \
ISO-8601 timestamp stem: <code>audit-YYYY-MM-DDTHH-MM-SSZ.{md,csv,json,sarif}</code>. \
SARIF 2.1.0 output is self-validated before write.",
"Exportiert jede Zeile der Tabelle <code>audit_log</code> (CRUD, \
Einstellungsänderungen, Import-/Export-Ereignisse) in vier Formaten, jeweils \
mit passenden Hash-Sidecars. Die Ausgabedateien landen im \
<strong>Exportverzeichnis</strong> unter einem ISO-8601-Zeitstempel-Stamm: \
<code>audit-YYYY-MM-DDTHH-MM-SSZ.{md,csv,json,sarif}</code>. Die \
SARIF-2.1.0-Ausgabe wird vor dem Schreiben selbst validiert.",
"Exporte chaque ligne de la table <code>audit_log</code> (CRUD, modifications \
des paramètres, événements d'import/export) en quatre formats, chacun avec ses \
fichiers sidecar de hachage correspondants. Les fichiers produits sont déposés \
dans le <strong>répertoire d'export</strong> sous un radical horodaté ISO-8601 : \
<code>audit-YYYY-MM-DDTHH-MM-SSZ.{md,csv,json,sarif}</code>. La sortie SARIF \
2.1.0 est auto-validée avant écriture.",
"Exporta cada fila de la tabla <code>audit_log</code> (CRUD, cambios de \
configuración, eventos de importación/exportación) en cuatro formatos, cada \
uno con sus archivos hash sidecar correspondientes. Los archivos generados se \
guardan en el <strong>directorio de exportación</strong> bajo un prefijo con \
marca de tiempo ISO-8601: <code>audit-YYYY-MM-DDTHH-MM-SSZ.{md,csv,json,sarif}</code>. \
La salida SARIF 2.1.0 se autovalida antes de escribirse.",
"Esporta ogni riga della tabella <code>audit_log</code> (CRUD, modifiche alle \
impostazioni, eventi di importazione/esportazione) in quattro formati, \
ciascuno con i relativi sidecar hash. I file prodotti vengono salvati nella \
<strong>directory di esportazione</strong> con un prefisso timestamp ISO-8601: \
<code>audit-YYYY-MM-DDTHH-MM-SSZ.{md,csv,json,sarif}</code>. L'output SARIF \
2.1.0 viene autovalidato prima della scrittura.",
),
"admin.exporting_audit_button" => (
"Exporting audit log...",
"Exportiere Audit-Protokoll...",
"Export du journal d'audit...",
"Exportando registro de auditoría...",
"Esportazione registro di audit...",
),
"admin.format_markdown_label" => (
"Markdown (<code>.md</code>)",
"Markdown (<code>.md</code>)",
"Markdown (<code>.md</code>)",
"Markdown (<code>.md</code>)",
"Markdown (<code>.md</code>)",
),
"admin.format_csv_label" => (
"CSV (<code>.csv</code>)",
"CSV (<code>.csv</code>)",
"CSV (<code>.csv</code>)",
"CSV (<code>.csv</code>)",
"CSV (<code>.csv</code>)",
),
"admin.format_json_label" => (
"JSON (<code>.json</code>)",
"JSON (<code>.json</code>)",
"JSON (<code>.json</code>)",
"JSON (<code>.json</code>)",
"JSON (<code>.json</code>)",
),
"admin.format_sarif_label" => (
"SARIF 2.1 (<code>.sarif</code>)",
"SARIF 2.1 (<code>.sarif</code>)",
"SARIF 2.1 (<code>.sarif</code>)",
"SARIF 2.1 (<code>.sarif</code>)",
"SARIF 2.1 (<code>.sarif</code>)",
),
_ => return None,
})
}
fn tr_audit_result(key: &str) -> Option<Entry> {
Some(match key {
"admin.audit_export_title" => (
"Audit Log Export",
"Audit-Protokoll-Export",
"Export du journal d'audit",
"Exportación del registro de auditoría",
"Esportazione registro di audit",
),
"admin.audit_export_no_format_selected" => (
"No output format was selected. Please tick at least one of Markdown, CSV, \
JSON, or SARIF.",
"Es wurde kein Ausgabeformat ausgewählt. Bitte wählen Sie mindestens eines aus \
Markdown, CSV, JSON oder SARIF.",
"Aucun format de sortie n'a été sélectionné. Veuillez cocher au moins Markdown, \
CSV, JSON ou SARIF.",
"No se seleccionó ningún formato de salida. Marque al menos uno de los \
siguientes: Markdown, CSV, JSON o SARIF.",
"Non è stato selezionato alcun formato di output. Selezionare almeno una tra le \
opzioni Markdown, CSV, JSON o SARIF.",
),
"admin.audit_export_complete_title" => (
"Audit Log Export Complete",
"Audit-Protokoll-Export abgeschlossen",
"Export du journal d'audit terminé",
"Exportación del registro de auditoría completada",
"Esportazione registro di audit completata",
),
"admin.audit_export_result_line" => (
"{rows} audit row(s) exported into {payloads} payload file(s) with {sidecars} \
sidecar(s), timestamp <code>{ts}</code>.",
"{rows} Audit-Zeile(n) exportiert in {payloads} Nutzdatendatei(en) mit \
{sidecars} Sidecar(s), Zeitstempel <code>{ts}</code>.",
"{rows} ligne(s) d'audit exportée(s) dans {payloads} fichier(s) de données \
avec {sidecars} sidecar(s), horodatage <code>{ts}</code>.",
"{rows} fila(s) de auditoría exportada(s) en {payloads} archivo(s) de datos \
con {sidecars} sidecar(s), marca de tiempo <code>{ts}</code>.",
"{rows} righe di audit esportate in {payloads} file di payload con {sidecars} \
sidecar, timestamp <code>{ts}</code>.",
),
"admin.payloads_heading" => (
"Payloads",
"Payload-Dateien",
"Fichiers payload",
"Archivos payload",
"File payload",
),
"admin.sidecars_heading" => ("Sidecars", "Sidecars", "Sidecars", "Sidecars", "Sidecar"),
"admin.audit_export_failed_title" => (
"Audit Log Export Failed",
"Audit-Protokoll-Export fehlgeschlagen",
"Échec de l'export du journal d'audit",
"Error al exportar el registro de auditoría",
"Esportazione registro di audit non riuscita",
),
_ => return None,
})
}
#[cfg(test)]
mod tests {
use super::super::{Lang, t};
use super::*;
const ALL_KEYS: &[&str] = &[
"admin.results_label",
"admin.errors_label",
"admin.error_label",
"admin.view_documents_link",
"admin.back_link",
"admin.back_to_export_link",
"admin.enabled_label",
"admin.disabled_label",
"admin.export_directory_label",
"admin.sha256_sidecars_label",
"admin.sha512_sidecars_label",
"admin.sha3_512_sidecars_label",
"admin.blake3_512_sidecars_label",
"admin.shake256_512_sidecars_label",
"admin.bytes_label",
"admin.import_heading",
"admin.import_intro",
"admin.import_directory_label",
"admin.import_place_hint",
"admin.importing_button",
"admin.start_import_button",
"admin.import_complete_title",
"admin.import_result_line",
"admin.import_again_link",
"admin.import_failed_title",
"admin.export_heading",
"admin.export_intro",
"admin.csaf_mode_label",
"admin.documents_to_export_label",
"admin.exporting_button",
"admin.start_export_button",
"admin.export_complete_title",
"admin.export_result_line",
"admin.export_again_link",
"admin.dump_heading",
"admin.dump_intro",
"admin.dump_directory_label",
"admin.dumping_button",
"admin.start_dump_button",
"admin.dump_complete_title",
"admin.dump_result_line",
"admin.sidecar_files_heading",
"admin.dump_failed_title",
"admin.audit_export_heading",
"admin.audit_export_intro",
"admin.exporting_audit_button",
"admin.format_markdown_label",
"admin.format_csv_label",
"admin.format_json_label",
"admin.format_sarif_label",
"admin.audit_export_title",
"admin.audit_export_no_format_selected",
"admin.audit_export_complete_title",
"admin.audit_export_result_line",
"admin.payloads_heading",
"admin.sidecars_heading",
"admin.audit_export_failed_title",
];
#[test]
fn every_admin_key_has_five_nonempty_translations() {
for key in ALL_KEYS {
let (en, de, fr, es, it) = tr(key).unwrap_or_else(|| panic!("{key} resolves"));
assert!(
!en.is_empty()
&& !de.is_empty()
&& !fr.is_empty()
&& !es.is_empty()
&& !it.is_empty(),
"{key}"
);
}
}
#[test]
fn unknown_key_is_not_claimed_by_this_table() {
assert_eq!(tr("admin.does_not_exist"), None);
}
#[test]
fn t_dispatches_admin_keys_through_the_shared_lookup() {
assert_eq!(t(Lang::De, "admin.start_import_button"), "Import starten");
assert_eq!(t(Lang::Fr, "admin.export_again_link"), "Exporter à nouveau");
assert_eq!(t(Lang::It, "admin.dump_failed_title"), "Dump non riuscito");
assert_eq!(t(Lang::Es, "admin.sidecars_heading"), "Sidecars");
}
}