NE.Standard

Localization

Text in a view is translated by key against the session's language — a property marked [Translatable] holding a translation key renders as its translated text, both when the server renders it statically and when it is patched live.

Translation sources

application.AddLocalizationSource(dictionary) registers an in-memory source: a dictionary keyed by language, then by key, each value the translated text.

internal static class DemoTranslations
{
    public static IReadOnlyDictionary<string, IReadOnlyDictionary<string, string>> Build()
        => new Dictionary<string, IReadOnlyDictionary<string, string>>
        {
            ["en"] = new Dictionary<string, string>
            {
                ["demo.home.header"] = "NE.Standard.UI",
                ["demo.home.description"] = "A server-driven UI framework...",
            }
        };
}

application.AddLocalizationSource(DemoTranslations.Build());

That overload wraps the dictionary in the built-in DictionaryTranslationSource. AddLocalizationSource(ITranslationSource source) registers any other source — implement ITranslationSource (Languages, TryTranslate(language, key, out value)) for one backed by a database, a .resx set, or a translation service, and register it the same way, or as an ordinary DI service (ITranslationSource is resolved from the container too). Sources are consulted most-recently-added first, so a later AddLocalizationSource call can override a key an earlier one set.

UILocalizationOptions

application.ConfigureLocalization(o => o.DefaultLanguage = "en");

DefaultLanguage (default "en") is the fallback language used when a translation is missing for the session's requested language, and the language a brand-new session starts in.

The session's language

UserSessionState.Language is the session's current language, read by every translation the session's requests make. Change it through Context.UpdateSessionAsync, the same way any other session field changes:

[UICommand]
public ValueTask SetLanguage(string language)
    => Context.UpdateSessionAsync(session => session with { Language = language });

[Translatable]

[Translatable] marks a component or item-model property whose value is a translation key rather than literal text — TextComponent.Title, TextBaseItem.Title/Icon, BadgeItem's text properties, and most other text-bearing properties on the built-in components and models carry it. A value on such a property is translated at render time; a plain literal that happens not to be a registered key renders unchanged (a lookup miss falls back to the key itself — see below), which is what makes writing "Add one" directly, with no translation source configured, work exactly as shown in getting started.

A static item's [Translatable] fields are translated on the static-rendering path too, not only through a live binding — an author-declared MenuItem or TabItem whose Title holds a translation key renders translated even though it was never bound to the controller. This is what makes a static navigation menu, or any other author-declared item collection, fully localizable.

Context.Translate

A controller translates a key directly with Context.Translate(key), using the current session's language — useful for text going into a ShowNotificationEffect or any other place text is built in code rather than carried by a [Translatable] property:

[UICommand]
public UICommandResult Save()
    => UICommandResult.Ok([new ShowNotificationEffect(Context.Translate("demo.save.done"), UIColorStyle.Success)]);

The framework's own words

UIStrings is the vocabulary the framework's own chrome uses — a date picker's "Today", a tab strip's "More tabs", a file input's "Uploading… %" — each a translation key (UIStrings.PickerToday, UIStrings.TabsMore, …) with English text in UIStrings.English. Override one the same way you translate your own text: register the same key in your own ITranslationSource.

application.AddLocalizationSource(new Dictionary<string, IReadOnlyDictionary<string, string>>
{
    ["en"] = new Dictionary<string, string> { [UIStrings.TabsMore] = "More tabs…" },
    ["fr"] = new Dictionary<string, string> { [UIStrings.TabsMore] = "Plus d'onglets" }
});

Fallback order

A lookup tries, in order: the requested language in the application's own sources, then the application's DefaultLanguage in those same sources, then UIStrings' built-in English (which answers for any requested language, so a framework word the application has not translated still reads instead of showing its key), and finally the key itself if nothing answered. An application's own text in its default language always outranks the framework's built-in English — the framework's words are a base to override, not a ceiling.