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));
+ }
+}