DotNetCampus.SourceLocalizations 0.1.1-alpha.9

This is a prerelease version of DotNetCampus.SourceLocalizations.
dotnet add package DotNetCampus.SourceLocalizations --version 0.1.1-alpha.9
                    
NuGet\Install-Package DotNetCampus.SourceLocalizations -Version 0.1.1-alpha.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DotNetCampus.SourceLocalizations" Version="0.1.1-alpha.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DotNetCampus.SourceLocalizations" Version="0.1.1-alpha.9" />
                    
Directory.Packages.props
<PackageReference Include="DotNetCampus.SourceLocalizations" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DotNetCampus.SourceLocalizations --version 0.1.1-alpha.9
                    
#r "nuget: DotNetCampus.SourceLocalizations, 0.1.1-alpha.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DotNetCampus.SourceLocalizations@0.1.1-alpha.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DotNetCampus.SourceLocalizations&version=0.1.1-alpha.9&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=DotNetCampus.SourceLocalizations&version=0.1.1-alpha.9&prerelease
                    
Install as a Cake Tool

DotNetCampus.SourceLocalizations

Build NuGet
alternate text is missing from this package README image alternate text is missing from this package README image

DotNetCampus.SourceLocalizations is a source generator that can convert text localization files (e.g. .toml) into C# code and provide strong type support for localization keys.

Features

static void Main()
{
    Console.WriteLine(LocalizedText.Current.App.Title);         // "Hello, World!"
    Console.WriteLine(LocalizedText.Current.App.Description);   // "This is a sample application."
    Console.WriteLine(LocalizedText.Current.Cli.Usage);         // "Usage: DotNetCampus.SourceLocalizations [options]"
    Console.WriteLine(LocalizedText.Current.PressAnyKeyToExit); // "Press any key to exit..."
}
  • Source Generators
    • Generate C# codes
    • Generate properties for implementation types (so that reflections on types can get localized properties which is very important for WPF Bindings)
    • Generate localized types for each language item which contains more than one arguments (This fixes different argument orders among different languages.)
  • File formats
    • TOML
    • YAML 🤡 Might be deprecated in the future.
  • UI Frameworks Support
    • Avalonia 😉 We look forward to your better suggestions.
    • MAUI 😶‍🌫️ Not tested yet
    • Uno Platform 😉 We look forward to your better suggestions.
    • Wpf 😉 We look forward to your better suggestions.
  • Diagnostics Analyzers and Code Fixes
    • Detect (and generate) missing localization keys
    • Detect (and remove) unused localization keys
    • Detect arguments mismatch among localized texts (e.g. Hello, {name:string} in en but こんにちは、{errorCode:int} in ja)
    • Detect invalid IETF language tags and report errors

Installation

alternate text is missing from this package README image

dotnet add package DotNetCampus.SourceLocalizations

Usage

1. Create localization files

// Localizations/en.toml
App.Title = "Hello, World!"
App.Description = "This is a sample application."
Cli.Usage = "Usage: DotNetCampus.SourceLocalizations [options]"
PressAnyKeyToExit = "Press any key to exit..."
// Localizations/zh-hans.toml
App.Title = "你好,世界!"
App.Description = "这是一个示例应用程序。"
Cli.Usage = "用法:dotnetCampus.SourceLocalizations [选项]"
PressAnyKeyToExit = "按任意键退出..."

The file name must conform to the IETF BCP 47 standard.

2. Write a localization class

// LocalizedText.cs
using DotNetCampus.SourceLocalizations;

namespace SampleApp;

// The default language is used to generate localization interfaces, so it must be the most complete one.
// The current language is optional. If not specified, the current OS UI language will be used.
// The notification is optional. Use NotificationMode.CurrentCulturePropertyChanged to notify the UI to update the localization text when the current language changes.
[LocalizedConfiguration(Default = "en", Current = "zh-hans", NotificationMode = NotificationMode.InitOnly)]
public partial class LocalizedText;

3. Use the generated code

Console, library or any other UI framework:

// Program.cs
static void Main()
{
    Console.WriteLine(LocalizedText.Current.App.Title);         // "Hello, World!"
    Console.WriteLine(LocalizedText.Current.App.Description);   // "This is a sample application."
    Console.WriteLine(LocalizedText.Current.Cli.Usage);         // "Usage: DotNetCampus.SourceLocalizations [options]"
    Console.WriteLine(LocalizedText.Current.PressAnyKeyToExit); // "Press any key to exit..."
}

Avalonia:


<TextBlock Text="{Binding App.Title, Source={x:Static l:LocalizedText.Current}}" />
<TextBlock Text="{Binding App.Description, Source={x:Static l:LocalizedText.Current}}" />

WPF:


<TextBlock Text="{Binding App.Title, Source={x:Static l:LocalizedText.Current}, Mode=OneWay}" />
<TextBlock Text="{Binding App.Description, Source={x:Static l:LocalizedText.Current}, Mode=OneWay}" />

Uno Platform:


