Skip to main content
Flowery.Uno provides built-in localization support for theme names and control text, with easy extensibility for additional languages.

Supported Languages

The library comes with built-in translations for 12 languages:

English

en (default)

German

de

French

fr

Spanish

es

Italian

it

Mandarin Simplified

zh-CN

Korean

ko

Japanese

ja

Arabic

ar

Turkish

tr

Ukrainian

uk

Hebrew

he

Quick Start

Switching Languages at Runtime

LOCALIZATION.md:26-34
using Flowery.Localization;

// Switch to German
FloweryLocalization.SetCulture("de");

// Switch to Mandarin
FloweryLocalization.SetCulture("zh-CN");

Accessing Supported Languages

LOCALIZATION.md:40-54
using Flowery.Localization;

var codes = FloweryLocalization.SupportedLanguages;
var current = FloweryLocalization.CurrentCultureName;

for (var i = 0; i < codes.Count; i++)
{
    var code = codes[i];
    if (FloweryLocalization.LanguageDisplayNames.TryGetValue(code, out var name))
    {
        // Use code and name in your UI
    }
}

XAML Binding Pattern

All Uno heads (Windows, Desktop/Skia, Android, iOS, WASM) use the WinUI XAML compiler and share the same binding rules.
Do NOT use {x:Bind Localization[...]} - the WinUI XamlCompiler rejects indexer syntax (WMC1110).

Preferred Pattern (Set DataContext Once)

LOCALIZATION.md:65-68
<ScrollViewer DataContext="{x:Bind Localization, Mode=OneWay}">
    <TextBlock Text="{Binding [Gallery_DataInput_Variants]}" />
</ScrollViewer>

Alternative (Explicit Source Per Binding)

LOCALIZATION.md:72-74
<TextBlock Text="{Binding [Gallery_DataInput_Variants], Source={x:Bind Localization}}" />
<!-- Set DataContext once -->
<ScrollViewer DataContext="{x:Bind Localization, Mode=OneWay}">
    <TextBlock Text="{Binding [Key1]}" />
    <TextBlock Text="{Binding [Key2]}" />
</ScrollViewer>

<!-- Or explicit source -->
<TextBlock Text="{Binding [Key], Source={x:Bind Localization}}" />

Runtime Language Switching

Desktop/Skia Rebinding

FloweryLocalization.SetCulture raises PropertyChanged on the UI thread via DispatcherQueue. Most Uno heads refresh indexer bindings automatically. If you still see stale values on Desktop/Skia, force a rebinding:
LOCALIZATION.md:91-99
// In your page/control that uses {Binding [Key]} with a Localization DataContext.
Loaded += (_, _) => FloweryLocalization.CultureChanged += OnCultureChanged;
Unloaded += (_, _) => FloweryLocalization.CultureChanged -= OnCultureChanged;

private void OnCultureChanged(object? sender, string cultureName)
{
    RootElement.DataContext = null;
    RootElement.DataContext = Localization;
}

Date Formatting

The DaisyDateTimeline control uses the Locale property for date formatting:
LOCALIZATION.md:121-124
<daisy:DaisyDateTimeline Locale="de-DE" />
Or bind to the current UI culture name:
LOCALIZATION.md:128-132
using System.Globalization;

timeline.Locale = CultureInfo.GetCultureInfo(FloweryLocalization.CurrentCultureName);

JSON-Based Localization

Flowery.Uno uses embedded JSON files for localization. This approach:
  • Works across all Uno Platform targets (Desktop, WASM, Android, iOS)
  • Avoids satellite assembly loading issues
  • Supports CJK/Arabic characters
  • Is AOT/trimming compatible with source generators

Step 1: Create JSON Translation Files

Create JSON files in your Localization/ folder:
LOCALIZATION.md:152-156
{
  "Effects_Reveal_Title": "Reveal Effect",
  "Effects_Reveal_Description": "Entrance animations when element enters the visual tree."
}

Step 2: Embed JSON Files in .csproj

Add all JSON files as embedded resources:
LOCALIZATION.md:170-177
<ItemGroup>
  <EmbeddedResource Include="Localization\\en.json" />
  <EmbeddedResource Include="Localization\\de.json" />
  <EmbeddedResource Include="Localization\\ja.json" />
  <!-- Add all other languages -->
</ItemGroup>

Step 3: Create JSON Localization Loader

Create a localization class that loads from embedded JSON:
LOCALIZATION.md:185-266
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

public class MyAppLocalization : INotifyPropertyChanged
{
    private static CultureInfo _currentCulture = CultureInfo.CurrentUICulture;
    private static readonly Dictionary<string, Dictionary<string, string>> _translations = new();
    private static readonly Lazy<MyAppLocalization> _instance = new(() => new MyAppLocalization());

    public static MyAppLocalization Instance => _instance.Value;
    public static event EventHandler<CultureInfo>? CultureChanged;
    public event PropertyChangedEventHandler? PropertyChanged;

    static MyAppLocalization()
    {
        // Load all translations at startup - use library's centralized list
        foreach (var lang in Flowery.Localization.FloweryLocalization.SupportedLanguages)
            LoadTranslation(lang);

        // Sync with Flowery library culture changes
        Flowery.Localization.FloweryLocalization.CultureChanged += (s, c) => SetCulture(c);
    }

