From 17c1bcdd352b3d43d8178a5ca543457d7f821e4f Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 5 Jun 2026 11:04:11 -0400 Subject: [PATCH 1/2] Add tests for language-tag matching rule 3 (exact generic beats specifics) PR #110 fixed the language-tag matching logic but left one rule untested: when an exact generic tag (zh) is available alongside specific variants (zh-CN, zh-TW), the exact match should be used without prompting. Adds TestMappingLanguageCodesToAvailable_ExactGenericMatchUsedWhenSpecificsAlsoExist to both LocalizationManagerTestsBase and XliffLocalizationManagerTests. Co-Authored-By: Claude Sonnet 4.6 --- .../LocalizationManagerTestsBase.cs | 58 ++++++++++++++++ .../XliffLocalizationManagerTests.cs | 66 +++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs b/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs index 5189f53..d6466e3 100644 --- a/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs +++ b/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs @@ -615,6 +615,29 @@ private void AddChineseOfTaiwanTranslation(string folderPath) chineseDoc.Save(Path.Combine(folderPath, LocalizationManager.GetTranslationFileNameForLanguage(AppId, "zh-TW"))); } + private void AddChineseBareTranslation(string folderPath) + { + var chineseDoc = CreateNewDocument(null, "en", "zh"); + // first unit + var tu = CreateTransUnit("theId", false, + CreateTransUnitVariant("en", "from English Translation"), + CreateTransUnitVariant("zh", "from Chinese (generic) Translation"), + "Test", TranslationStatus.Approved); + chineseDoc.AddTransUnit(tu); + // second unit + var tu2 = CreateTransUnit("notUsedId", false, + CreateTransUnitVariant("en", "no longer used English text"), + CreateTransUnitVariant("zh", "no longer used Chinese (generic) text"), + null, TranslationStatus.Approved); + chineseDoc.AddTransUnit(tu2); + // third unit + var tu3 = CreateTransUnit("blahId", false, + CreateTransUnitVariant("en", "blah"), + CreateTransUnitVariant("zh", "中文 blah")); + chineseDoc.AddTransUnit(tu3); + chineseDoc.Save(Path.Combine(folderPath, LocalizationManager.GetTranslationFileNameForLanguage(AppId, "zh"))); + } + protected void AddRandomTranslation(string langId, string folderPath) { var doc = CreateNewDocument(null, "en", langId); @@ -1006,5 +1029,40 @@ public void TestMappingLanguageCodesToAvailable_FindsSpecificGivenGeneric() Assert.That(languageIdUsed, Is.EqualTo("zh-CN")); } } + + /// + /// Rule 3: when an exact generic match (zh) is available alongside specific variants + /// (zh-CN, zh-TW), the exact match should be used with no prompt. + /// + [Test] + public void TestMappingLanguageCodesToAvailable_ExactGenericMatchUsedWhenSpecificsAlsoExist() + { + LocalizationManager.SetUILanguage("en"); + LocalizationManagerInternal.LoadedManagers.Clear(); + using (var folder = new TempFolder()) + { + var installedFolder = Path.Combine(folder.Path, "installed"); + AddEnglishTranslation(installedFolder, null); + AddChineseBareTranslation(installedFolder); + AddChineseOfChinaTranslation(installedFolder); + AddChineseOfTaiwanTranslation(installedFolder); + LocalizationManagerInternal.ChooseFallbackLanguage(); + var manager = LocalizationManager.Create("zh", AppId, AppName, AppVersion, installedFolder, + $"Temp/{Path.GetFileName(folder.Path)}/user", new string[] { }); + LocalizationManagerInternal.LoadedManagers[AppId] = (ILocalizationManagerInternal)manager; + + // The UI language should be set to the exact match "zh", not one of the specifics. + Assert.That(LocalizationManager.UILanguageId, Is.EqualTo("zh")); + + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh"), Is.True, "zh should find zh (exact)"); + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh-CN"), Is.True, "zh-CN should find zh-CN"); + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh-TW"), Is.True, "zh-TW should find zh-TW"); + + // The generic zh request should use the generic zh translation, not CN or TW. + var str = LocalizationManager.GetString("theId", ".", "", new[] { "zh" }, out var languageIdUsed); + Assert.That(str, Is.EqualTo("from Chinese (generic) Translation")); + Assert.That(languageIdUsed, Is.EqualTo("zh")); + } + } } } diff --git a/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs b/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs index 0ea8dcf..3265356 100644 --- a/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs +++ b/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs @@ -157,6 +157,29 @@ private void AddChineseOfTaiwanTranslation(string folderPath) chineseDoc.Save(Path.Combine(folderPath, LocalizationManager.GetTranslationFileNameForLanguage(AppId, "zh-TW"))); } + private void AddChineseBareTranslation(string folderPath) + { + var chineseDoc = CreateNewDocument(null, "en", "zh"); + // first unit + var tu = CreateTransUnit("theId", false, + CreateTransUnitVariant("en", "from English Translation"), + CreateTransUnitVariant("zh", "from Chinese (generic) Translation"), + "Test", TranslationStatus.Approved); + chineseDoc.AddTransUnit(tu); + // second unit + var tu2 = CreateTransUnit("notUsedId", false, + CreateTransUnitVariant("en", "no longer used English text"), + CreateTransUnitVariant("zh", "no longer used Chinese (generic) text"), + null, TranslationStatus.Approved); + chineseDoc.AddTransUnit(tu2); + // third unit + var tu3 = CreateTransUnit("blahId", false, + CreateTransUnitVariant("en", "blah"), + CreateTransUnitVariant("zh", "中文 blah")); + chineseDoc.AddTransUnit(tu3); + chineseDoc.Save(Path.Combine(folderPath, LocalizationManager.GetTranslationFileNameForLanguage(AppId, "zh"))); + } + [Test] public void TestMappingLanguageCodesToAvailable_AmbiguousOptions_PromptsUser([Values("zh-CN", "zh-TW")] string choice) { @@ -193,5 +216,48 @@ public void TestMappingLanguageCodesToAvailable_AmbiguousOptions_PromptsUser([Va Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "en"), Is.True, "en should find en"); } } + + /// + /// Rule 3: when an exact generic match (zh) is available alongside specific variants + /// (zh-CN, zh-TW), the exact match should be used with no prompt. + /// + [Test] + public void TestMappingLanguageCodesToAvailable_ExactGenericMatchUsedWhenSpecificsAlsoExist() + { + LocalizationManagerWinforms.SetUILanguage("en", true); + LocalizationManagerInternalWinforms.LoadedManagers.Clear(); + using (var folder = new L10NSharp.Tests.TempFolder()) + { + var installedFolder = Path.Combine(folder.Path, "installed"); + // ReSharper disable once AssignNullToNotNullAttribute + var userRelativeFolder = Path.Combine("Temp", Path.GetFileName(Path.GetDirectoryName(folder.Path)), + Path.GetFileName(folder.Path), "user"); + AddEnglishTranslation(installedFolder, null); + AddChineseBareTranslation(installedFolder); + AddChineseOfChinaTranslation(installedFolder); + AddChineseOfTaiwanTranslation(installedFolder); + var userPromptCount = 0; + LocalizationManagerInternalWinforms.ChooseFallbackLanguageWinforms = (langTag, icon) => + { + userPromptCount++; + return langTag; + }; + var manager = LocalizationManagerWinforms.Create("zh", AppId, AppName, AppVersion, installedFolder, + userRelativeFolder, null, new string[] { }); + // Exact match available — no prompt should have been shown. + Assert.That(userPromptCount, Is.EqualTo(0)); + Assert.That(LocalizationManager.UILanguageId, Is.EqualTo("zh")); + LocalizationManagerInternal.LoadedManagers[AppId] = (ILocalizationManagerInternal)manager; + + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh"), Is.True, "zh should find zh (exact)"); + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh-CN"), Is.True, "zh-CN should find zh-CN"); + Assert.That(LocalizationManager.GetIsStringAvailableForLangId("theId", "zh-TW"), Is.True, "zh-TW should find zh-TW"); + + // The generic zh request should use the generic zh translation, not CN or TW. + var str = LocalizationManager.GetString("theId", ".", "", new[] { "zh" }, out var languageIdUsed); + Assert.That(str, Is.EqualTo("from Chinese (generic) Translation")); + Assert.That(languageIdUsed, Is.EqualTo("zh")); + } + } } } From 5422adb8e2622d55dd73771d571127e2dc973a7d Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 5 Jun 2026 14:22:51 -0400 Subject: [PATCH 2/2] Remove out-of-context summaries --- src/L10NSharp.Tests/LocalizationManagerTestsBase.cs | 12 ++++-------- .../XliffLocalizationManagerTests.cs | 4 ---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs b/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs index d6466e3..aaab601 100644 --- a/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs +++ b/src/L10NSharp.Tests/LocalizationManagerTestsBase.cs @@ -216,19 +216,19 @@ public void CreateOrUpdateDefaultTranslationFileIfNecessary_Missing_IncludesStri Assert.AreEqual("My Own English String", ProxyLocalizationManager.MyOwnGetString("myOwn.English.String.Id", "My Own English String")); - + Assert.AreEqual("My Own English String (with comment)", ProxyLocalizationManager.MyOwnGetString("myOwn.English.String.Id.With.Comment", "My Own English String (with comment)", "This is used to test the case where MyOwnGetString is passed as an extra method to use for extraction.")); - + Assert.AreEqual("Click me", ProxyLocalizationManager.MyOwnGetString("myDlg.btnClickMe.Text", "Click me", "This is the text from the third version of MyOwnGetString.", "Click this thingy to do stuff.", "Ctrl-T", btnClickMe)); - + Assert.AreEqual("String to Localize", "String to Localize".Localize()); - + Assert.AreEqual("Another String to Localize", "Another String to Localize".Localize("With.Id.And.Comment", "This is used to test the case where Localize is passed as an extra method to use for extraction.")); } @@ -1030,10 +1030,6 @@ public void TestMappingLanguageCodesToAvailable_FindsSpecificGivenGeneric() } } - /// - /// Rule 3: when an exact generic match (zh) is available alongside specific variants - /// (zh-CN, zh-TW), the exact match should be used with no prompt. - /// [Test] public void TestMappingLanguageCodesToAvailable_ExactGenericMatchUsedWhenSpecificsAlsoExist() { diff --git a/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs b/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs index 3265356..2ba4cf9 100644 --- a/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs +++ b/src/L10NSharp.Windows.Forms.Tests/XliffLocalizationManagerTests.cs @@ -217,10 +217,6 @@ public void TestMappingLanguageCodesToAvailable_AmbiguousOptions_PromptsUser([Va } } - /// - /// Rule 3: when an exact generic match (zh) is available alongside specific variants - /// (zh-CN, zh-TW), the exact match should be used with no prompt. - /// [Test] public void TestMappingLanguageCodesToAvailable_ExactGenericMatchUsedWhenSpecificsAlsoExist() {