<TextBlock Text="{x:Bind l:Lang.Current.App.Title}" />
<TextBlock Text="{x:Bind l:Lang.Current.App.Description}" />
// Uno Platform MainPage.xaml.cs
using DotNetCampus.Localizations;
namespace DotNetCampus.SampleUnoApp;
public sealed partial class MainPage : Page
{
    public MainPage() => InitializeComponent();
    // IMPORTANT: The Lang property must be public.
    public ILocalizedValues Lang => global::DotNetCampus.SampleUnoApp.Localizations.LocalizedText.Current;
}

Best Practices

Write the full property chain at each use site. Searching the repository for a key path such as App.Title then finds every read.

window.Title = LocalizedText.Current.App.Title;
window.Content = LocalizedText.Current.App.Description;

A local, field, or property that holds an intermediate node removes that path from the call site, so the same search no longer finds it. The intermediate adds nothing: each step is already a property read.

// Do not do this. It is an anti-pattern.
var lta = LocalizedText.Current.App;
window.Title = lta.Title;          // A search for App.Title misses this line.
window.Content = lta.Description;  // A search for App.Description misses this line.

Advanced Usage

If you want to add real-time language switching support, you can modify the LocalizedText class as follows:

[LocalizedConfiguration(Default = "en-US", NotificationMode = NotificationMode.CurrentCulturePropertyChanged)]
public static partial class LocalizedText
{
    public static AppBuilder UseCompiledLang(this AppBuilder appBuilder)
    {
        if (OperatingSystem.IsWindows())
        {
            var language = GetUserProfileLanguage() ?? CultureInfo.CurrentUICulture.Name;
            SetCurrent(language);
            SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
        }
        else
        {
            // On other operating systems, the current language is automatically set to the current UI culture.
        }
        return appBuilder;
    }

    [SupportedOSPlatform("windows")]
    private static void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
    {
        if (e.Category is UserPreferenceCategory.Locale)
        {
            Dispatcher.UIThread.InvokeAsync(() =>
            {
                var language = GetUserProfileLanguage();
                if (language is not null)
                {
                    SetCurrent(language);
                }
            }, DispatcherPriority.Background);
        }
    }

    [SupportedOSPlatform("windows")]
    private static string? GetUserProfileLanguage()
    {
        // Retrieve the current language settings from the registry.
        //
        // Compared to CultureInfo.CurrentUICulture.Name or Win32 API's GetUserDefaultUILanguage, the registry can get updated standard language tags,
        // and supports user-defined language preferences without needing to log off.
        // Note: Even restarting the application will get the old settings; only logging off the system will get the new ones.
        var languageNames = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64)
            .OpenSubKey(@"Control Panel\International\User Profile", false)?
            .GetValue("Languages", null) as IReadOnlyList<string>;
        return languageNames?.FirstOrDefault();
    }
}

Then, you can use the UseCompiledLang method in your App.xaml.cs file:

public static AppBuilder BuildAvaloniaApp()
    => AppBuilder.Configure<App>()
        .UsePlatformDetect()
        .UseCompiledLang()
        .XxxOthers()
    ;

Compose providers by priority

Dictionary mode exposes Lang.Current as an ILocalizedStringProvider. Set SupportsAddingProviders to generate an independent Provider chain for a Lang. Compiled mode does not support this option and reports build error DLA006 when it is enabled:

[LocalizedConfiguration(
    Default = "zh-Hans",
    GenerationMode = GenerationMode.Dictionary,
    DependencyMode = DependencyMode.Library,
    SupportsAddingProviders = true)]
internal static partial class Lang;

The generator adds Lang.AddProvider and Lang.RemoveProvider. The generated Lang's own Provider has priority 0. Providers with a positive priority override its values, while providers with a negative priority act as fallbacks. An added Provider with priority 0 is queried after the generated Provider. Empty results continue to the next Provider.

Lang.AddProvider(ProductLang.Current, priority: 50);
Lang.AddProvider(AppLang.Current, priority: 100);

Each generated Lang owns its Provider chain. No process-wide Provider collection is used. The same behavior is available with DependencyMode.Library and DependencyMode.NestedSource.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .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.

Version Downloads Last Updated
0.1.1-alpha.9 347 10/22/2026
0.1.1-alpha.7 63 10/19/2026
0.1.1-alpha.6 679 9/18/2026
0.1.1-alpha.5 590 7/8/2026
0.1.1-alpha.4 115 5/24/2026
0.1.1-alpha.2 236 10/28/2025
0.1.1-alpha.1 192 10/14/2025
0.1.0-alpha22 252 8/27/2025
0.1.0-alpha21 234 8/27/2025
0.1.0-alpha20 224 7/18/2025
0.1.0-alpha19 197 4/25/2025
0.1.0-alpha18 190 4/25/2025
0.1.0-alpha17 192 4/25/2025
0.1.0-alpha16 216 4/22/2025
0.1.0-alpha15 211 3/31/2025
0.1.0-alpha14 200 3/31/2025
0.1.0-alpha13 183 3/28/2025
0.1.0-alpha12 182 3/27/2025
0.1.0-alpha11 519 3/26/2025
0.1.0-alpha10 529 3/25/2025
Loading failed