    // Indexer for XAML binding
    public string this[string key] => GetString(key);

    public static void SetCulture(CultureInfo culture)
    {
        if (_currentCulture.Name == culture.Name) return;
        _currentCulture = culture;
        CultureChanged?.Invoke(null, culture);
        Instance.PropertyChanged?.Invoke(Instance, new PropertyChangedEventArgs("Item"));
        Instance.PropertyChanged?.Invoke(Instance, new PropertyChangedEventArgs("Item[]"));
    }

    public static string GetString(string key)
    {
        // Try exact culture (e.g., "de-DE")
        if (_translations.TryGetValue(_currentCulture.Name, out var exact) && exact.TryGetValue(key, out var v1))
            return v1;

        // Try language only (e.g., "de")
        var lang = _currentCulture.TwoLetterISOLanguageName;
        if (_translations.TryGetValue(lang, out var langDict) && langDict.TryGetValue(key, out var v2))
            return v2;

        // Fallback to English
        if (_translations.TryGetValue("en", out var en) && en.TryGetValue(key, out var v3))
            return v3;

        return key; // Return key if not found
    }

    private static void LoadTranslation(string langCode)
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = $"YourApp.Localization.{langCode}.json";

        using var stream = assembly.GetManifestResourceStream(resourceName);
        if (stream == null) return;

        using var reader = new StreamReader(stream);
        var json = reader.ReadToEnd();

        // Use source generator for AOT compatibility
        var dict = JsonSerializer.Deserialize(json, LocalizationJsonContext.Default.DictionaryStringString);
        if (dict != null) _translations[langCode] = dict;
    }
}

// REQUIRED: JSON Source Generator for AOT/WASM compatibility
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
[JsonSerializable(typeof(Dictionary<string, string>))]
internal partial class LocalizationJsonContext : JsonSerializerContext { }
The JsonSerializerContext source generator is required for WASM. Without it, you will get JsonSerializerIsReflectionDisabled errors.

CJK Font Support

For CJK characters (Japanese, Korean, Chinese) to display correctly, you must embed fonts in your consuming application.
Flowery.Uno does NOT ship with CJK fonts. Each consuming application that needs CJK support must embed its own fonts.

1. Embed CJK Fonts in Your App

LOCALIZATION.md:282-287
<ItemGroup>
  <Content Include="Assets\\Fonts\\NotoSansJP-Regular.otf" />
  <Content Include="Assets\\Fonts\\NotoSansSC-Regular.otf" />
  <Content Include="Assets\\Fonts\\NotoSansKR-Regular.otf" />
</ItemGroup>

2. Define Font Family Resource

LOCALIZATION.md:293-297
<Application.Resources>
    <FontFamily x:Key="NotoSansFamily">ms-appx:///Assets/Fonts/NotoSansJP-Regular.otf#Noto Sans JP</FontFamily>
</Application.Resources>

3. Apply Font to All Text Controls

LOCALIZATION.md:301-309
<Application.Resources>
    <Style TargetType="TextBlock">
        <Setter Property="FontFamily" Value="{StaticResource NotoSansFamily}" />
    </Style>
    <Style TargetType="TextBox">
        <Setter Property="FontFamily" Value="{StaticResource NotoSansFamily}" />
    </Style>
    <!-- Add other text controls as needed -->
</Application.Resources>

Available Resource Keys

The built-in keys live in Flowery.Uno/Localization/en.json. Here are some key categories:
Size_ExtraSmall
Size_Small
Size_Medium
Size_Large
Size_ExtraLarge
See LOCALIZATION.md:319-466 for the complete list of 100+ built-in resource keys.

Custom Resolver for App-Specific Keys

FloweryLocalization.GetString uses CustomResolver when it is set. This is intended for app-owned keys:
LOCALIZATION.md:106-109
// In your app's localization setup or App startup:
FloweryLocalization.CustomResolver = MyAppLocalization.GetString;
This allows:
  • Library controls that call FloweryLocalization.GetString("Sidebar_Home") to resolve your app keys
  • Your resolver to supply translations from your app’s JSON files
If you set CustomResolver, make sure it returns the key when a value is not found so the UI degrades gracefully.

Handling Culture Changes

When culture changes, bound strings need to update. For ViewModel properties:
LOCALIZATION.md:475-485
public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        FloweryLocalization.CultureChanged += (s, culture) =>
        {
            OnPropertyChanged(nameof(Greeting));
        };
    }

    public string Greeting => FloweryLocalization.GetString("Greeting_Text");
}

Troubleshooting

Cause: CJK fonts not loaded or not applied.Fix:
  1. Embed Noto Sans CJK fonts as Content
  2. Apply font to all text-displaying controls in App.xaml
Cause: WASM has Native AOT which disables reflection.Fix: Add a JsonSerializerContext source generator (see Step 3 above).
Cause: Desktop/Skia doesn’t always refresh indexer bindings.Fix: Force rebinding by setting DataContext to null then back to Localization in the CultureChanged handler.

Contributing Translations

  1. Fork the repository
  2. Add your JSON file for your language in Flowery.Uno/Localization/
  3. Submit a pull request
Contributions for any language are welcome!

Build docs developers (and LLMs) love