diff --git a/SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs b/SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs new file mode 100644 index 0000000..c3b337d --- /dev/null +++ b/SharepointToolbox.Tests/Localization/LocaleCompletenessTests.cs @@ -0,0 +1,84 @@ +using System.Collections; +using System.Globalization; +using System.Resources; +using SharepointToolbox.Localization; + +namespace SharepointToolbox.Tests.Localization; + +[Trait("Category", "Unit")] +public class LocaleCompletenessTests +{ + /// + /// Verifies every EN key in Strings.resx has a non-empty, non-bracketed FR translation. + /// + [Fact] + public void AllEnKeys_HaveNonEmptyFrTranslation() + { + var rm = new ResourceManager("SharepointToolbox.Localization.Strings", typeof(Strings).Assembly); + var enResourceSet = rm.GetResourceSet(CultureInfo.InvariantCulture, true, true); + Assert.NotNull(enResourceSet); + + var frCulture = new CultureInfo("fr"); + var failures = new List(); + + foreach (DictionaryEntry entry in enResourceSet) + { + var key = entry.Key?.ToString(); + if (string.IsNullOrEmpty(key)) continue; + + var frValue = rm.GetString(key, frCulture); + if (string.IsNullOrWhiteSpace(frValue)) + { + failures.Add($" [{key}]: null or whitespace"); + } + else if (frValue.StartsWith("[", StringComparison.Ordinal)) + { + failures.Add($" [{key}]: bracketed fallback — '{frValue}'"); + } + } + + Assert.True(failures.Count == 0, + $"The following {failures.Count} key(s) are missing or invalid in Strings.fr.resx:\n" + + string.Join("\n", failures)); + } + + /// + /// Spot-checks 5 keys that must contain diacritics after Plan 02 fixes. + /// This test FAILS until Plan 02 corrects the FR translations. + /// + [Fact] + public void FrStrings_ContainExpectedDiacritics() + { + var rm = new ResourceManager("SharepointToolbox.Localization.Strings", typeof(Strings).Assembly); + var frCulture = new CultureInfo("fr"); + var failures = new List(); + + void CheckDiacritic(string key, char expectedChar) + { + var value = rm.GetString(key, frCulture); + if (value == null || !value.Contains(expectedChar)) + { + failures.Add($" [{key}] = '{value ?? "(null)"}' — expected to contain '{expectedChar}'"); + } + } + + // Déplacer must contain é (currently "Deplacer") + CheckDiacritic("transfer.mode.move", 'é'); + + // Créer les sites must contain é (currently "Creer les sites") + CheckDiacritic("bulksites.execute", 'é'); + + // Modèles enregistrés must contain è (currently "Modeles enregistres") + CheckDiacritic("templates.list", 'è'); + + // Terminé : {0} réussis, {1} échoués must contain é (currently "Termine : ...") + CheckDiacritic("bulk.result.success", 'é'); + + // Bibliothèque cible must contain è (currently "Bibliotheque cible") + CheckDiacritic("folderstruct.library", 'è'); + + Assert.True(failures.Count == 0, + $"The following {failures.Count} key(s) are missing expected diacritics in Strings.fr.resx " + + $"(fix in Plan 02):\n" + string.Join("\n", failures)); + } +}