Implementing Localization for PowerToys Modules Using .resx and .resw Files
PowerToys implements localization through standard .NET resource files, using .resx for WinForms modules and .resw for XAML-based Settings UI, accessed via strongly-typed designer classes or a singleton ResourceLoader that automatically loads culture-specific PRI packages based on the user's display language.
PowerToys, Microsoft's open-source utility suite for Windows, supports multiple languages across its numerous C# modules by leveraging the standard .NET localization infrastructure. Whether you are contributing to the WinForms-based PowerRename utility or the WinUI XAML Settings interface, understanding how to properly implement localization for PowerToys modules using .resx and .resw files ensures your UI text displays correctly across all supported locales.
Understanding Resource Types: .resx vs .resw
PowerToys uses two distinct resource file formats depending on the UI technology stack. The project structure separates these clearly to maintain compatibility with both classic Windows Forms and modern WinUI applications.
.resx files serve WinForms and classic .NET modules. These XML resource files live in paths like src/modules/powerrename/dll/Resources.resx and compile into strongly-typed C# accessor classes via ResGen. The auto-generated Resources.Designer.cs exposes static properties such as Resources.PowerRename_DeleteConfirmation that map directly to resource keys.
.resw files support UWP and WinUI XAML interfaces, primarily in the Settings UI and Quick Access modules. Located in folders like src/settings-ui/Settings.UI/Strings/en-us/Resources.resw, these files require runtime resolution through Windows.ApplicationModel.Resources.ResourceLoader rather than compile-time properties.
Both formats ultimately package into .pri (Package Resource Index) files—such as PowerToys.Settings.pri—that Windows loads dynamically based on the current UI culture.
How Resource Loading Works in PowerToys
The localization system operates through a predictable pipeline that handles culture resolution automatically without requiring runtime logic in individual modules.
-
Base and satellite resources: Each module includes a base English resource file plus optional culture-specific variants (e.g.,
Resources.resx→Resources.fr.resxorResources.resw→Resources.fr-FR.resw). -
Designer generation: MSBuild executes
GenerateResourcetasks to create strongly-typed.Designer.csclasses for.resxfiles, exposing a lazy-loadedResourceManagerproperty. -
Singleton loader pattern: XAML-based modules implement a thin wrapper class called
ResourceLoaderInstancethat instantiates aResourceLoaderpointing to the module's PRI file:// From src/settings-ui/Settings.UI/Helpers/ResourceLoaderInstance.cs internal static class ResourceLoaderInstance { internal static ResourceLoader ResourceLoader { get; } static ResourceLoaderInstance() => ResourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("PowerToys.Settings.pri"); } -
Runtime resolution: UI code calls
ResourceLoaderInstance.ResourceLoader.GetString("KeyName")to retrieve localized strings. The OS automatically selects the appropriate language from the PRI, falling back to English if a key is missing in the requested culture. -
Culture selection: Windows determines the active language from the user's display language settings; developers add new translation files without modifying runtime code.
Adding New Localized Strings Step-by-Step
Follow this workflow when introducing new UI text that requires translation support.
Step 1: Select the Appropriate Resource Type
Choose .resx for WinForms modules and command-line utilities. Choose .resw for any XAML-based interface in Settings UI or Quick Access.
Step 2: Add the Resource Entry
For WinForms modules using .resx:
- Open the file (e.g.,
src/modules/powerrename/dll/Resources.resx) in Visual Studio's resource editor. - Add a name-value pair such as
PowerRename_DeleteConfirmation="Delete selected items?". - Save to trigger regeneration of
Resources.Designer.cs.
For XAML modules using .resw:
-
Open
src/settings-ui/Settings.UI/Strings/en-us/Resources.resw. -
Add an XML data entry:
<data name="PowerRename_DeleteConfirmation" xml:space="preserve"> <value>Delete selected items?</value> </data> -
Create culture-specific folders (e.g.,
fr-fr/,de-de/) containing identically-named.reswfiles with translated values.
Step 3: Reference the String in Code
Access your new resource using the pattern appropriate to the file type:
// .resx usage via generated designer class (WinForms)
using Microsoft.PowerToys.PowerRename.Resources;
var message = Resources.PowerRename_DeleteConfirmation;
// .resw usage via ResourceLoader (XAML/Settings UI)
var message = ResourceLoaderInstance.ResourceLoader.GetString("PowerRename_DeleteConfirmation");
Step 4: Build and Validate
Rebuild the solution. The build pipeline automatically packages updated resources into the relevant .pri files. Test by running PowerToys under different language settings to verify string retrieval.
Code Implementation Examples
Loading .resx Strings in WinForms
The PowerRename module demonstrates classic resource access through the auto-generated designer file:
// src/modules/powerrename/dll/Resources.Designer.cs provides this API
using Microsoft.PowerToys.PowerRename.Resources;
public void ShowDeleteConfirmation()
{
var message = Resources.PowerRename_DeleteConfirmation;
var title = Resources.PowerRename_DeleteTitle;
MessageBox.Show(message, title, MessageBoxButtons.YesNo);
}
Loading .resw Strings in Settings UI ViewModels
ViewModels in the Settings UI utilize the singleton loader pattern to maintain testability and consistency:
// Example pattern from src/settings-ui/Settings.UI/ViewModels/ZoomItViewModel.cs
public class PowerRenameSettingsViewModel
{
private readonly ResourceLoader _loader = ResourceLoaderInstance.ResourceLoader;
public string DeleteConfirmationText =>
_loader.GetString("PowerRename_DeleteConfirmation");
}
Adding French Localization
Create the culture-specific file at src/settings-ui/Settings.UI/Strings/fr-fr/Resources.resw with the translated content:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="PowerRename_DeleteConfirmation" xml:space="preserve">
<value>Supprimer les éléments sélectionnés ?</value>
</data>
</root>
Commit this file to include French support in the next build cycle.
Key Files and Locations
| Purpose | File Path | Access Pattern |
|---|---|---|
| PowerRename WinForms resources | src/modules/powerrename/dll/Resources.resx |
Resources.<Key> via designer |
| PowerRename designer class | src/modules/powerrename/dll/Resources.Designer.cs |
Auto-generated properties |
| Settings UI base strings | src/settings-ui/Settings.UI/Strings/en-us/Resources.resw |
ResourceLoader.GetString |
| Settings UI loader singleton | src/settings-ui/Settings.UI/Helpers/ResourceLoaderInstance.cs |
Singleton instance accessor |
| Quick Access loader | src/QuickAccess.UI/Helpers/ResourceLoaderInstance.cs |
Singleton instance accessor |
| ZoomIt ViewModel example | src/settings-ui/Settings.UI/ViewModels/ZoomItViewModel.cs |
Runtime string retrieval |
Best Practices for PowerToys Localization
-
Keep resource keys descriptive but concise—they become C# property names in generated designer files.
-
Never embed UI strings directly in code—always route through resource files to maintain translation capability.
-
Comment ambiguous entries in
.resxor.reswfiles using the comment field to provide context for translators. -
Use BCP-47 culture tags consistently in folder naming (
fr-fr,de-de,zh-cn) to match Windows language pack identifiers. -
Validate fallback behavior by testing with incomplete translations to ensure graceful degradation to English when keys are missing.
Summary
- Use
.resxfiles for WinForms modules and.reswfiles** for XAML-based Settings UI and Quick Access modules. - Access resources through strongly-typed
ResourceManagerproperties for.resx, or via theResourceLoaderInstancesingleton callingGetString()for.resw. - Add translations by creating culture-specific folders using BCP-47 tags and duplicating resource files with localized values.
- Build integration handles PRI compilation automatically; no manual packaging steps are required for localization updates.
Frequently Asked Questions
What is the difference between .resx and .resw files in PowerToys?
.resx files serve classic .NET and WinForms modules, compiling into strongly-typed C# classes with static properties for compile-time validation. .resw files support WinUI XAML applications and require runtime resolution through ResourceLoader, offering more flexibility for dynamic UI scenarios but requiring string-based key lookups.
How do I access localized strings in a Settings UI ViewModel?
Import the ResourceLoaderInstance helper from src/settings-ui/Settings.UI/Helpers/ResourceLoaderInstance.cs and call ResourceLoader.GetString("YourResourceKey"). This singleton wraps the PowerToys.Settings.pri resource package and automatically returns the appropriate language based on the current system culture.
Where should I place new language resource files for a module?
Place .resx satellite assemblies in the same directory as the base file using the culture code as the filename suffix (e.g., Resources.fr.resx). For .resw files, create a subfolder under Strings/ using the BCP-47 culture tag (e.g., Strings/fr-fr/Resources.resw) to match the packaging expectations of the PRI compiler.
Do I need to manually compile PRI files when adding translations?
No. The MSBuild pipeline automatically compiles resource files into .pri packages during the standard build process. Adding a new .resw or .resx file and rebuilding the solution is sufficient to include the translations in the output.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →