PleasantUI ships a reactive localization system built on .NET ResourceManager. Switching language at runtime updates every bound string instantly without reloading views.
Create .resx files for each language:
Properties/Localizations/App.resx ← default (English)
Properties/Localizations/App.ru.resx ← Russian
Properties/Localizations/App.de.resx ← German
Register the resource manager in your Application constructor:
public App()
{
Localizer.AddRes(new ResourceManager(typeof(Properties.Localizations.App)));
Localizer.ChangeLang("en"); // set initial language
}Use {Localize Key} — updates live when the language changes:
<TextBlock Text="{Localize WelcomeMessage}" />
<Button Content="{Localize SaveButton}" />
<TextBox PlaceholderText="{Localize SearchPlaceholder}" />Group related keys with a context prefix to avoid collisions:
<!-- Looks up "Settings/Theme" -->
<TextBlock Text="{Localize Theme, Context=Settings}" />In the .resx file the key is Settings/Theme.
<TextBlock Text="{Localize {CompiledBinding Name}, Context=Theme}" /><TextBlock Text="{Localize NoCustomThemes, Default='No custom themes'}" />// Simple lookup — throws-style error string on missing key
string text = Localizer.Instance["WelcomeMessage"];
// Safe lookup with fallback
string title = Localizer.TrDefault("DialogTitle", "Confirm");
// With context
string label = Localizer.TrDefault("Save", "Save", "Settings");
// With format args
string msg = Localizer.Tr("ItemCount", context: null, args: 42);
// resx value: "Found {0} items" → "Found 42 items"
// Try-get pattern
if (Localizer.Instance.TryGetString("MyKey", out string value))
DoSomething(value);Localizer.ChangeLang("ru");All {Localize} bindings update immediately. Subscribe to the event if you need to react in code:
Localizer.Instance.LocalizationChanged += lang =>
{
Console.WriteLine($"Language changed to: {lang}");
};You can register multiple resource managers — lookups cascade through all of them in registration order:
Localizer.AddRes(new ResourceManager(typeof(App))); // app strings
Localizer.AddRes(new ResourceManager(typeof(LibraryStrings))); // library stringsUse \\n in the .resx value — it is automatically converted to \n at runtime:
<data name="MultiLineMessage">
<value>Line one\\nLine two</value>
</data>