feat(04-07): add Phase 4 localization, shared dialogs, and example CSV resources

- Add 80+ Phase 4 EN/FR localization keys to Strings.resx and Strings.fr.resx (tabs, transfer, bulkmembers, bulksites, folderstruct, templates, bulk-shared, folderbrowser)
- Add ResourceManager property accessors for all new keys to Strings.Designer.cs
- Create ConfirmBulkOperationDialog (XAML + code-behind) with Proceed/Cancel buttons
- Create FolderBrowserDialog (XAML + code-behind) with lazy-loading TreeView of SharePoint libraries/folders
- Bundle bulk_add_members.csv, bulk_create_sites.csv, folder_structure.csv as EmbeddedResource in csproj
This commit is contained in:
Dev
2026-04-03 10:13:39 +02:00
parent fdb1108e76
commit 1a2cc13224
11 changed files with 507 additions and 0 deletions

View File

@@ -136,5 +136,96 @@ namespace SharepointToolbox.Localization {
public static string ph_dup_lib => ResourceManager.GetString("ph.dup.lib", resourceCulture) ?? string.Empty;
public static string btn_run_scan => ResourceManager.GetString("btn.run.scan", resourceCulture) ?? string.Empty;
public static string btn_open_results => ResourceManager.GetString("btn.open.results", resourceCulture) ?? string.Empty;
// Phase 4: Tab headers
public static string tab_transfer => ResourceManager.GetString("tab.transfer", resourceCulture) ?? string.Empty;
public static string tab_bulkMembers => ResourceManager.GetString("tab.bulkMembers", resourceCulture) ?? string.Empty;
public static string tab_bulkSites => ResourceManager.GetString("tab.bulkSites", resourceCulture) ?? string.Empty;
public static string tab_folderStructure => ResourceManager.GetString("tab.folderStructure", resourceCulture) ?? string.Empty;
// Phase 4: Transfer tab
public static string transfer_sourcesite => ResourceManager.GetString("transfer.sourcesite", resourceCulture) ?? string.Empty;
public static string transfer_destsite => ResourceManager.GetString("transfer.destsite", resourceCulture) ?? string.Empty;
public static string transfer_sourcelibrary => ResourceManager.GetString("transfer.sourcelibrary", resourceCulture) ?? string.Empty;
public static string transfer_destlibrary => ResourceManager.GetString("transfer.destlibrary", resourceCulture) ?? string.Empty;
public static string transfer_sourcefolder => ResourceManager.GetString("transfer.sourcefolder", resourceCulture) ?? string.Empty;
public static string transfer_destfolder => ResourceManager.GetString("transfer.destfolder", resourceCulture) ?? string.Empty;
public static string transfer_mode => ResourceManager.GetString("transfer.mode", resourceCulture) ?? string.Empty;
public static string transfer_mode_copy => ResourceManager.GetString("transfer.mode.copy", resourceCulture) ?? string.Empty;
public static string transfer_mode_move => ResourceManager.GetString("transfer.mode.move", resourceCulture) ?? string.Empty;
public static string transfer_conflict => ResourceManager.GetString("transfer.conflict", resourceCulture) ?? string.Empty;
public static string transfer_conflict_skip => ResourceManager.GetString("transfer.conflict.skip", resourceCulture) ?? string.Empty;
public static string transfer_conflict_overwrite => ResourceManager.GetString("transfer.conflict.overwrite", resourceCulture) ?? string.Empty;
public static string transfer_conflict_rename => ResourceManager.GetString("transfer.conflict.rename", resourceCulture) ?? string.Empty;
public static string transfer_browse => ResourceManager.GetString("transfer.browse", resourceCulture) ?? string.Empty;
public static string transfer_start => ResourceManager.GetString("transfer.start", resourceCulture) ?? string.Empty;
public static string transfer_nofiles => ResourceManager.GetString("transfer.nofiles", resourceCulture) ?? string.Empty;
// Phase 4: Bulk Members tab
public static string bulkmembers_import => ResourceManager.GetString("bulkmembers.import", resourceCulture) ?? string.Empty;
public static string bulkmembers_example => ResourceManager.GetString("bulkmembers.example", resourceCulture) ?? string.Empty;
public static string bulkmembers_execute => ResourceManager.GetString("bulkmembers.execute", resourceCulture) ?? string.Empty;
public static string bulkmembers_preview => ResourceManager.GetString("bulkmembers.preview", resourceCulture) ?? string.Empty;
public static string bulkmembers_groupname => ResourceManager.GetString("bulkmembers.groupname", resourceCulture) ?? string.Empty;
public static string bulkmembers_groupurl => ResourceManager.GetString("bulkmembers.groupurl", resourceCulture) ?? string.Empty;
public static string bulkmembers_email => ResourceManager.GetString("bulkmembers.email", resourceCulture) ?? string.Empty;
public static string bulkmembers_role => ResourceManager.GetString("bulkmembers.role", resourceCulture) ?? string.Empty;
// Phase 4: Bulk Sites tab
public static string bulksites_import => ResourceManager.GetString("bulksites.import", resourceCulture) ?? string.Empty;
public static string bulksites_example => ResourceManager.GetString("bulksites.example", resourceCulture) ?? string.Empty;
public static string bulksites_execute => ResourceManager.GetString("bulksites.execute", resourceCulture) ?? string.Empty;
public static string bulksites_preview => ResourceManager.GetString("bulksites.preview", resourceCulture) ?? string.Empty;
public static string bulksites_name => ResourceManager.GetString("bulksites.name", resourceCulture) ?? string.Empty;
public static string bulksites_alias => ResourceManager.GetString("bulksites.alias", resourceCulture) ?? string.Empty;
public static string bulksites_type => ResourceManager.GetString("bulksites.type", resourceCulture) ?? string.Empty;
public static string bulksites_owners => ResourceManager.GetString("bulksites.owners", resourceCulture) ?? string.Empty;
public static string bulksites_members => ResourceManager.GetString("bulksites.members", resourceCulture) ?? string.Empty;
// Phase 4: Folder Structure tab
public static string folderstruct_import => ResourceManager.GetString("folderstruct.import", resourceCulture) ?? string.Empty;
public static string folderstruct_example => ResourceManager.GetString("folderstruct.example", resourceCulture) ?? string.Empty;
public static string folderstruct_execute => ResourceManager.GetString("folderstruct.execute", resourceCulture) ?? string.Empty;
public static string folderstruct_preview => ResourceManager.GetString("folderstruct.preview", resourceCulture) ?? string.Empty;
public static string folderstruct_library => ResourceManager.GetString("folderstruct.library", resourceCulture) ?? string.Empty;
public static string folderstruct_siteurl => ResourceManager.GetString("folderstruct.siteurl", resourceCulture) ?? string.Empty;
// Phase 4: Templates tab
public static string templates_list => ResourceManager.GetString("templates.list", resourceCulture) ?? string.Empty;
public static string templates_capture => ResourceManager.GetString("templates.capture", resourceCulture) ?? string.Empty;
public static string templates_apply => ResourceManager.GetString("templates.apply", resourceCulture) ?? string.Empty;
public static string templates_rename => ResourceManager.GetString("templates.rename", resourceCulture) ?? string.Empty;
public static string templates_delete => ResourceManager.GetString("templates.delete", resourceCulture) ?? string.Empty;
public static string templates_siteurl => ResourceManager.GetString("templates.siteurl", resourceCulture) ?? string.Empty;
public static string templates_name => ResourceManager.GetString("templates.name", resourceCulture) ?? string.Empty;
public static string templates_newtitle => ResourceManager.GetString("templates.newtitle", resourceCulture) ?? string.Empty;
public static string templates_newalias => ResourceManager.GetString("templates.newalias", resourceCulture) ?? string.Empty;
public static string templates_options => ResourceManager.GetString("templates.options", resourceCulture) ?? string.Empty;
public static string templates_opt_libraries => ResourceManager.GetString("templates.opt.libraries", resourceCulture) ?? string.Empty;
public static string templates_opt_folders => ResourceManager.GetString("templates.opt.folders", resourceCulture) ?? string.Empty;
public static string templates_opt_permissions => ResourceManager.GetString("templates.opt.permissions", resourceCulture) ?? string.Empty;
public static string templates_opt_logo => ResourceManager.GetString("templates.opt.logo", resourceCulture) ?? string.Empty;
public static string templates_opt_settings => ResourceManager.GetString("templates.opt.settings", resourceCulture) ?? string.Empty;
public static string templates_empty => ResourceManager.GetString("templates.empty", resourceCulture) ?? string.Empty;
// Phase 4: Shared bulk operation strings
public static string bulk_confirm_title => ResourceManager.GetString("bulk.confirm.title", resourceCulture) ?? string.Empty;
public static string bulk_confirm_proceed => ResourceManager.GetString("bulk.confirm.proceed", resourceCulture) ?? string.Empty;
public static string bulk_confirm_cancel => ResourceManager.GetString("bulk.confirm.cancel", resourceCulture) ?? string.Empty;
public static string bulk_confirm_message => ResourceManager.GetString("bulk.confirm.message", resourceCulture) ?? string.Empty;
public static string bulk_result_success => ResourceManager.GetString("bulk.result.success", resourceCulture) ?? string.Empty;
public static string bulk_result_allfailed => ResourceManager.GetString("bulk.result.allfailed", resourceCulture) ?? string.Empty;
public static string bulk_result_allsuccess => ResourceManager.GetString("bulk.result.allsuccess", resourceCulture) ?? string.Empty;
public static string bulk_exportfailed => ResourceManager.GetString("bulk.exportfailed", resourceCulture) ?? string.Empty;
public static string bulk_retryfailed => ResourceManager.GetString("bulk.retryfailed", resourceCulture) ?? string.Empty;
public static string bulk_validation_invalid => ResourceManager.GetString("bulk.validation.invalid", resourceCulture) ?? string.Empty;
public static string bulk_csvimport_title => ResourceManager.GetString("bulk.csvimport.title", resourceCulture) ?? string.Empty;
public static string bulk_csvimport_filter => ResourceManager.GetString("bulk.csvimport.filter", resourceCulture) ?? string.Empty;
// Phase 4: Folder browser dialog
public static string folderbrowser_title => ResourceManager.GetString("folderbrowser.title", resourceCulture) ?? string.Empty;
public static string folderbrowser_loading => ResourceManager.GetString("folderbrowser.loading", resourceCulture) ?? string.Empty;
public static string folderbrowser_select => ResourceManager.GetString("folderbrowser.select", resourceCulture) ?? string.Empty;
public static string folderbrowser_cancel => ResourceManager.GetString("folderbrowser.cancel", resourceCulture) ?? string.Empty;
}
}

