chore: release v2.4

- Add theme system (Dark/Light palettes, ModernTheme, ThemeManager)
- Add InputDialog, Spinner common view
- Add DuplicatesCsvExportService
- Refresh views, dialogs, and view models across tabs
- Update localization strings (en/fr)
- Tweak services (transfer, permissions, search, user access, ownership elevation, bulk operations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dev
2026-04-20 11:23:11 +02:00
parent 8f30a60d2a
commit 12dd1de9f2
93 changed files with 8708 additions and 1159 deletions
+215 -2
View File
@@ -109,6 +109,18 @@
<data name="settings.lang.fr" xml:space="preserve">
<value>Français</value>
</data>
<data name="settings.theme" xml:space="preserve">
<value>Thème</value>
</data>
<data name="settings.theme.system" xml:space="preserve">
<value>Utiliser le paramètre système</value>
</data>
<data name="settings.theme.light" xml:space="preserve">
<value>Clair</value>
</data>
<data name="settings.theme.dark" xml:space="preserve">
<value>Sombre</value>
</data>
<data name="settings.folder" xml:space="preserve">
<value>Dossier de sortie des données</value>
</data>
@@ -130,8 +142,8 @@
<data name="profile.add" xml:space="preserve">
<value>Ajouter</value>
</data>
<data name="profile.rename" xml:space="preserve">
<value>Renommer</value>
<data name="profile.save" xml:space="preserve">
<value>Enregistrer</value>
</data>
<data name="profile.delete" xml:space="preserve">
<value>Supprimer</value>
@@ -139,6 +151,9 @@
<data name="status.ready" xml:space="preserve">
<value>Prêt</value>
</data>
<data name="status.complete" xml:space="preserve">
<value>Termin&#233;</value>
</data>
<data name="status.cancelled" xml:space="preserve">
<value>Opération annulée</value>
</data>
@@ -357,6 +372,27 @@
<data name="audit.btn.exportHtml" xml:space="preserve">
<value>Exporter HTML</value>
</data>
<data name="export.split.label" xml:space="preserve">
<value>D&#233;couper</value>
</data>
<data name="export.split.single" xml:space="preserve">
<value>Fichier unique</value>
</data>
<data name="export.split.bySite" xml:space="preserve">
<value>Par site</value>
</data>
<data name="export.split.byUser" xml:space="preserve">
<value>Par utilisateur</value>
</data>
<data name="export.html.layout.label" xml:space="preserve">
<value>Mise en page HTML</value>
</data>
<data name="export.html.layout.separate" xml:space="preserve">
<value>Fichiers s&#233;par&#233;s</value>
</data>
<data name="export.html.layout.tabbed" xml:space="preserve">
<value>Fichier unique &#224; onglets</value>
</data>
<data name="audit.summary.total" xml:space="preserve">
<value>Total des acc&#232;s</value>
</data>
@@ -437,4 +473,181 @@
<data name="settings.ownership.auto" xml:space="preserve"><value>Prendre automatiquement la propri&#233;t&#233; d'administrateur de collection de sites en cas de refus d'acc&#232;s</value></data>
<data name="settings.ownership.description" xml:space="preserve"><value>Lorsqu'activ&#233;, l'application prendra automatiquement les droits d'administrateur de collection de sites lorsqu'un scan rencontre une erreur de refus d'acc&#232;s. N&#233;cessite les permissions d'administrateur de tenant.</value></data>
<data name="permissions.elevated.tooltip" xml:space="preserve"><value>Ce site a &#233;t&#233; &#233;lev&#233; automatiquement — la propri&#233;t&#233; a &#233;t&#233; prise pour compl&#233;ter le scan</value></data>
<!-- Report export localization -->
<data name="report.title.user_access" xml:space="preserve"><value>Rapport d'audit des acc&#232;s utilisateurs</value></data>
<data name="report.title.user_access_consolidated" xml:space="preserve"><value>Rapport d'audit des acc&#232;s utilisateurs (consolid&#233;)</value></data>
<data name="report.title.permissions" xml:space="preserve"><value>Rapport des permissions SharePoint</value></data>
<data name="report.title.permissions_simplified" xml:space="preserve"><value>Rapport des permissions SharePoint (simplifi&#233;)</value></data>
<data name="report.title.storage" xml:space="preserve"><value>M&#233;triques de stockage SharePoint</value></data>
<data name="report.title.duplicates" xml:space="preserve"><value>Rapport de d&#233;tection de doublons SharePoint</value></data>
<data name="report.title.duplicates_short" xml:space="preserve"><value>Rapport de d&#233;tection de doublons</value></data>
<data name="report.title.search" xml:space="preserve"><value>R&#233;sultats de recherche de fichiers SharePoint</value></data>
<data name="report.title.search_short" xml:space="preserve"><value>R&#233;sultats de recherche de fichiers</value></data>
<data name="report.stat.total_accesses" xml:space="preserve"><value>Acc&#232;s totaux</value></data>
<data name="report.stat.users_audited" xml:space="preserve"><value>Utilisateurs audit&#233;s</value></data>
<data name="report.stat.sites_scanned" xml:space="preserve"><value>Sites analys&#233;s</value></data>
<data name="report.stat.high_privilege" xml:space="preserve"><value>Privil&#232;ge &#233;lev&#233;</value></data>
<data name="report.stat.external_users" xml:space="preserve"><value>Utilisateurs externes</value></data>
<data name="report.stat.total_entries" xml:space="preserve"><value>Entr&#233;es totales</value></data>
<data name="report.stat.unique_permission_sets" xml:space="preserve"><value>Ensembles de permissions uniques</value></data>
<data name="report.stat.distinct_users_groups" xml:space="preserve"><value>Utilisateurs/Groupes distincts</value></data>
<data name="report.stat.libraries" xml:space="preserve"><value>Biblioth&#232;ques</value></data>
<data name="report.stat.files" xml:space="preserve"><value>Fichiers</value></data>
<data name="report.stat.total_size" xml:space="preserve"><value>Taille totale</value></data>
<data name="report.stat.version_size" xml:space="preserve"><value>Taille des versions</value></data>
<data name="report.badge.guest" xml:space="preserve"><value>Invit&#233;</value></data>
<data name="report.badge.direct" xml:space="preserve"><value>Direct</value></data>
<data name="report.badge.group" xml:space="preserve"><value>Groupe</value></data>
<data name="report.badge.inherited" xml:space="preserve"><value>H&#233;rit&#233;</value></data>
<data name="report.badge.unique" xml:space="preserve"><value>Unique</value></data>
<data name="report.view.by_user" xml:space="preserve"><value>Par utilisateur</value></data>
<data name="report.view.by_site" xml:space="preserve"><value>Par site</value></data>
<data name="report.filter.placeholder_results" xml:space="preserve"><value>Filtrer les r&#233;sultats...</value></data>
<data name="report.filter.placeholder_permissions" xml:space="preserve"><value>Filtrer les permissions...</value></data>
<data name="report.filter.placeholder_rows" xml:space="preserve"><value>Filtrer les lignes…</value></data>
<data name="report.filter.label" xml:space="preserve"><value>Filtre :</value></data>
<data name="report.col.site" xml:space="preserve"><value>Site</value></data>
<data name="report.col.sites" xml:space="preserve"><value>Sites</value></data>
<data name="report.col.object_type" xml:space="preserve"><value>Type d'objet</value></data>
<data name="report.col.object" xml:space="preserve"><value>Objet</value></data>
<data name="report.col.permission_level" xml:space="preserve"><value>Niveau de permission</value></data>
<data name="report.col.access_type" xml:space="preserve"><value>Type d'acc&#232;s</value></data>
<data name="report.col.granted_through" xml:space="preserve"><value>Accord&#233; via</value></data>
<data name="report.col.user" xml:space="preserve"><value>Utilisateur</value></data>
<data name="report.col.title" xml:space="preserve"><value>Titre</value></data>
<data name="report.col.url" xml:space="preserve"><value>URL</value></data>
<data name="report.col.users_groups" xml:space="preserve"><value>Utilisateurs/Groupes</value></data>
<data name="report.col.simplified" xml:space="preserve"><value>Simplifi&#233;</value></data>
<data name="report.col.risk" xml:space="preserve"><value>Risque</value></data>
<data name="report.col.library_folder" xml:space="preserve"><value>Biblioth&#232;que / Dossier</value></data>
<data name="report.col.last_modified" xml:space="preserve"><value>Derni&#232;re modification</value></data>
<data name="report.col.name" xml:space="preserve"><value>Nom</value></data>
<data name="report.col.library" xml:space="preserve"><value>Biblioth&#232;que</value></data>
<data name="report.col.path" xml:space="preserve"><value>Chemin</value></data>
<data name="report.col.size" xml:space="preserve"><value>Taille</value></data>
<data name="report.col.created" xml:space="preserve"><value>Cr&#233;&#233;</value></data>
<data name="report.col.modified" xml:space="preserve"><value>Modifi&#233;</value></data>
<data name="report.col.created_by" xml:space="preserve"><value>Cr&#233;&#233; par</value></data>
<data name="report.col.modified_by" xml:space="preserve"><value>Modifi&#233; par</value></data>
<data name="report.col.file_name" xml:space="preserve"><value>Nom de fichier</value></data>
<data name="report.col.extension" xml:space="preserve"><value>Extension</value></data>
<data name="report.col.file_type" xml:space="preserve"><value>Type de fichier</value></data>
<data name="report.col.file_count" xml:space="preserve"><value>Nombre de fichiers</value></data>
<data name="report.col.error" xml:space="preserve"><value>Erreur</value></data>
<data name="report.col.timestamp" xml:space="preserve"><value>Horodatage</value></data>
<data name="report.col.number" xml:space="preserve"><value>#</value></data>
<data name="report.col.group" xml:space="preserve"><value>Groupe</value></data>
<data name="report.col.total_size_mb" xml:space="preserve"><value>Taille totale (Mo)</value></data>
<data name="report.col.version_size_mb" xml:space="preserve"><value>Taille des versions (Mo)</value></data>
<data name="report.col.size_mb" xml:space="preserve"><value>Taille (Mo)</value></data>
<data name="report.col.size_bytes" xml:space="preserve"><value>Taille (octets)</value></data>
<data name="report.text.accesses" xml:space="preserve"><value>acc&#232;s</value></data>
<data name="report.text.access_es" xml:space="preserve"><value>acc&#232;s</value></data>
<data name="report.text.sites_parens" xml:space="preserve"><value>site(s)</value></data>
<data name="report.text.permissions_parens" xml:space="preserve"><value>permission(s)</value></data>
<data name="report.text.copies" xml:space="preserve"><value>copies</value></data>
<data name="report.text.duplicate_groups_found" xml:space="preserve"><value>groupe(s) de doublons trouv&#233;(s).</value></data>
<data name="report.text.results_parens" xml:space="preserve"><value>r&#233;sultat(s)</value></data>
<data name="report.text.of" xml:space="preserve"><value>sur</value></data>
<data name="report.text.shown" xml:space="preserve"><value>affich&#233;(s)</value></data>
<data name="report.text.generated" xml:space="preserve"><value>G&#233;n&#233;r&#233;</value></data>
<data name="report.text.generated_colon" xml:space="preserve"><value>G&#233;n&#233;r&#233; :</value></data>
<data name="report.text.members_unavailable" xml:space="preserve"><value>membres indisponibles</value></data>
<data name="report.text.link" xml:space="preserve"><value>Lien</value></data>
<data name="report.text.no_ext" xml:space="preserve"><value>(sans ext.)</value></data>
<data name="report.text.no_extension" xml:space="preserve"><value>(sans extension)</value></data>
<data name="report.text.high_priv" xml:space="preserve"><value>priv. &#233;lev&#233;</value></data>
<data name="report.section.storage_by_file_type" xml:space="preserve"><value>Stockage par type de fichier</value></data>
<data name="report.section.library_details" xml:space="preserve"><value>D&#233;tails des biblioth&#232;ques</value></data>
<!-- Site picker dialog -->
<data name="sitepicker.title" xml:space="preserve"><value>S&#233;lectionner les sites</value></data>
<data name="sitepicker.filter" xml:space="preserve"><value>Filtre&#160;:</value></data>
<data name="sitepicker.type" xml:space="preserve"><value>Type&#160;:</value></data>
<data name="sitepicker.type.all" xml:space="preserve"><value>Tous</value></data>
<data name="sitepicker.type.team" xml:space="preserve"><value>Sites d'&#233;quipe (MS Teams)</value></data>
<data name="sitepicker.type.communication" xml:space="preserve"><value>Communication</value></data>
<data name="sitepicker.type.classic" xml:space="preserve"><value>Classique</value></data>
<data name="sitepicker.type.other" xml:space="preserve"><value>Autre</value></data>
<data name="sitepicker.size" xml:space="preserve"><value>Taille (Mo)&#160;:</value></data>
<data name="sitepicker.size.min" xml:space="preserve"><value>min</value></data>
<data name="sitepicker.size.max" xml:space="preserve"><value>max</value></data>
<data name="sitepicker.col.title" xml:space="preserve"><value>Titre</value></data>
<data name="sitepicker.col.url" xml:space="preserve"><value>URL</value></data>
<data name="sitepicker.col.type" xml:space="preserve"><value>Type</value></data>
<data name="sitepicker.col.size" xml:space="preserve"><value>Taille</value></data>
<data name="sitepicker.btn.load" xml:space="preserve"><value>Charger les sites</value></data>
<data name="sitepicker.btn.selectAll" xml:space="preserve"><value>Tout s&#233;lectionner</value></data>
<data name="sitepicker.btn.deselectAll" xml:space="preserve"><value>Tout d&#233;s&#233;lectionner</value></data>
<data name="sitepicker.btn.ok" xml:space="preserve"><value>OK</value></data>
<data name="sitepicker.btn.cancel" xml:space="preserve"><value>Annuler</value></data>
<data name="sitepicker.status.loading" xml:space="preserve"><value>Chargement des sites...</value></data>
<data name="sitepicker.status.loaded" xml:space="preserve"><value>{0} sites charg&#233;s.</value></data>
<data name="sitepicker.status.shown" xml:space="preserve"><value>{0} / {1} sites affich&#233;s.</value></data>
<data name="sitepicker.status.error" xml:space="preserve"><value>Erreur&#160;: {0}</value></data>
<data name="sitepicker.kind.teamsite" xml:space="preserve"><value>Site d'&#233;quipe</value></data>
<data name="sitepicker.kind.communication" xml:space="preserve"><value>Communication</value></data>
<data name="sitepicker.kind.classic" xml:space="preserve"><value>Classique</value></data>
<data name="sitepicker.kind.other" xml:space="preserve"><value>Autre</value></data>
<!-- Common UI -->
<data name="common.valid" xml:space="preserve"><value>Valide</value></data>
<data name="common.errors" xml:space="preserve"><value>Erreurs</value></data>
<data name="common.close" xml:space="preserve"><value>Fermer</value></data>
<data name="common.new_folder" xml:space="preserve"><value>+ Nouveau dossier</value></data>
<data name="common.guest" xml:space="preserve"><value>Invit&#233;</value></data>
<!-- InputDialog -->
<data name="input.title" xml:space="preserve"><value>Saisie</value></data>
<!-- ProfileManagementDialog -->
<data name="profmgmt.title" xml:space="preserve"><value>G&#233;rer les profils</value></data>
<data name="profmgmt.group" xml:space="preserve"><value>Profils</value></data>
<!-- Duplicates columns -->
<data name="duplicates.col.group" xml:space="preserve"><value>Groupe</value></data>
<data name="duplicates.col.copies" xml:space="preserve"><value>Copies</value></data>
<!-- Folder structure levels -->
<data name="folderstruct.col.level1" xml:space="preserve"><value>Niveau 1</value></data>
<data name="folderstruct.col.level2" xml:space="preserve"><value>Niveau 2</value></data>
<data name="folderstruct.col.level3" xml:space="preserve"><value>Niveau 3</value></data>
<data name="folderstruct.col.level4" xml:space="preserve"><value>Niveau 4</value></data>
<!-- Permissions extra columns -->
<data name="perm.col.unique_perms" xml:space="preserve"><value>Perm. uniques</value></data>
<data name="perm.col.permission_levels" xml:space="preserve"><value>Niveaux d'autorisation</value></data>
<data name="perm.col.principal_type" xml:space="preserve"><value>Type de principal</value></data>
<!-- Storage summary labels -->
<data name="storage.lbl.total_size_colon" xml:space="preserve"><value>Taille totale&#160;: </value></data>
<data name="storage.lbl.version_size_colon" xml:space="preserve"><value>Taille des versions&#160;: </value></data>
<data name="storage.lbl.files_colon" xml:space="preserve"><value>Fichiers&#160;: </value></data>
<!-- Templates columns -->
<data name="templates.col.source" xml:space="preserve"><value>Source</value></data>
<data name="templates.col.captured" xml:space="preserve"><value>Captur&#233;</value></data>
<!-- Transfer view -->
<data name="transfer.text.files_selected" xml:space="preserve"><value> fichier(s) s&#233;lectionn&#233;(s)</value></data>
<data name="transfer.chk.include_source" xml:space="preserve"><value>Inclure le dossier source dans la destination</value></data>
<data name="transfer.chk.include_source.tooltip" xml:space="preserve"><value>Si activ&#233;, recr&#233;e le dossier source sous la destination. Sinon, d&#233;pose le contenu directement dans le dossier de destination.</value></data>
<data name="transfer.chk.copy_contents" xml:space="preserve"><value>Copier le contenu du dossier</value></data>
<data name="transfer.chk.copy_contents.tooltip" xml:space="preserve"><value>Si activ&#233; (par d&#233;faut), transf&#232;re les fichiers du dossier. Sinon, seul le dossier est cr&#233;&#233; &#224; la destination.</value></data>
<!-- Shared ViewModel errors and statuses -->
<data name="err.no_tenant" xml:space="preserve"><value>Aucun tenant connect&#233;.</value></data>
<data name="err.no_tenant_connected" xml:space="preserve"><value>Aucun tenant s&#233;lectionn&#233;. Connectez-vous &#224; un tenant d'abord.</value></data>
<data name="err.no_profile_selected" xml:space="preserve"><value>Aucun profil de tenant s&#233;lectionn&#233;. Connectez-vous d'abord.</value></data>
<data name="err.no_sites_selected" xml:space="preserve"><value>S&#233;lectionnez au moins un site dans la barre d'outils.</value></data>
<data name="err.no_users_selected" xml:space="preserve"><value>Ajoutez au moins un utilisateur &#224; auditer.</value></data>
<data name="err.no_valid_rows" xml:space="preserve"><value>Aucune ligne valide &#224; traiter. Importez un CSV d'abord.</value></data>
<data name="err.template_name_required" xml:space="preserve"><value>Le nom du mod&#232;le est requis.</value></data>
<data name="err.site_title_required" xml:space="preserve"><value>Le titre du nouveau site est requis.</value></data>
<data name="err.site_alias_required" xml:space="preserve"><value>L'alias du nouveau site est requis.</value></data>
<data name="err.transfer_source_required" xml:space="preserve"><value>Le site source et la biblioth&#232;que doivent &#234;tre s&#233;lectionn&#233;s.</value></data>
<data name="err.transfer_dest_required" xml:space="preserve"><value>Le site de destination et la biblioth&#232;que doivent &#234;tre s&#233;lectionn&#233;s.</value></data>
<data name="err.library_title_required" xml:space="preserve"><value>Le titre de la biblioth&#232;que est requis.</value></data>
<!-- Templates status -->
<data name="templates.status.capturing" xml:space="preserve"><value>Capture du mod&#232;le...</value></data>
<data name="templates.status.success" xml:space="preserve"><value>Mod&#232;le captur&#233; avec succ&#232;s.</value></data>
<data name="templates.status.capture_failed" xml:space="preserve"><value>&#201;chec de la capture&#160;: {0}</value></data>
<data name="templates.status.applying" xml:space="preserve"><value>Application du mod&#232;le...</value></data>
<data name="templates.status.applied" xml:space="preserve"><value>Mod&#232;le appliqu&#233;. Site cr&#233;&#233; &#224;&#160;: {0}</value></data>
<data name="templates.status.apply_failed" xml:space="preserve"><value>&#201;chec de l'application&#160;: {0}</value></data>
<!-- UI text -->
<data name="audit.searching" xml:space="preserve"><value>Recherche en cours...</value></data>
<!-- Report text -->
<data name="report.text.users_parens" xml:space="preserve"><value>utilisateur(s)</value></data>
<data name="report.text.files_unit" xml:space="preserve"><value>fichiers</value></data>
<data name="report.text.sites_unit" xml:space="preserve"><value>sites</value></data>
</root>