Skip to content

fix(i18n): stop leaking a ResourceDictionary on every language switch - #165

Open
divya0795 wants to merge 1 commit into
k1tbyte:masterfrom
divya0795:fix/localization-dictionary-leak
Open

fix(i18n): stop leaking a ResourceDictionary on every language switch#165
divya0795 wants to merge 1 commit into
k1tbyte:masterfrom
divya0795:fix/localization-dictionary-leak

Conversation

@divya0795

@divya0795 divya0795 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Fixes #164

Problem

LocalizationManager.SetLanguage replaces the merged locale ResourceDictionary correctly once, then appends on every subsequent switch without removing the previous one.

The replacement dictionary is built with new ResourceDictionary() and has no Source (:85), but the lookup for the dictionary to replace requires d.Source != null (:108-109). The first switch matches App.xaml's Locale/lang.en-US.xaml; after that the installed dictionary has no Source, the lookup returns null, and control reaches the else branch that calls .Add(...).

Switching language N times leaves N parsed locale dictionaries merged for the process lifetime. Text stays correct — the last merged dictionary wins — so the symptom is an unbounded memory leak, not wrong strings.

Change

Track the installed dictionary in _currentLocaleDictionary and prefer it when locating the one to replace, keeping the existing Source-based predicate as the fallback for the first call.

The index is now resolved before use and the else branch is taken when it is -1, so a tracked dictionary that is no longer merged appends instead of throwing on Insert(-1, ...). Behaviour is otherwise unchanged: same position in MergedDictionaries, same English-base-plus-overlay construction, same settings save.

One file changed, +17 / -5.

Verification

  • Control-flow analysis against master @ 643c8f8.
  • Compile-checked by dispatching this repo's own .github/workflows/build.yml (full build.ps1 → MSBuild, windows-latest) on my fork — I have no local Visual Studio/MSBuild environment. Run linked in a comment below.

Two limits I want to be explicit about rather than imply otherwise:

  • The repo has no C# test project, and WPF MergedDictionaries behaviour needs a running Application, so there is no unit test accompanying this.
  • CONTRIBUTING.md asks for manual testing against the current WeMod build; I do not have a licensed WeMod install, so I have not manually exercised the Settings language switch. The reasoning above is from the source alone and is worth a maintainer sanity-check.

@divya0795

Copy link
Copy Markdown
Contributor Author

Compile verification: dispatched this repo's own build.yml against this branch on my fork. It runs the full build.ps1 - pnpm install, web-panel build, NuGet restore, then MSBuild of Wand-Enhancer.sln on windows-latest.

Result: success in ~1.6 min

https://github.com/divya0795/Wand-Enhancer/actions/runs/30205234754

That satisfies "your code compiles without errors" from CONTRIBUTING.md. The manual-testing-against-WeMod step remains outstanding on my side, as flagged in the PR description.

SetLanguage builds the replacement locale dictionary with
"new ResourceDictionary()" and never assigns a Source, but the lookup that
finds the dictionary to replace requires "d.Source != null". Only the first
switch matches, because that one still targets the Source-bearing
Locale/lang.en-US.xaml merged by App.xaml. From then on the installed
dictionary has no Source, the lookup returns null, and control falls to the
else branch, which appends without removing.

Switching languages N times therefore leaves N fully parsed locale
dictionaries merged into Application.Current.Resources. Displayed text stays
correct because the last merged dictionary wins, so the symptom is an
unbounded memory leak rather than wrong strings.

Track the installed dictionary in a static field and prefer it when looking
up the one to replace, falling back to the Source-based predicate for the
first call. The index is checked before use so a dictionary that is no longer
merged appends instead of throwing.
@divya0795
divya0795 force-pushed the fix/localization-dictionary-leak branch from f593eea to 9bbc96d Compare July 26, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LocalizationManager leaks a ResourceDictionary on every language switch after the first

1 participant