View File

@@ -221,4 +221,87 @@
<data name="ph.dup.lib" xml:space="preserve"><value>Tous (laisser vide)</value></data>
<data name="btn.run.scan" xml:space="preserve"><value>Lancer l'analyse</value></data>
<data name="btn.open.results" xml:space="preserve"><value>Ouvrir les résultats</value></data>
<!-- Phase 4: Tab headers -->
<data name="tab.transfer" xml:space="preserve"><value>Transfert</value></data>
<data name="tab.bulkMembers" xml:space="preserve"><value>Ajout en masse</value></data>
<data name="tab.bulkSites" xml:space="preserve"><value>Sites en masse</value></data>
<data name="tab.folderStructure" xml:space="preserve"><value>Structure de dossiers</value></data>
<!-- Phase 4: Transfer tab -->
<data name="transfer.sourcesite" xml:space="preserve"><value>Site source</value></data>
<data name="transfer.destsite" xml:space="preserve"><value>Site destination</value></data>
<data name="transfer.sourcelibrary" xml:space="preserve"><value>Bibliotheque source</value></data>
<data name="transfer.destlibrary" xml:space="preserve"><value>Bibliotheque destination</value></data>
<data name="transfer.sourcefolder" xml:space="preserve"><value>Dossier source</value></data>
<data name="transfer.destfolder" xml:space="preserve"><value>Dossier destination</value></data>
<data name="transfer.mode" xml:space="preserve"><value>Mode de transfert</value></data>
<data name="transfer.mode.copy" xml:space="preserve"><value>Copier</value></data>
<data name="transfer.mode.move" xml:space="preserve"><value>Deplacer</value></data>
<data name="transfer.conflict" xml:space="preserve"><value>Politique de conflit</value></data>
<data name="transfer.conflict.skip" xml:space="preserve"><value>Ignorer</value></data>
<data name="transfer.conflict.overwrite" xml:space="preserve"><value>Ecraser</value></data>
<data name="transfer.conflict.rename" xml:space="preserve"><value>Renommer (ajouter suffixe)</value></data>
<data name="transfer.browse" xml:space="preserve"><value>Parcourir...</value></data>
<data name="transfer.start" xml:space="preserve"><value>Demarrer le transfert</value></data>
<data name="transfer.nofiles" xml:space="preserve"><value>Aucun fichier a transferer.</value></data>
<!-- Phase 4: Bulk Members tab -->
<data name="bulkmembers.import" xml:space="preserve"><value>Importer CSV</value></data>
<data name="bulkmembers.example" xml:space="preserve"><value>Charger l'exemple</value></data>
<data name="bulkmembers.execute" xml:space="preserve"><value>Ajouter les membres</value></data>
<data name="bulkmembers.preview" xml:space="preserve"><value>Apercu ({0} lignes, {1} valides, {2} invalides)</value></data>
<data name="bulkmembers.groupname" xml:space="preserve"><value>Nom du groupe</value></data>
<data name="bulkmembers.groupurl" xml:space="preserve"><value>URL du groupe</value></data>
<data name="bulkmembers.email" xml:space="preserve"><value>Courriel</value></data>
<data name="bulkmembers.role" xml:space="preserve"><value>Role</value></data>
<!-- Phase 4: Bulk Sites tab -->
<data name="bulksites.import" xml:space="preserve"><value>Importer CSV</value></data>
<data name="bulksites.example" xml:space="preserve"><value>Charger l'exemple</value></data>
<data name="bulksites.execute" xml:space="preserve"><value>Creer les sites</value></data>
<data name="bulksites.preview" xml:space="preserve"><value>Apercu ({0} lignes, {1} valides, {2} invalides)</value></data>
<data name="bulksites.name" xml:space="preserve"><value>Nom</value></data>
<data name="bulksites.alias" xml:space="preserve"><value>Alias</value></data>
<data name="bulksites.type" xml:space="preserve"><value>Type</value></data>
<data name="bulksites.owners" xml:space="preserve"><value>Proprietaires</value></data>
<data name="bulksites.members" xml:space="preserve"><value>Membres</value></data>
<!-- Phase 4: Folder Structure tab -->
<data name="folderstruct.import" xml:space="preserve"><value>Importer CSV</value></data>
<data name="folderstruct.example" xml:space="preserve"><value>Charger l'exemple</value></data>
<data name="folderstruct.execute" xml:space="preserve"><value>Creer les dossiers</value></data>
<data name="folderstruct.preview" xml:space="preserve"><value>Apercu ({0} dossiers a creer)</value></data>
<data name="folderstruct.library" xml:space="preserve"><value>Bibliotheque cible</value></data>
<data name="folderstruct.siteurl" xml:space="preserve"><value>URL du site</value></data>
<!-- Phase 4: Templates tab -->
<data name="templates.list" xml:space="preserve"><value>Modeles enregistres</value></data>
<data name="templates.capture" xml:space="preserve"><value>Capturer un modele</value></data>
<data name="templates.apply" xml:space="preserve"><value>Appliquer le modele</value></data>
<data name="templates.rename" xml:space="preserve"><value>Renommer</value></data>
<data name="templates.delete" xml:space="preserve"><value>Supprimer</value></data>
<data name="templates.siteurl" xml:space="preserve"><value>URL du site source</value></data>
<data name="templates.name" xml:space="preserve"><value>Nom du modele</value></data>
<data name="templates.newtitle" xml:space="preserve"><value>Titre du nouveau site</value></data>
<data name="templates.newalias" xml:space="preserve"><value>Alias du nouveau site</value></data>
<data name="templates.options" xml:space="preserve"><value>Options de capture</value></data>
<data name="templates.opt.libraries" xml:space="preserve"><value>Bibliotheques</value></data>
<data name="templates.opt.folders" xml:space="preserve"><value>Dossiers</value></data>
<data name="templates.opt.permissions" xml:space="preserve"><value>Groupes de permissions</value></data>
<data name="templates.opt.logo" xml:space="preserve"><value>Logo du site</value></data>
<data name="templates.opt.settings" xml:space="preserve"><value>Parametres du site</value></data>
<data name="templates.empty" xml:space="preserve"><value>Aucun modele enregistre.</value></data>
<!-- Phase 4: Shared bulk operation strings -->
<data name="bulk.confirm.title" xml:space="preserve"><value>Confirmer l'operation</value></data>
<data name="bulk.confirm.proceed" xml:space="preserve"><value>Continuer</value></data>
<data name="bulk.confirm.cancel" xml:space="preserve"><value>Annuler</value></data>
<data name="bulk.confirm.message" xml:space="preserve"><value>{0} — Continuer ?</value></data>
<data name="bulk.result.success" xml:space="preserve"><value>Termine : {0} reussis, {1} echoues</value></data>
<data name="bulk.result.allfailed" xml:space="preserve"><value>Les {0} elements ont echoue.</value></data>
<data name="bulk.result.allsuccess" xml:space="preserve"><value>Les {0} elements ont ete traites avec succes.</value></data>
<data name="bulk.exportfailed" xml:space="preserve"><value>Exporter les elements echoues</value></data>
<data name="bulk.retryfailed" xml:space="preserve"><value>Reessayer les echecs</value></data>
<data name="bulk.validation.invalid" xml:space="preserve"><value>{0} lignes contiennent des erreurs. Corrigez et reimportez.</value></data>
<data name="bulk.csvimport.title" xml:space="preserve"><value>Selectionner un fichier CSV</value></data>
<data name="bulk.csvimport.filter" xml:space="preserve"><value>Fichiers CSV (*.csv)|*.csv</value></data>
<!-- Phase 4: Folder browser dialog -->
<data name="folderbrowser.title" xml:space="preserve"><value>Selectionner un dossier</value></data>
<data name="folderbrowser.loading" xml:space="preserve"><value>Chargement de l'arborescence...</value></data>
<data name="folderbrowser.select" xml:space="preserve"><value>Selectionner</value></data>
<data name="folderbrowser.cancel" xml:space="preserve"><value>Annuler</value></data>
</root>

