Table of Contents
Table of Contents
- ResX Files and Resource File Editors: The Complete .NET Localization Guide
- TL;DR / Key Takeaways
- What Are ResX Files?
- The XML Structure
- Satellite Assemblies
- How to Set Up ResX-Based Localization
- Step 1: Create Resource Files
- Step 2: Access Resources in C#
- Step 3: Set the Culture
- Step 4: Use IStringLocalizer
- Step 5: WPF and WinForms
- Best Resource File Editors
- Common Issues
- Modern Alternatives
- Conclusion
- References
ResX Files and Resource File Editors: The Complete .NET Localization Guide
If you've ever added a second language to a .NET application, you've encountered .resx files. They're the backbone of .NET localization — and they've been around since .NET Framework 1.0. This guide explains how .resx files work, how to structure a localization setup correctly in both ASP.NET Core and WinForms/WPF, which editors make the job manageable, and when it is worth looking at alternatives.
TL;DR / Key Takeaways
- A
.resxfile is an XML-based resource file used by .NET to store localized strings, images, and other data. The runtime loads the correct file based on the current thread culture. - The satellite assembly model compiles locale-specific
.resxfiles into separate.dllfiles, so your main application ships without embedding every translation. - Visual Studio has a built-in
.resxeditor, but it becomes painful beyond a handful of languages. Third-party tools like ResXManager or Zeta Resource Editor significantly improve the multi-language editing experience. .resxlocalization is the right default for offline desktop applications (WPF, WinForms, MAUI) where all assets must be bundled.- For web applications, CDN-based delivery platforms can complement or replace
.resxworkflows, reducing rebuild-and-redeploy cycles for translation updates.
What Are ResX Files?
A .resx file is an XML resource file that .NET uses to store named key-value pairs — typically strings — for a specific language or culture. When your application runs, the ResourceManager class loads the correct .resx file based on the current thread's CultureInfo, falling back to the default (neutral) resource file if a locale-specific file does not exist.
The XML Structure
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<data name="WelcomeMessage" xml:space="preserve">
<value>Welcome to our application!</value>
<comment>Displayed on the home page hero section</comment>
</data>
<data name="SubmitButton" xml:space="preserve">
<value>Submit</value>
</data>
</root>
For a French translation, create Strings.fr.resx alongside Strings.resx. The runtime walks the culture hierarchy from most specific (fr-CA) to neutral (fr) to default (Strings.resx).
Satellite Assemblies
The .NET compiler compiles locale-specific .resx files into satellite assemblies — separate .dll files in culture-code subdirectories. According to Microsoft's documentation, this lets teams update languages independently.
How to Set Up ResX-Based Localization
Step 1: Create Resource Files
Resources/
Strings.resx ← default (English)
Strings.fr.resx ← French
Strings.de.resx ← German
Strings.ja.resx ← Japanese
Step 2: Access Resources in C#
using MyApp.Resources;
string message = Strings.WelcomeMessage;
Step 3: Set the Culture
Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr");
In ASP.NET Core, use RequestLocalizationMiddleware.
Step 4: Use IStringLocalizer
public class HomeController : Controller
{
private readonly IStringLocalizer<HomeController> _localizer;
public HomeController(IStringLocalizer<HomeController> localizer) => _localizer = localizer;
public IActionResult Index()
{
ViewData["Message"] = _localizer["WelcomeMessage"];
return View();
}
}
See the ASP.NET Core localization docs.
Step 5: WPF and WinForms
<TextBlock Text="{x:Static props:Strings.WelcomeMessage}" />
Best Resource File Editors
| Editor | Platform | Multi-language | Auto-translate | Best for |
|---|---|---|---|---|
| Visual Studio | Windows | No | No | Quick edits |
| ResXManager | Windows | Yes | Google Translate | .NET teams |
| Zeta Resource Editor | Windows | Yes | No | Small teams |
| POEditor | Web | Yes | MT | Non-dev translators |
| Crowdin | Web | Yes | MT | Enterprise |
| Better i18n | Web + CLI | Yes | AI-powered | Web + .NET hybrid |
ResXManager is the most widely used — open-source, side-by-side editing, missing translation highlighting.
Common Issues
Translations not showing? Check file naming case sensitivity (Linux/macOS), satellite assembly presence, and ResourcesPath in AddLocalization().
Culture fallback: fr-CA → fr → default. Missing keys fall back silently.
Thousands of keys? Split by functional area: Strings.Common.resx, Strings.Checkout.resx, etc.
Keeping files in sync? Use ResXManager's missing-translation view or a build-time check.
Modern Alternatives
JSON-Based: IStringLocalizer<T> works with JSON providers. More readable in PRs, but no strongly-typed wrapper.
CDN-Based: Better i18n delivers translations from Cloudflare's edge. Update strings without a redeploy.
When .resx is still right: Desktop apps (WPF, WinForms, MAUI) that must work offline. Satellite assemblies are the correct model.
Conclusion
Start with .resx and Visual Studio for any .NET project. Add ResXManager at 3+ languages. Consider JSON or CDN for web-first projects. Keep .resx for desktop apps.
References
Last updated: March 2026