LiveResx.Avalonia
2.0.0
dotnet add package LiveResx.Avalonia --version 2.0.0
NuGet\Install-Package LiveResx.Avalonia -Version 2.0.0
<PackageReference Include="LiveResx.Avalonia" Version="2.0.0" />
<PackageVersion Include="LiveResx.Avalonia" Version="2.0.0" />
<PackageReference Include="LiveResx.Avalonia" />
paket add LiveResx.Avalonia --version 2.0.0
#r "nuget: LiveResx.Avalonia, 2.0.0"
#:package LiveResx.Avalonia@2.0.0
#addin nuget:?package=LiveResx.Avalonia&version=2.0.0
#tool nuget:?package=LiveResx.Avalonia&version=2.0.0
LiveResx.Avalonia
A lightweight localization library for Avalonia with runtime language switching, strongly-typed translations, and zero ViewModel boilerplate.
Unlike traditional .resx localization approaches, LiveResx.Avalonia keeps using standard .resx files while providing automatic UI updates when the application's culture changes.
Why?
Avalonia currently does not provide a built-in localization solution comparable to WPF's dynamic resource system for .resx files.
Typical approaches usually involve one or more of the following:
- restarting or recreating windows after a language change,
- exposing every localized string through a ViewModel,
- injecting localization services everywhere,
- manually raising
PropertyChangednotifications, - relying on reflection-based localization frameworks.
LiveResx.Avalonia aims to provide a small, strongly-typed alternative that feels natural to Avalonia applications while keeping .resx files as the single source of truth.
🚀 Getting Started
📋 Prerequisites
- Avalonia 11.3 or later
- Standard
.resxresources withPublicResXFileCodeGeneratororInternalResXFileCodeGenerator
💡 Note: Use
1.x.xwith Avalonia >= 11.3.0 and < 12.0.0, and 2.x.x with Avalonia >= 12.0.0.
📦 Installation
dotnet add package LiveResx.Avalonia
Or via the Package Manager Console:
Install-Package LiveResx.Avalonia
1️⃣ Create a resource file
Add a .resx file (e.g., Resources.resx) with the entries you want to localize:
| Name | Value |
|---|---|
Greeting |
Hello, World! |
Set the Custom Tool property to PublicResXFileCodeGenerator (or InternalResXFileCodeGenerator for internal types).
2️⃣ Declare the XAML namespace
In your Window or UserControl, add the markup extension namespace:
xmlns:loc="clr-namespace:LiveResx.Avalonia"
3️⃣ Use translations in XAML
<TextBlock Text="{loc:Translate {x:Static loc:DynamicResources.Greeting}}" />
💡 Tip: Every
DynamicResources.*property is strongly typed and appears in IntelliSense after the source generator runs.
4️⃣ Switch culture at runtime
using System.Globalization;
using LiveResx.Avalonia;
// Switch to German
DynamicLocalization.Instance.SwitchLocale(new CultureInfo("de"));
// Switch back to English
DynamicLocalization.Instance.SwitchLocale(new CultureInfo("en"));
// Read the current locale
CultureInfo current = DynamicLocalization.Instance.Locale;
All controls using {loc:Translate ...} update automatically — no configuration, base class, or service registration required.
5️⃣ Rx integration
If your project references System.Reactive or ReactiveUI, three extension methods are emitted automatically:
// Observe translation value changes
IObservable<string> text = DynamicResources.Greeting.ToObservable();
// Observe locale switches
IObservable<CultureInfo> locale = DynamicLocalization.Instance.ObservableLocale();
// Observe custom resource value changes
IObservable<string> flag = DynamicLocalization.Instance
.GetResource<string>("CountryFlag").ToObservable();
All emit the current value immediately on subscribe, then on each subsequent change.
6️⃣ Custom typed resources
For culture-aware values defined in code rather than .resx, see the Advanced Usage section.
Features
- ✅ Uses standard
.resxresource files - ✅ Runtime language switching
- ✅ Automatic UI updates
- ✅ Strongly-typed translations generated at compile time
- ✅ IntelliSense and compile-time checking
- ✅ No localization service injection
- ✅ No ViewModel properties for localized strings
- ✅ No
INotifyPropertyChangedboilerplate in application code - ✅
ToObservable()/ObservableLocale()extensions — whenSystem.ReactiveorReactiveUIis referenced - ✅
ILocalizedResource<T>— define a class and the source generator auto-creates aDynamicResources.*property, registers it, and wires up culture switching - ✅
LocalizedResource<T>— culture-aware typed values withInvariantorParentChainfallback - ✅
RegisterResource<T>()/GetResource<T>()/TryGetResource<T>()— runtime custom resource registration
How it works
LiveResx.Avalonia consists of three parts:
- Runtime library – manages translations and language switching.
- Source generator – discovers
.resxresources and generates strongly-typed translation objects. - Markup extension – connects generated translations to Avalonia bindings.
Internally, every generated translation is represented by a small observable object. When the culture changes, the library updates all registered translations, causing Avalonia bindings to refresh automatically.
Advanced Usage
Source-generated custom resources (ILocalizedResource<T>)
When you need a culture-switchable resource that is defined in application code rather than a .resx file — for example, paths to flag images, enum values, or configuration objects — implement ILocalizedResource<T> on a class.
The source generator automatically discovers the class, creates a LocalizedResource<T> field, registers it with DynamicLocalization, and exposes it as a property on DynamicResources.
1. Define the resource
using System.Collections.Generic;
using System.Globalization;
using LiveResx.Avalonia;
internal sealed class CountryFlags : ILocalizedResource<string>
{
public IReadOnlyDictionary<CultureInfo, string> Values { get; } =
new Dictionary<CultureInfo, string>
{
[CultureInfo.InvariantCulture] = "/Assets/default.svg",
[new CultureInfo("en")] = "/Assets/uk.svg",
[new CultureInfo("de")] = "/Assets/de.svg",
}.AsReadOnly();
}
2. Use it in XAML
<Image Source="{Binding Value, Source={x:Static loc:DynamicResources.CountryFlags}}" />
Note:
DynamicResources.CountryFlagsreturns aLocalizedResource<string>instance. Binding toValueensures the image source updates automatically whenDynamicLocalization.SwitchLocaleis called, becauseLocalizedResource<T>.ValueraisesPropertyChanged.
3. Imperative usage
// Read the current value (snapshot of the active culture)
string currentFlag = DynamicResources.CountryFlags.Value;
// Switch locale — all bindings and .Value accessors update automatically
DynamicLocalization.Instance.SwitchLocale(new CultureInfo("de"));
4. Reactive extensions
When System.Reactive or ReactiveUI is referenced, you can observe value changes:
IObservable<string> flag = DynamicResources.CountryFlags.ToObservable();
The observable emits the current value immediately on subscribe, then on each culture switch.
Manual custom resources (LocalizedResource<T>)
If you prefer to create and manage resource instances in code instead of using the source generator:
// Create a culture-aware resource with a fallback strategy
var flag = new LocalizedResource<string>(
"CountryFlag",
new Dictionary<CultureInfo, string>
{
[CultureInfo.InvariantCulture] = "/Assets/default.svg",
[new CultureInfo("en")] = "/Assets/uk.svg",
[new CultureInfo("de")] = "/Assets/de.svg"
},
FallbackBehavior.Invariant);
// Register it — it will refresh automatically on SwitchLocale
DynamicLocalization.Instance.RegisterResource(flag);
// Retrieve and use
string currentFlag = DynamicLocalization.Instance.GetResource<string>("CountryFlag").Value;
// Safe retrieval when unsure about type
if (DynamicLocalization.Instance.TryGetResource<string>("CountryFlag", out var resource))
{
// Use resource.Value
}
This is useful when the resource values are computed at runtime, loaded from a database, or when you need multiple instances of the same type.
Both approaches support ToObservable<T>() when System.Reactive or ReactiveUI is referenced.
Composite format strings (TranslateFormatExtension)
For localized strings that contain placeholders (e.g. "Hello, {0}!"), use TranslateFormat to bind the format template and arguments separately:
<TextBlock>
<TextBlock.Text>
<loc:TranslateFormat Template="{x:Static loc:DynamicResources.WelcomeMessage}">
<Binding Path="UserName" />
</loc:TranslateFormat>
</TextBlock.Text>
</TextBlock>
The UI is automatically updated when either the bound value (UserName) changes or the localized template is refreshed due to a culture change.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.