View File

@@ -221,4 +221,87 @@
<data name="ph.dup.lib" xml:space="preserve"><value>All (leave empty)</value></data>
<data name="btn.run.scan" xml:space="preserve"><value>Run Scan</value></data>
<data name="btn.open.results" xml:space="preserve"><value>Open Results</value></data>
<!-- Phase 4: Tab headers -->
<data name="tab.transfer" xml:space="preserve"><value>Transfer</value></data>
<data name="tab.bulkMembers" xml:space="preserve"><value>Bulk Members</value></data>
<data name="tab.bulkSites" xml:space="preserve"><value>Bulk Sites</value></data>
<data name="tab.folderStructure" xml:space="preserve"><value>Folder Structure</value></data>
<!-- Phase 4: Transfer tab -->
<data name="transfer.sourcesite" xml:space="preserve"><value>Source Site</value></data>
<data name="transfer.destsite" xml:space="preserve"><value>Destination Site</value></data>
<data name="transfer.sourcelibrary" xml:space="preserve"><value>Source Library</value></data>
<data name="transfer.destlibrary" xml:space="preserve"><value>Destination Library</value></data>
<data name="transfer.sourcefolder" xml:space="preserve"><value>Source Folder</value></data>
<data name="transfer.destfolder" xml:space="preserve"><value>Destination Folder</value></data>
<data name="transfer.mode" xml:space="preserve"><value>Transfer Mode</value></data>
<data name="transfer.mode.copy" xml:space="preserve"><value>Copy</value></data>
<data name="transfer.mode.move" xml:space="preserve"><value>Move</value></data>
<data name="transfer.conflict" xml:space="preserve"><value>Conflict Policy</value></data>
<data name="transfer.conflict.skip" xml:space="preserve"><value>Skip</value></data>
<data name="transfer.conflict.overwrite" xml:space="preserve"><value>Overwrite</value></data>
<data name="transfer.conflict.rename" xml:space="preserve"><value>Rename (append suffix)</value></data>
<data name="transfer.browse" xml:space="preserve"><value>Browse...</value></data>
<data name="transfer.start" xml:space="preserve"><value>Start Transfer</value></data>
<data name="transfer.nofiles" xml:space="preserve"><value>No files found to transfer.</value></data>
<!-- Phase 4: Bulk Members tab -->
<data name="bulkmembers.import" xml:space="preserve"><value>Import CSV</value></data>
<data name="bulkmembers.example" xml:space="preserve"><value>Load Example</value></data>
<data name="bulkmembers.execute" xml:space="preserve"><value>Add Members</value></data>
<data name="bulkmembers.preview" xml:space="preserve"><value>Preview ({0} rows, {1} valid, {2} invalid)</value></data>
<data name="bulkmembers.groupname" xml:space="preserve"><value>Group Name</value></data>
<data name="bulkmembers.groupurl" xml:space="preserve"><value>Group URL</value></data>
<data name="bulkmembers.email" xml:space="preserve"><value>Email</value></data>
<data name="bulkmembers.role" xml:space="preserve"><value>Role</value></data>
<!-- Phase 4: Bulk Sites tab -->
<data name="bulksites.import" xml:space="preserve"><value>Import CSV</value></data>
<data name="bulksites.example" xml:space="preserve"><value>Load Example</value></data>
<data name="bulksites.execute" xml:space="preserve"><value>Create Sites</value></data>
<data name="bulksites.preview" xml:space="preserve"><value>Preview ({0} rows, {1} valid, {2} invalid)</value></data>
<data name="bulksites.name" xml:space="preserve"><value>Name</value></data>
<data name="bulksites.alias" xml:space="preserve"><value>Alias</value></data>
<data name="bulksites.type" xml:space="preserve"><value>Type</value></data>
<data name="bulksites.owners" xml:space="preserve"><value>Owners</value></data>
<data name="bulksites.members" xml:space="preserve"><value>Members</value></data>
<!-- Phase 4: Folder Structure tab -->
<data name="folderstruct.import" xml:space="preserve"><value>Import CSV</value></data>
<data name="folderstruct.example" xml:space="preserve"><value>Load Example</value></data>
<data name="folderstruct.execute" xml:space="preserve"><value>Create Folders</value></data>
<data name="folderstruct.preview" xml:space="preserve"><value>Preview ({0} folders to create)</value></data>
<data name="folderstruct.library" xml:space="preserve"><value>Target Library</value></data>
<data name="folderstruct.siteurl" xml:space="preserve"><value>Site URL</value></data>
<!-- Phase 4: Templates tab -->
<data name="templates.list" xml:space="preserve"><value>Saved Templates</value></data>
<data name="templates.capture" xml:space="preserve"><value>Capture Template</value></data>
<data name="templates.apply" xml:space="preserve"><value>Apply Template</value></data>
<data name="templates.rename" xml:space="preserve"><value>Rename</value></data>
<data name="templates.delete" xml:space="preserve"><value>Delete</value></data>
<data name="templates.siteurl" xml:space="preserve"><value>Source Site URL</value></data>
<data name="templates.name" xml:space="preserve"><value>Template Name</value></data>
<data name="templates.newtitle" xml:space="preserve"><value>New Site Title</value></data>
<data name="templates.newalias" xml:space="preserve"><value>New Site Alias</value></data>
<data name="templates.options" xml:space="preserve"><value>Capture Options</value></data>
<data name="templates.opt.libraries" xml:space="preserve"><value>Libraries</value></data>
<data name="templates.opt.folders" xml:space="preserve"><value>Folders</value></data>
<data name="templates.opt.permissions" xml:space="preserve"><value>Permission Groups</value></data>
<data name="templates.opt.logo" xml:space="preserve"><value>Site Logo</value></data>
<data name="templates.opt.settings" xml:space="preserve"><value>Site Settings</value></data>
<data name="templates.empty" xml:space="preserve"><value>No templates saved yet.</value></data>
<!-- Phase 4: Shared bulk operation strings -->
<data name="bulk.confirm.title" xml:space="preserve"><value>Confirm Operation</value></data>
<data name="bulk.confirm.proceed" xml:space="preserve"><value>Proceed</value></data>
<data name="bulk.confirm.cancel" xml:space="preserve"><value>Cancel</value></data>
<data name="bulk.confirm.message" xml:space="preserve"><value>{0} — Proceed?</value></data>
<data name="bulk.result.success" xml:space="preserve"><value>Completed: {0} succeeded, {1} failed</value></data>
<data name="bulk.result.allfailed" xml:space="preserve"><value>All {0} items failed.</value></data>
<data name="bulk.result.allsuccess" xml:space="preserve"><value>All {0} items completed successfully.</value></data>
<data name="bulk.exportfailed" xml:space="preserve"><value>Export Failed Items</value></data>
<data name="bulk.retryfailed" xml:space="preserve"><value>Retry Failed</value></data>
<data name="bulk.validation.invalid" xml:space="preserve"><value>{0} rows have validation errors. Fix and re-import.</value></data>
<data name="bulk.csvimport.title" xml:space="preserve"><value>Select CSV File</value></data>
<data name="bulk.csvimport.filter" xml:space="preserve"><value>CSV Files (*.csv)|*.csv</value></data>
<!-- Phase 4: Folder browser dialog -->
<data name="folderbrowser.title" xml:space="preserve"><value>Select Folder</value></data>
<data name="folderbrowser.loading" xml:space="preserve"><value>Loading folder tree...</value></data>
<data name="folderbrowser.select" xml:space="preserve"><value>Select</value></data>
<data name="folderbrowser.cancel" xml:space="preserve"><value>Cancel</value></data>
</root>