From af082f31eae25efd595d72da454769583bdf9265 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 5 Jun 2026 10:59:19 -0400 Subject: [PATCH 1/5] Strip duplicate and stale "Not found" notes in MergeXliffDocuments (#113) Running ExtractXliff multiple times accumulated one "Not found" note per run. Now the note is replaced (old one stripped before adding a new one) rather than appended. Additionally, "Not found" notes are no longer copied forward when a string is found in the current extraction. --- src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs b/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs index fcd284c..cabb0e0 100644 --- a/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs +++ b/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs @@ -608,6 +608,9 @@ internal static XLiffDocument MergeXliffDocuments(XLiffDocument xliffNew, XLiffD { foreach (var note in tuOld.Notes) { + // Skip "Not found" notes — the string IS found in this run. + if (note.Text.StartsWith("Not found in static scan") || note.Text.StartsWith("Not found when running")) + continue; bool haveAlready = false; foreach (var newNote in tu.Notes) { @@ -656,12 +659,16 @@ internal static XLiffDocument MergeXliffDocuments(XLiffDocument xliffNew, XLiffD ++missingDynamicStringCount; missingDynamicStringIds.Add(tu.Id); if (newDynamicCount > 0) // note only if attempt made to collect dynamic strings + { + tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found in static scan") || n.Text.StartsWith("Not found when running")); tu.AddNote("en", $"Not found when running compiled program (version {xliffNew.File.ProductVersion})"); + } } else { ++missingStringCount; missingStringIds.Add(tu.Id); + tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found in static scan") || n.Text.StartsWith("Not found when running")); tu.AddNote("en", $"Not found in static scan of compiled code (version {xliffNew.File.ProductVersion})"); } } From a932d8aac600f8e8ffce0542bd83a1efa449e1e2 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 5 Jun 2026 11:26:28 -0400 Subject: [PATCH 2/5] Update CHANGELOG for #113 fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 895773a..f3a2ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [L10NSharp.Windows.Forms] Restored project-local Resources support for `FallbackLanguagesDlgBase` button images (`Move`, `Move_up`, and `Move_down`). - [L10NSharp.Windows.Forms] Corrected resource manager base name to `L10NSharp.Windows.Forms.Properties.Resources`. - [L10NSharp.Windows.Forms.Tests] Corrected resource manager base name to `L10NSharp.Windows.Forms.Tests.Properties.Resources`. +- [L10NSharp] Fixed `ExtractXliff` accumulating duplicate "Not found in static scan" notes on successive runs; the note is now replaced rather than appended, and removed when the string is subsequently found. (#113) ### Removed From 44db3e6855f456ae5108f6d920b7c1ba69858d81 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 5 Jun 2026 11:43:15 -0400 Subject: [PATCH 3/5] Add regression tests: duplicate and stale Not-found notes (#113) Co-Authored-By: Claude Sonnet 4.6 --- .../XLiffLocalizationManagerTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs b/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs index 72a02f0..d90689a 100644 --- a/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs +++ b/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs @@ -239,6 +239,42 @@ public void MergeXliffDocuments_WorksAsExpected() }, true); } + [Test] + public void MergeXliffDocuments_RunTwice_DoesNotDuplicateNotFoundNotes() + { + var oldDoc = CreateTestDocument(); + var newDoc = CreateTestDocument(); + AdjustDocumentForTestingMerge(newDoc); + + var mergedDoc = XliffLocalizationManager.MergeXliffDocuments(newDoc, oldDoc, true); + var tuAfterFirstMerge = mergedDoc.GetTransUnitForId("That.test"); + Assert.IsNotNull(tuAfterFirstMerge); + var expectedNoteCount = tuAfterFirstMerge.Notes.Count; + + var mergedDoc2 = XliffLocalizationManager.MergeXliffDocuments(newDoc, mergedDoc, true); + var tuAfterSecondMerge = mergedDoc2.GetTransUnitForId("That.test"); + Assert.IsNotNull(tuAfterSecondMerge); + Assert.That(expectedNoteCount, Is.EqualTo(tuAfterSecondMerge.Notes.Count)); + } + + [Test] + public void MergeXliffDocuments_StringFoundAfterBeingMissing_RemovesNotFoundNote() + { + var oldDoc = CreateTestDocument(); + var newDoc = CreateTestDocument(); + AdjustDocumentForTestingMerge(newDoc); + + var mergedDoc = XliffLocalizationManager.MergeXliffDocuments(newDoc, oldDoc, true); + + // newDoc2 is NOT adjusted, so "That.test" IS present in it + var newDoc2 = CreateTestDocument(); + var mergedDoc2 = XliffLocalizationManager.MergeXliffDocuments(newDoc2, mergedDoc, true); + + var tu = mergedDoc2.GetTransUnitForId("That.test"); + Assert.IsNotNull(tu); + Assert.That(tu.Notes.Any(n => n.Text.StartsWith("Not found")), Is.False); + } + private void CheckMergedTransUnit(XLiffTransUnit tu, string sourceText, string[] notes, bool isDynamic) { Assert.IsNotNull(tu); From eb35b99c61dc8a0bcb2d788ed50c9790b907bf1f Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Mon, 8 Jun 2026 09:18:18 -0400 Subject: [PATCH 4/5] Generalize check --- src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs b/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs index cabb0e0..9fc5b55 100644 --- a/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs +++ b/src/L10NSharp/XLiffUtils/XliffLocalizationManager.cs @@ -539,7 +539,7 @@ public virtual void HandleUiLanguageChange() { UiLanguageChanged?.Invoke(this, EventArgs.Empty); } - + /// ------------------------------------------------------------------------------------ public override string ToString() { @@ -608,8 +608,8 @@ internal static XLiffDocument MergeXliffDocuments(XLiffDocument xliffNew, XLiffD { foreach (var note in tuOld.Notes) { - // Skip "Not found" notes — the string IS found in this run. - if (note.Text.StartsWith("Not found in static scan") || note.Text.StartsWith("Not found when running")) + // Skip "Not found[...]" notes — the string IS found in this run. + if (note.Text.StartsWith("Not found")) continue; bool haveAlready = false; foreach (var newNote in tu.Notes) @@ -658,9 +658,9 @@ internal static XLiffDocument MergeXliffDocuments(XLiffDocument xliffNew, XLiffD { ++missingDynamicStringCount; missingDynamicStringIds.Add(tu.Id); - if (newDynamicCount > 0) // note only if attempt made to collect dynamic strings + if (newDynamicCount > 0) // note only if attempt made to collect dynamic strings { - tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found in static scan") || n.Text.StartsWith("Not found when running")); + tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found")); tu.AddNote("en", $"Not found when running compiled program (version {xliffNew.File.ProductVersion})"); } } @@ -668,7 +668,7 @@ internal static XLiffDocument MergeXliffDocuments(XLiffDocument xliffNew, XLiffD { ++missingStringCount; missingStringIds.Add(tu.Id); - tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found in static scan") || n.Text.StartsWith("Not found when running")); + tu.Notes.RemoveAll(n => n.Text.StartsWith("Not found")); tu.AddNote("en", $"Not found in static scan of compiled code (version {xliffNew.File.ProductVersion})"); } } From 67d2826a5095c883459bd51a59ee347d3ebc7904 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Mon, 8 Jun 2026 09:36:56 -0400 Subject: [PATCH 5/5] Fix test assertion to catch [OLD NOTE]-prefixed Not-found notes On master the copy-old-notes loop prepends "[OLD NOTE] " to any note not already prefixed, so the "Not found" note from a prior merge survives as "[OLD NOTE] Not found...". StartsWith("Not found") missed it; Contains("Not found") catches it regardless of prefix. Co-Authored-By: Claude Sonnet 4.6 --- src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs b/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs index d90689a..c752881 100644 --- a/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs +++ b/src/L10NSharp.Tests/XLiffLocalizationManagerTests.cs @@ -272,7 +272,7 @@ public void MergeXliffDocuments_StringFoundAfterBeingMissing_RemovesNotFoundNote var tu = mergedDoc2.GetTransUnitForId("That.test"); Assert.IsNotNull(tu); - Assert.That(tu.Notes.Any(n => n.Text.StartsWith("Not found")), Is.False); + Assert.That(tu.Notes.Any(n => n.Text.Contains("Not found")), Is.False); } private void CheckMergedTransUnit(XLiffTransUnit tu, string sourceText, string[] notes, bool isDynamic)