--- phase: 03 plan: 06 title: Localization — Phase 3 EN and FR Keys status: pending wave: 2 depends_on: - 03-01 files_modified: - SharepointToolbox/Localization/Strings.resx - SharepointToolbox/Localization/Strings.fr.resx - SharepointToolbox/Localization/Strings.Designer.cs autonomous: true requirements: - STOR-01 - STOR-02 - STOR-04 - STOR-05 - SRCH-01 - SRCH-02 - SRCH-03 - SRCH-04 - DUPL-01 - DUPL-02 - DUPL-03 must_haves: truths: - "All Phase 3 EN keys exist in Strings.resx" - "All Phase 3 FR keys exist in Strings.fr.resx with non-empty French values" - "Strings.Designer.cs has one static property per new key (dot-to-underscore naming: chk.per.lib -> chk_per_lib)" - "dotnet build produces 0 errors after localization changes" - "No existing Phase 2 or Phase 1 keys are modified or removed" artifacts: - path: "SharepointToolbox/Localization/Strings.resx" provides: "English localization for Phase 3 tabs" - path: "SharepointToolbox/Localization/Strings.fr.resx" provides: "French localization for Phase 3 tabs" - path: "SharepointToolbox/Localization/Strings.Designer.cs" provides: "Strongly-typed accessors for new keys" key_links: - from: "Strings.Designer.cs" to: "Strings.resx" via: "ResourceManager.GetString" pattern: "ResourceManager\\.GetString" --- # Plan 03-06: Localization — Phase 3 EN and FR Keys ## Goal Add all EN and FR localization keys needed by the Storage, File Search, and Duplicates tabs. Views in plans 03-07 and 03-08 reference these keys via `TranslationSource.Instance["key"]` XAML bindings. Keys must exist before the Views compile. ## Context Strings.resx uses a manually maintained `Strings.Designer.cs` (no ResXFileCodeGenerator — confirmed in Phase 1 decisions). The naming convention converts dots to underscores: key `chk.per.lib` becomes accessor `Strings.chk_per_lib`. Both `.resx` files use `xml:space="preserve"` on each `` element. The following keys already exist and must NOT be duplicated: `tab.storage`, `tab.search`, `tab.duplicates`, `lbl.folder.depth`, `chk.max.depth`. > **Pre-existing keys — do not add:** The following keys are confirmed present in `Strings.resx` from Phase 2 and must be skipped when editing both `.resx` files and `Strings.Designer.cs`: > - `grp.scan.opts` (value: "Scan Options") — already exists > - `grp.export.fmt` (value: "Export Format") — already exists > - `btn.cancel` (value: "Cancel") — already exists > > Before appending, verify with: `grep -n "grp.scan.opts\|grp.export.fmt\|btn.cancel" SharepointToolbox/Localization/Strings.resx` > Do not add designer properties for these keys if they already exist in `Strings.Designer.cs`. ## Tasks ### Task 1: Add Phase 3 keys to Strings.resx, Strings.fr.resx, and Strings.Designer.cs **Files:** - `SharepointToolbox/Localization/Strings.resx` - `SharepointToolbox/Localization/Strings.fr.resx` - `SharepointToolbox/Localization/Strings.Designer.cs` **Action:** Modify — append new `` elements before `` in both .resx files; append new properties before the closing `}` in Strings.Designer.cs **Why:** Views in plans 03-07 and 03-08 bind to these keys. Missing keys produce empty strings at runtime. Add these entries immediately before the closing `` tag in `Strings.resx`: ```xml Per-Library Breakdown Include Subsites Note: deeper folder scans on large sites may take several minutes. Generate Metrics Open Report Library Site Files Total Size Version Size Last Modified Share of Total CSV HTML Search Filters Extension(s): docx pdf xlsx Name / Regex: Ex: report.* or \.bak$ Created after: Created before: Modified after: Modified before: Created by: First Last or email Modified by: First Last or email Library: Optional relative path e.g. Shared Documents Max results: Site URL: https://tenant.sharepoint.com/sites/MySite Run Search Open Results File Name Extension Created Modified Created By Modified By Size Path CSV HTML Duplicate Type Duplicate files Duplicate folders Comparison Criteria Name is always the primary criterion. Check additional criteria: Same size Same creation date Same modification date Same subfolder count Same file count Include subsites All (leave empty) Run Scan Open Results ``` Add these entries immediately before the closing `` tag in `Strings.fr.resx`: ```xml Détail par bibliothèque Inclure les sous-sites Remarque : les analyses de dossiers profondes sur les grands sites peuvent prendre plusieurs minutes. Générer les métriques Ouvrir le rapport Bibliothèque Site Fichiers Taille totale Taille des versions Dernière modification Part du total CSV HTML Filtres de recherche Extension(s) : docx pdf xlsx Nom / Regex : Ex : rapport.* ou \.bak$ Créé après : Créé avant : Modifié après : Modifié avant : Créé par : Prénom Nom ou courriel Modifié par : Prénom Nom ou courriel Bibliothèque : Chemin relatif optionnel, ex. Documents partagés Max résultats : URL du site : https://tenant.sharepoint.com/sites/MonSite Lancer la recherche Ouvrir les résultats Nom du fichier Extension Créé Modifié Créé par Modifié par Taille Chemin CSV HTML Type de doublon Fichiers en doublon Dossiers en doublon Critères de comparaison Le nom est toujours le critère principal. Cochez des critères supplémentaires : Même taille Même date de création Même date de modification Même nombre de sous-dossiers Même nombre de fichiers Inclure les sous-sites Tous (laisser vide) Lancer l'analyse Ouvrir les résultats ``` Add these properties inside the `Strings` class in `Strings.Designer.cs` (before the closing `}`): ```csharp // Phase 3: Storage Tab public static string chk_per_lib => ResourceManager.GetString("chk.per.lib", resourceCulture) ?? string.Empty; public static string chk_subsites => ResourceManager.GetString("chk.subsites", resourceCulture) ?? string.Empty; public static string stor_note => ResourceManager.GetString("stor.note", resourceCulture) ?? string.Empty; public static string btn_gen_storage => ResourceManager.GetString("btn.gen.storage", resourceCulture) ?? string.Empty; public static string btn_open_storage => ResourceManager.GetString("btn.open.storage", resourceCulture) ?? string.Empty; public static string stor_col_library => ResourceManager.GetString("stor.col.library", resourceCulture) ?? string.Empty; public static string stor_col_site => ResourceManager.GetString("stor.col.site", resourceCulture) ?? string.Empty; public static string stor_col_files => ResourceManager.GetString("stor.col.files", resourceCulture) ?? string.Empty; public static string stor_col_size => ResourceManager.GetString("stor.col.size", resourceCulture) ?? string.Empty; public static string stor_col_versions => ResourceManager.GetString("stor.col.versions", resourceCulture) ?? string.Empty; public static string stor_col_lastmod => ResourceManager.GetString("stor.col.lastmod", resourceCulture) ?? string.Empty; public static string stor_col_share => ResourceManager.GetString("stor.col.share", resourceCulture) ?? string.Empty; public static string stor_rad_csv => ResourceManager.GetString("stor.rad.csv", resourceCulture) ?? string.Empty; public static string stor_rad_html => ResourceManager.GetString("stor.rad.html", resourceCulture) ?? string.Empty; // Phase 3: File Search Tab public static string grp_search_filters => ResourceManager.GetString("grp.search.filters", resourceCulture) ?? string.Empty; public static string lbl_extensions => ResourceManager.GetString("lbl.extensions", resourceCulture) ?? string.Empty; public static string ph_extensions => ResourceManager.GetString("ph.extensions", resourceCulture) ?? string.Empty; public static string lbl_regex => ResourceManager.GetString("lbl.regex", resourceCulture) ?? string.Empty; public static string ph_regex => ResourceManager.GetString("ph.regex", resourceCulture) ?? string.Empty; public static string chk_created_after => ResourceManager.GetString("chk.created.after", resourceCulture) ?? string.Empty; public static string chk_created_before => ResourceManager.GetString("chk.created.before", resourceCulture) ?? string.Empty; public static string chk_modified_after => ResourceManager.GetString("chk.modified.after", resourceCulture) ?? string.Empty; public static string chk_modified_before => ResourceManager.GetString("chk.modified.before", resourceCulture) ?? string.Empty; public static string lbl_created_by => ResourceManager.GetString("lbl.created.by", resourceCulture) ?? string.Empty; public static string ph_created_by => ResourceManager.GetString("ph.created.by", resourceCulture) ?? string.Empty; public static string lbl_modified_by => ResourceManager.GetString("lbl.modified.by", resourceCulture) ?? string.Empty; public static string ph_modified_by => ResourceManager.GetString("ph.modified.by", resourceCulture) ?? string.Empty; public static string lbl_library => ResourceManager.GetString("lbl.library", resourceCulture) ?? string.Empty; public static string ph_library => ResourceManager.GetString("ph.library", resourceCulture) ?? string.Empty; public static string lbl_max_results => ResourceManager.GetString("lbl.max.results", resourceCulture) ?? string.Empty; public static string lbl_site_url => ResourceManager.GetString("lbl.site.url", resourceCulture) ?? string.Empty; public static string ph_site_url => ResourceManager.GetString("ph.site.url", resourceCulture) ?? string.Empty; public static string btn_run_search => ResourceManager.GetString("btn.run.search", resourceCulture) ?? string.Empty; public static string btn_open_search => ResourceManager.GetString("btn.open.search", resourceCulture) ?? string.Empty; public static string srch_col_name => ResourceManager.GetString("srch.col.name", resourceCulture) ?? string.Empty; public static string srch_col_ext => ResourceManager.GetString("srch.col.ext", resourceCulture) ?? string.Empty; public static string srch_col_created => ResourceManager.GetString("srch.col.created", resourceCulture) ?? string.Empty; public static string srch_col_modified => ResourceManager.GetString("srch.col.modified", resourceCulture) ?? string.Empty; public static string srch_col_author => ResourceManager.GetString("srch.col.author", resourceCulture) ?? string.Empty; public static string srch_col_modby => ResourceManager.GetString("srch.col.modby", resourceCulture) ?? string.Empty; public static string srch_col_size => ResourceManager.GetString("srch.col.size", resourceCulture) ?? string.Empty; public static string srch_col_path => ResourceManager.GetString("srch.col.path", resourceCulture) ?? string.Empty; public static string srch_rad_csv => ResourceManager.GetString("srch.rad.csv", resourceCulture) ?? string.Empty; public static string srch_rad_html => ResourceManager.GetString("srch.rad.html", resourceCulture) ?? string.Empty; // Phase 3: Duplicates Tab public static string grp_dup_type => ResourceManager.GetString("grp.dup.type", resourceCulture) ?? string.Empty; public static string rad_dup_files => ResourceManager.GetString("rad.dup.files", resourceCulture) ?? string.Empty; public static string rad_dup_folders => ResourceManager.GetString("rad.dup.folders", resourceCulture) ?? string.Empty; public static string grp_dup_criteria => ResourceManager.GetString("grp.dup.criteria", resourceCulture) ?? string.Empty; public static string lbl_dup_note => ResourceManager.GetString("lbl.dup.note", resourceCulture) ?? string.Empty; public static string chk_dup_size => ResourceManager.GetString("chk.dup.size", resourceCulture) ?? string.Empty; public static string chk_dup_created => ResourceManager.GetString("chk.dup.created", resourceCulture) ?? string.Empty; public static string chk_dup_modified => ResourceManager.GetString("chk.dup.modified", resourceCulture) ?? string.Empty; public static string chk_dup_subfolders => ResourceManager.GetString("chk.dup.subfolders", resourceCulture) ?? string.Empty; public static string chk_dup_filecount => ResourceManager.GetString("chk.dup.filecount", resourceCulture) ?? string.Empty; public static string chk_include_subsites => ResourceManager.GetString("chk.include.subsites", resourceCulture) ?? string.Empty; 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; ``` **Verification:** ```bash dotnet build C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.slnx ``` Expected: 0 errors ## Verification ```bash dotnet build C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.slnx dotnet test C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.Tests/SharepointToolbox.Tests.csproj -x 2>&1 | tail -5 ``` Expected: 0 build errors; all previously passing tests still pass; no new failures ## Commit Message feat(03-06): add Phase 3 EN/FR localization keys for Storage, Search, and Duplicates tabs ## Output After completion, create `.planning/phases/03-storage/03-06-SUMMARY.md`