WinUI3Localizer 3.0.0-alpha
dotnet add package WinUI3Localizer --version 3.0.0-alpha
NuGet\Install-Package WinUI3Localizer -Version 3.0.0-alpha
<PackageReference Include="WinUI3Localizer" Version="3.0.0-alpha" />
<PackageVersion Include="WinUI3Localizer" Version="3.0.0-alpha" />
<PackageReference Include="WinUI3Localizer" />
paket add WinUI3Localizer --version 3.0.0-alpha
#r "nuget: WinUI3Localizer, 3.0.0-alpha"
#:package WinUI3Localizer@3.0.0-alpha
#addin nuget:?package=WinUI3Localizer&version=3.0.0-alpha&prerelease
#tool nuget:?package=WinUI3Localizer&version=3.0.0-alpha&prerelease
🌏WinUI3Localizer
WinUI3Localizer is a NuGet package that helps you localize your WinUI 3 app.
- Switch languages without app restarting
- You/users can edit localized strings even after deployment
- You/users can add new languages even after deployment
- Use standard Resources.resw (see Microsoft docs)
🙌 Quick Start
Note: This is a quick start guide. Check the sample app for details.
Install WinUI3Localizer
Install WinUI3Localizer from the NuGet Package Manager.
Create localized strings
Create a "Strings" folder in your app project and populate it with your string resources files for each language you need. For example, this is a basic structure for English (en-US), es-ES (Spanish) and Japanese (ja) resources files.
- Strings
- en-US
- Resources.resw
- es-ES
- Resources.resw
- ja
- Resources.resw
- en-US
Add this ItemGroup in the project file (*.csproj) of your app.
<ItemGroup>
<Content Include="Strings\**\*.resw">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Note: The "Strings" folder can be anywhere as long the app can access it. Usually, aside the app executable for non-packaged apps, or in the "LocalFolder" for packaged-apps.
Build WinUI3Localizer
Non-packaged apps:
In App.xaml.cs, build WinUI3Localizer like this:
private async Task InitializeLocalizer() { // Initialize a "Strings" folder in the executables folder. string stringsFolderPath = Path.Combine(AppContext.BaseDirectory, "Strings"); ILocalizer localizer = new LocalizerBuilder() .AddStringResourcesFolderForLanguageDictionaries(stringsFolderPath) .SetOptions(options => { options.DefaultLanguage = "en-US"; }) .Build(); }Packaged apps:
In App.xaml.cs, build WinUI3Localizer like this:
private async Task InitializeLocalizer() { // Initialize a "Strings" folder in the "LocalFolder" for the packaged app. StorageFolder localFolder = ApplicationData.Current.LocalFolder; StorageFolder stringsFolder = await localFolder.CreateFolderAsync( "Strings", CreationCollisionOption.OpenIfExists); // Create string resources file from app resources if doesn't exists. string resourceFileName = "Resources.resw"; await MakeSureStringResourceFileExists(stringsFolder, "en-US", resourceFileName); await MakeSureStringResourceFileExists(stringsFolder, "es-ES", resourceFileName); await MakeSureStringResourceFileExists(stringsFolder, "ja", resourceFileName); ILocalizer localizer = new LocalizerBuilder() .AddStringResourcesFolderForLanguageDictionaries(stringsFolder.Path) .SetOptions(options => { options.DefaultLanguage = "en-US"; }) .Build(); } private static async Task MakeSureStringResourceFileExists(StorageFolder stringsFolder, string language, string resourceFileName) { StorageFolder languageFolder = await stringsFolder.CreateFolderAsync( desiredName: language, CreationCollisionOption.OpenIfExists); string appResourceFilePath = Path.Combine(stringsFolder.Name, language, resourceFileName); StorageFile appResourceFile = await LoadStringResourcesFileFromAppResource(appResourceFilePath); IStorageItem? localResourceFile = await languageFolder.TryGetItemAsync(resourceFileName); if (localResourceFile is null || (await GetModifiedDate(appResourceFile)) > (await GetModifiedDate(localResourceFile))) { _ = await appResourceFile.CopyAsync( destinationFolder: languageFolder, desiredNewName: appResourceFile.Name, option: NameCollisionOption.ReplaceExisting); } } private static async Task<StorageFile> LoadStringResourcesFileFromAppResource(string filePath) { Uri resourcesFileUri = new($"ms-appx:///{filePath}"); return await StorageFile.GetFileFromApplicationUriAsync(resourcesFileUri); } private static async Task<DateTimeOffset> GetModifiedDate(IStorageItem file) { return (await file.GetBasicPropertiesAsync()).DateModified; }
Localizing controls
This is an example of how to localize the Content of a Button.
First asign an Uid to the Button, then in each language resources file, add an item that corresponds to the Uid.
You can also have multiple string resources files. For example, besides the Resources.resw file, you can have a Messages.resw for your messages file.
To just need to include /<resources-file-name>/ before the string resource identifier.
<Page
x:Class="WinUI3Localizer.SampleApp.TestPage"
...
xmlns:l="using:WinUI3Localizer">
<StackPanel>
<Button l:Uids.Uid="TestPage_Button">
<Button.Flyout>
<Flyout>
<TextBlock l:Uids.Uid="/Messages/ButtonFlyoutMessage" />
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</Page>
en-US
Resources.resw
Name Value TestPageButton.Content Awesome! Messages.resw
Name Value ButtonFlyoutMessage.Text This is an awesome message!
es-ES:
Resources.resw
Name Value TestPageButton.Content ¡Increíble! Messages.resw
Name Value ButtonFlyoutMessage.Text ¡Esto es un mensaje increíble!
ja:
Resources.resw
Name Value TestPageButton.Content 素晴らしい! Messages.resw
Name Value ButtonFlyoutMessage.Text これは素晴らしいメッセージです!
Getting localized strings
If we need to localize strings in code-behind or in ViewModels, we can use the GetLocalizedString() method.
List<string> colors = new()
{
"Red",
"Green",
"Blue",
};
ILocalizer localizer = Localizer.Get();
List<string> localizedColors = colors
.Select(x => localizer.GetLocalizedString(x))
.ToList();
In this case, we just use the Uid as Name.
en-US
Resources.resw
Name Value Red Red Green Green Blue Blue
es-ES:
Resources.resw
Name Value Red Rojo Green Verde Blue Azul
ja:
Resources.resw
Name Value Red 赤 Green 緑 Blue 青
Default Resources
You can place a Resources.resw file directly under the Strings folder, which will be referenced when the key is not found in the current language's Resources.resw.
Dynamic Resources
Add new dictionaries:
var newDictionary = new LanguageDictionary( language: "en-US", name: "Additional English Dictionary") { // The higher the value, the higher the priority. The default value is 0. Priority = (int)this.PriorityNumberBox.Value, }; _ = this.localizer.AddLanguageDictionary(newDictionary);Add dictionary items:
ILocalizer localizer = Localizer.Get(); string currentLanguage = localizer.GetCurrentLanguage(); LanguageDictionary currentDictionary = localizer.GetLanguageDictionaries(currentLanguage).First(); LanguageDictionaryItem newItem = new( uid: "TestPage_Button", dependencyPropertyName: "Content", stringResourceItemName: "TestPage_Button.Content", value: "Click!"); currentDictionary.AddItem(newItem);Edit dictionary items:
ILocalizer localizer = Localizer.Get(); string currentLanguage = localizer.GetCurrentLanguage(); LanguageDictionary currentDictionary = localizer.GetLanguageDictionaries(currentLanguage).First(); LanguageDictionaryItem targetItem = currentDictionary .GetItems() .First(item => item.Uid == "TestPage_Button"); targetItem.Value = "New Test Value";
Minimal example
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows10.0.19041 is compatible. net9.0-windows was computed. net9.0-windows10.0.19041 is compatible. net10.0-windows was computed. |
-
net8.0-windows10.0.19041
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.2)
- Microsoft.Windows.SDK.BuildTools (>= 10.0.26100.1742)
- Microsoft.WindowsAppSDK (>= 1.6.250205002)
-
net9.0-windows10.0.19041
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.2)
- Microsoft.Windows.SDK.BuildTools (>= 10.0.26100.1742)
- Microsoft.WindowsAppSDK (>= 1.6.250205002)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on WinUI3Localizer:
| Package | Downloads |
|---|---|
|
BeWidgets.Widget
Package Description |
GitHub repositories (4)
Showing the top 4 popular GitHub repositories that depend on WinUI3Localizer:
| Repository | Stars |
|---|---|
|
ProtonVPN/win-app
Official ProtonVPN Windows app
|
|
|
IviriusCommunity/Rebound
WinUI rewrite project of Windows 11 system apps.
|
|
|
Jorixon/JASM
Just Another Skin Manager
|
|
|
WinDurango/WinDurango.UI
GUI for WinDurango, which is planned to allow for easy installing/patching among other random stuff I decide lmfao
|
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-alpha | 393 | 3/30/2025 |
| 2.3.0 | 1,370 | 5/21/2025 |
| 2.3.0-alpha | 489 | 9/13/2024 |
| 2.2.0 | 4,956 | 4/12/2024 |
| 2.1.0 | 1,343 | 11/1/2023 |
| 2.0.1 | 389 | 9/12/2023 |
| 2.0.0 | 189 | 9/12/2023 |
| 1.1.0 | 419 | 8/15/2023 |
| 1.0.1 | 5,357 | 1/31/2023 |
| 1.0.0 | 423 | 1/30/2023 |