Class Localizer
- Namespace
- RentADeveloper.ResXLocalization
- Assembly
- ResXLocalization.Core.dll
The default ILocalizer implementation: an ambient, process-wide localizer that resolves strings from registered ResourceManager instances and notifies bindings when the culture changes. Access the shared instance through Current.
public sealed class Localizer : ILocalizer, INotifyPropertyChanged
- Inheritance
-
Localizer
- Implements
- Inherited Members
- Extension Methods
Remarks
Like the UI frameworks it serves, this class is designed for UI-thread use and is not synchronized: register resource managers once at startup and set CurrentCulture, MessageFormatter, LookupFailureTextBuilder and EnumKeyBuilder from the UI thread, so change notifications reach bindings on the thread WPF and Avalonia expect.
Constructors
Localizer()
Initializes a new, isolated localizer with no registered resource managers. The XAML markup extensions always resolve through the ambient Current instance - create your own instance only where isolation matters, such as unit tests or code-behind consumers that inject ILocalizer.
public Localizer()
Properties
Current
Gets or sets the shared, ambient localizer instance used throughout the application. Register resource managers on it at startup and set CurrentCulture to switch languages. Applications may replace it at startup with their DI-owned implementation; markup extensions always resolve through the current value.
public static ILocalizer Current { get; set; }
Property Value
Exceptions
- ArgumentNullException
The assigned value is null.
CurrentCulture
Gets or sets the culture used to resolve resources. Setting a different value raises PropertyChanged, advances RefreshTriggeringRevision and raises CultureChanged.
public CultureInfo CurrentCulture { get; set; }
Property Value
- CultureInfo
The active culture. Defaults to CurrentUICulture.
Remarks
Setting this property changes only how this localizer resolves translations; it deliberately does not touch CurrentUICulture or DefaultThreadCurrentUICulture. ResXLocalization is a translation engine, not a formatting engine - if number, date, or currency formatting should follow the selected language too, set those thread cultures yourself when handling CultureChanged.
Exceptions
- ArgumentNullException
The supplied value is null.
EnumKeyBuilder
Gets or sets the function that builds the resource key of an enum lookup from the enumeration value and an optional key prefix.
public Func<Enum, string?, string> EnumKeyBuilder { get; set; }
Property Value
- Func<Enum, string, string>
The enum key function. Defaults to the
Enum_{EnumTypeName}_{Value}convention.
Remarks
The function receives, in order:
- The enumeration value of the lookup (Enum); never null.
-
The key prefix the lookup passed (
keyPrefix,KeyPrefix; string?), or null when it passed none. null means "use your own default"; a non-null value is an explicit override.
It returns the resource key, never null or empty. The default builds
{keyPrefix ?? "Enum_"}{EnumTypeName}_{Value}, for example
Enum_FileSortOrder_Ascending. A custom convention might look like this:
Localizer.Current.EnumKeyBuilder = (value, keyPrefix) => (keyPrefix ?? "Text_") + value.GetType().Name + "." + value;
The builder applies to every enum lookup: Get(Enum, …), {l:LocalizeEnum} and
LocalizeEnumConverter. It must not throw or return null or an empty
string: an exception it throws propagates out of the lookup, and a null or empty
result makes the lookup throw InvalidOperationException.
Assigning a different delegate instance advances RefreshTriggeringRevision, so bound text re-resolves; assigning the current instance again does nothing.
Exceptions
- ArgumentNullException
The supplied value is null.
this[string]
Gets the localized string for the specified key by searching every registered ResourceManager in registration order.
public string this[string key] { get; }
Parameters
keystringThe resource key to resolve.
Property Value
- string
The localized string, Empty for a null or empty key, or the failure text (see ILocalizer).
LookupFailureTextBuilder
Gets or sets the function that produces the failure text: the text a lookup returns instead of a translation when no resource file contains the key or its value cannot be formatted.
public Func<LookupFailure, string> LookupFailureTextBuilder { get; set; }
Property Value
- Func<LookupFailure, string>
The failure-text function. Defaults to
failure => $"!{failure.Key}!".
Remarks
The function receives a LookupFailure describing the failed lookup; Reason tells the two cases apart. It returns the text shown instead of the translation; an empty string shows nothing.
Examples:
failure => $"[{failure.Key}]"failure => failure.Key[(failure.Key.LastIndexOf('.') + 1)..]failure => failure.Culture.TwoLetterISOLanguageName == "de" ? $"[fehlt: {failure.Key}]" : $"[missing: {failure.Key}]"failure => failure.Reason == LookupFailureReason.TranslationNotFound ? $"[missing: {failure.Key}]" : $"[broken: {failure.Key}]"
The function is called on every failed lookup, so it should be cheap. It must not throw or return null: an exception it throws propagates out of the lookup, and a null result makes the lookup throw InvalidOperationException.
Assigning a different delegate instance advances RefreshTriggeringRevision; assigning the current instance again does nothing.
Exceptions
- ArgumentNullException
The supplied value is null.
MessageFormatter
Gets or sets the formatter that turns each resolved resource value and the arguments of its lookup into the final string.
public IMessageFormatter MessageFormatter { get; set; }
Property Value
- IMessageFormatter
The formatter. Defaults to Instance.
Remarks
Every lookup that resolves a value calls the formatter, also a lookup without arguments, so it is the one hook for all translated texts (see ILocalizer).
Localizer.Current.UseMessageFormat() from the ResXLocalization.MessageFormat package installs an
ICU MessageFormat formatter here (plural, select). That formatter parses every resolved
value as an ICU message, including the values of lookups without arguments.
Assigning a different instance advances RefreshTriggeringRevision; assigning the current instance again does nothing. Exceptions thrown by PropertyChanged handlers propagate from the assignment.
Exceptions
- ArgumentNullException
The supplied value is null.
RefreshTriggeringRevision
Gets a value that changes whenever something changes that can change the result of a lookup - the culture, the formatter, the lookup-failure text builder, the enum key builder or the registered resource managers. Bind to it to re-resolve localized text; only whether the value differs is meaningful.
public int RefreshTriggeringRevision { get; }
Property Value
Remarks
The value advances after each real change of CurrentCulture,
MessageFormatter, LookupFailureTextBuilder or
EnumKeyBuilder, and after
RegisterResourceManager(ResourceManager), UnregisterResourceManager(ResourceManager) and
ClearResourceManagers() when they change the registered set. Each advance raises
PropertyChanged for this property and then for the indexer
(Item[]). Strings previously returned by Get are not updated.
Make these changes on the UI thread once views exist. In XAML, the trigger is
<Binding Path="RefreshTriggeringRevision" Source="{x:Static core:Localizer.Current}" />.
Methods
ClearResourceManagers()
Removes every registered ResourceManager from the search-all set. Typed and scoped lookups are unaffected - they never consult the registration set. When at least one manager was registered, advances RefreshTriggeringRevision.
public void ClearResourceManagers()
Get(ResourceKey, MessageArguments?)
Resolves the localized string for a typed ResourceKey, which carries both the key name and the owning ResourceManager, and passes it to MessageFormatter with the supplied arguments.
public string Get(ResourceKey key, MessageArguments? arguments = null)
Parameters
keyResourceKeyThe typed key identifying the resource and its resource manager.
argumentsMessageArgumentsThe arguments of the lookup, built with MessageArguments; null or empty for none.
Returns
- string
The localized (or formatted) string, or the failure text (see ILocalizer).
Remarks
Every resolved value passes through MessageFormatter; a formatting failure returns the failure text and raises LookupFailed (see ILocalizer).
Exceptions
- ArgumentNullException
keyis a default or otherwise uninitialized ResourceKey, whose Manager is null.
Get(Enum, MessageArguments?, ResourceManager?, string?)
Resolves the localized string for an enumeration value: EnumKeyBuilder builds the resource key from the value, which is then resolved like a string key and passed to MessageFormatter with the supplied arguments.
public string Get(Enum value, MessageArguments? arguments = null, ResourceManager? resourceManager = null, string? keyPrefix = null)
Parameters
valueEnumThe enumeration value to resolve.
argumentsMessageArgumentsThe arguments of the lookup, built with MessageArguments, for example
MessageArguments.FromValues(count); null or empty for none.resourceManagerResourceManagerThe single resource manager to read the key from, or null (the default) to search every registered resource manager in registration order.
keyPrefixstringA key prefix passed to EnumKeyBuilder, overriding only its default prefix (by default
Enum_); null (the default) lets the builder decide. Pass it by name:Get(sortOrder, keyPrefix: "Display_").
Returns
- string
The localized (or formatted) string, or the failure text (see ILocalizer).
Remarks
Every resolved value passes through MessageFormatter; a formatting failure returns the failure text and raises LookupFailed (see ILocalizer).
Exceptions
- ArgumentNullException
valueis null.- InvalidOperationException
EnumKeyBuilder returned null or an empty string.
Get(string, MessageArguments?, ResourceManager?)
Resolves the localized string for the specified key - searching every registered ResourceManager in registration order, or reading a single, explicit one - and passes it to MessageFormatter with the supplied arguments.
public string Get(string key, MessageArguments? arguments = null, ResourceManager? resourceManager = null)
Parameters
keystringThe resource key to resolve.
argumentsMessageArgumentsThe arguments of the lookup, built with MessageArguments, for example
MessageArguments.FromValues(3, 10); null or empty for none.resourceManagerResourceManagerThe single resource manager to read the key from, or null (the default) to search every registered resource manager in registration order. Pass it by name:
Get("Key", resourceManager: rm).
Returns
- string
The localized (or formatted) string, Empty for a null or empty key, or the failure text (see ILocalizer) in case the lookup failed.
Remarks
This is the lookup every other Get overload, the indexer and the XAML markup extensions go
through. Every resolved value passes through MessageFormatter; a formatting failure
returns the failure text and raises LookupFailed (see ILocalizer).
GetAvailableCultures()
Discovers the cultures for which any registered ResourceManager ships its own resources - the natural source for a language picker.
public IReadOnlyList<CultureInfo> GetAvailableCultures()
Returns
- IReadOnlyList<CultureInfo>
The union of the available cultures across every registered resource manager, sorted by culture name, with InvariantCulture (the neutral resources) first when present. Empty when nothing is registered.
Remarks
The neutral (fallback) resources embedded in the main assembly are reported as
InvariantCulture, because a ResourceManager does not
expose which language they are written in. Map it to the language you declared in
<NeutralLanguage> when building a picker.
Discovery probes every known culture for a satellite assembly, which is I/O-bound: call it once at startup and cache the result rather than per lookup or per binding.
GetAvailableCultures(ResourceManager)
Discovers the cultures for which a single ResourceManager ships its own resources. See GetAvailableCultures() for how neutral resources are reported and why the result should be cached.
public IReadOnlyList<CultureInfo> GetAvailableCultures(ResourceManager resourceManager)
Parameters
resourceManagerResourceManagerThe resource manager to probe.
Returns
- IReadOnlyList<CultureInfo>
The available cultures, sorted by culture name, with InvariantCulture (the neutral resources) first when present.
Exceptions
- ArgumentNullException
resourceManageris null.
RegisterResourceManager(ResourceManager)
Registers a ResourceManager to be searched by search-all lookups. Managers are searched in registration order, and the first match wins; registering the same instance more than once has no effect. Adding a manager advances RefreshTriggeringRevision.
public void RegisterResourceManager(ResourceManager resourceManager)
Parameters
resourceManagerResourceManagerThe resource manager to add to the search set.
Remarks
Which lookups need registration, which instance to register and where to register it is described on RegisterResourceManager(ResourceManager).
The registrations belong to this instance. A localizer assigned to Current later does not inherit them; register the resource managers on the instance that serves the lookups.
A manager whose type is exactly ResourceManager is checked once, when it is first registered: if no resources exist under its BaseName, it is rejected and not registered. A subclass of ResourceManager is registered without that check.
Exceptions
- ArgumentNullException
resourceManageris null.- ArgumentException
resourceManageris exactly of type ResourceManager, and no resources exist under its base name - usually a hand-written base name that does not match the embedded resource.
UnregisterResourceManager(ResourceManager)
Removes a previously registered ResourceManager from the search-all set, for example when the plugin or module that owns its strings is unloaded. Typed and scoped lookups are unaffected - they never consult the registration set. Removing a manager advances RefreshTriggeringRevision.
public bool UnregisterResourceManager(ResourceManager resourceManager)
Parameters
resourceManagerResourceManagerThe resource manager to remove from the search set.
Returns
Remarks
Managers are compared by reference: pass the instance that was registered, normally the generated
<Name>Keys.ResourceManager. Another instance of the same file, such as the designer's
<Name>.ResourceManager, is not found.
Exceptions
- ArgumentNullException
resourceManageris null.
Events
CultureChanged
Occurs after CurrentCulture changes, carrying the previous and current culture. Subscribe to refresh values that are not resolved through a binding.
public event EventHandler<CultureChangedEventArgs>? CultureChanged
Event Type
LookupFailed
Occurs when a lookup fails, before it returns the failure text: no resource file contains the key, or MessageFormatter threw while formatting its value. Reason tells the two apart. Subscribe to log missing or broken translations.
public event EventHandler<LookupFailedEventArgs>? LookupFailed
Event Type
Remarks
Normal .NET resource fallback runs first, so a key that resolves from a parent or the neutral
resources is not reported. A formatting failure is not specific to ICU MessageFormat: the
default StringFormatMessageFormatter reports one for Broken {0, or for
File {0} of {1} with one argument.
Handlers must not throw (see ILocalizer).
PropertyChanged
Occurs when a property value changes, including CurrentCulture, RefreshTriggeringRevision and the indexer, so that localized bindings re-resolve after a change that can change the result of a lookup.
public event PropertyChangedEventHandler? PropertyChanged