DotNetCampus.SourceLocalizations
0.1.1-alpha.6
dotnet add package DotNetCampus.SourceLocalizations --version 0.1.1-alpha.6
NuGet\Install-Package DotNetCampus.SourceLocalizations -Version 0.1.1-alpha.6
<PackageReference Include="DotNetCampus.SourceLocalizations" Version="0.1.1-alpha.6" />
<PackageVersion Include="DotNetCampus.SourceLocalizations" Version="0.1.1-alpha.6" />
<PackageReference Include="DotNetCampus.SourceLocalizations" />
paket add DotNetCampus.SourceLocalizations --version 0.1.1-alpha.6
#r "nuget: DotNetCampus.SourceLocalizations, 0.1.1-alpha.6"
#:package DotNetCampus.SourceLocalizations@0.1.1-alpha.6
#addin nuget:?package=DotNetCampus.SourceLocalizations&version=0.1.1-alpha.6&prerelease
#tool nuget:?package=DotNetCampus.SourceLocalizations&version=0.1.1-alpha.6&prerelease
DotNetCampus.SourceLocalizations
| Build | NuGet |
|---|---|
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.
- Avalonia
- 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
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;
}
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 | 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.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.1-alpha.6 | 116 | 9/18/2026 |
| 0.1.1-alpha.5 | 571 | 7/8/2026 |
| 0.1.1-alpha.4 | 95 | 5/24/2026 |
| 0.1.1-alpha.2 | 224 | 10/28/2025 |
| 0.1.1-alpha.1 | 183 | 10/14/2025 |
| 0.1.0-alpha22 | 241 | 8/27/2025 |
| 0.1.0-alpha21 | 223 | 8/27/2025 |
| 0.1.0-alpha20 | 209 | 7/18/2025 |
| 0.1.0-alpha19 | 184 | 4/25/2025 |
| 0.1.0-alpha18 | 179 | 4/25/2025 |
| 0.1.0-alpha17 | 180 | 4/25/2025 |
| 0.1.0-alpha16 | 206 | 4/22/2025 |
| 0.1.0-alpha15 | 198 | 3/31/2025 |
| 0.1.0-alpha14 | 190 | 3/31/2025 |
| 0.1.0-alpha13 | 168 | 3/28/2025 |
| 0.1.0-alpha12 | 171 | 3/27/2025 |
| 0.1.0-alpha11 | 508 | 3/26/2025 |
| 0.1.0-alpha10 | 520 | 3/25/2025 |
| 0.1.0-alpha09 | 201 | 3/20/2025 |
| 0.1.0-alpha08 | 181 | 3/20/2025 |