---
name: dotnet-localization
description: >-
Localizes .NET apps. .resx resources, IStringLocalizer, source generators,
pluralization, RTL.
metadata:
short-description: .NET skill guidance for csharp tasks
---
# dotnet-localization
Comprehensive .NET internationalization and localization: .resx resource files and satellite assemblies, modern
alternatives (JSON resources, source generators for AOT), IStringLocalizer patterns, date/number/currency formatting
with CultureInfo, RTL layout support, pluralization engines, and per-framework localization integration for Blazor,
MAUI, Uno Platform, and WPF.
**Version assumptions:** .NET 8.0+ baseline. IStringLocalizer stable since .NET Core 1.0; localization APIs stable since
.NET 5. .NET 9+ features explicitly marked.
## Scope
- .resx resource files, satellite assemblies, culture fallback chains
- IStringLocalizer patterns and DI registration
- Modern alternatives: JSON resources, source generators for AOT
- Date/number/currency formatting with CultureInfo
- RTL layout support per framework (Blazor, MAUI, Uno, WPF)
- Pluralization engines (MessageFormat.NET, SmartFormat.NET)
## Out of scope
- Deep Blazor component patterns -- see [skill:dotnet-blazor-components]
- Deep MAUI development patterns -- see [skill:dotnet-maui-development]
- Uno Platform project structure and Extensions ecosystem -- see [skill:dotnet-uno-platform]
- WPF Host builder and MVVM patterns -- see [skill:dotnet-wpf-modern]
- Source generator authoring (Roslyn API) -- see [skill:dotnet-csharp-source-generators]
Cross-references: [skill:dotnet-blazor-components] for Blazor component lifecycle, [skill:dotnet-maui-development] for
MAUI app structure, [skill:dotnet-uno-platform] for Uno Extensions and x:Uid, [skill:dotnet-wpf-modern] for WPF on
modern .NET.
---
## .resx Resource Files
### Overview
Resource files (`.resx`) are the standard .NET localization format. They compile into satellite assemblies resolved by
`ResourceManager` with automatic culture fallback.
### Culture Fallback Chain
Resources resolve in order of specificity, falling back until a match is found:
````text
sr-Cyrl-RS.resx -> sr-Cyrl.resx -> sr.resx -> Resources.resx (default/neutral)
```text
The default `.resx` file (no culture suffix) is the single source of truth. Translation files must not contain keys
absent from the default file.
### Project Setup
```xml
en-US
```text
### Resource File Structure
```xml
Welcome to the applicationShown on the home pageYou have {0} item(s){0} = number of items
```text
### Accessing Resources
```csharp
// Via generated strongly-typed class (ResXFileCodeGenerator custom tool)
string welcome = Messages.Welcome;
// Via ResourceManager directly
var rm = new ResourceManager("MyApp.Resources.Messages",
typeof(Messages).Assembly);
string welcome = rm.GetString("Welcome", CultureInfo.CurrentUICulture);
```text
---
## Modern Alternatives
### JSON-Based Resources
Lightweight alternative for projects already using JSON for configuration. Libraries provide `IStringLocalizer`
implementations backed by JSON files.
```json
// Resources/en-US.json
{
"Welcome": "Welcome to the application",
"ItemCount": "You have {0} item(s)"
}
```text
**Libraries:**
- `Senlin.Mo.Localization` -- JSON-backed `IStringLocalizer`
- `Embedded.Json.Localization` -- embedded JSON resources
JSON resources are popular in ASP.NET Core but lack the built-in tooling support (Visual Studio designer, satellite
assembly compilation) of `.resx`.
### Source Generators for AOT Compatibility
Traditional `.resx` with `ResourceManager` uses reflection at runtime, which is problematic for Native AOT and trimming.
Source generators eliminate runtime reflection by generating strongly-typed accessor classes at compile time.
**Recommended source generators:**
| Generator | Description | AOT-Safe |
| -------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| ResXGenerator (ycanardeau) | Strongly-typed classes with `IStringLocalizer` support and DI registration | Yes |
| VocaDb.ResXFileCodeGenerator | Original strongly-typed `.resx` source generator | Yes |
| Built-in `ResXFileCodeGenerator` | Visual Studio custom tool (not a Roslyn source generator) | No -- generates static properties but still uses `ResourceManager` |
```xml
```text
```csharp
// Generated at compile time -- no runtime reflection
string welcome = Messages.Welcome;
// With DI registration (ResXGenerator)
services.AddResXLocalization();
```text
**Recommendation:** Use `.resx` files as the resource format (broadest tooling support) with a source generator for
AOT/trimming scenarios. Use JSON resources only for lightweight or config-heavy projects.
---
## IStringLocalizer Patterns
### Registration
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register localization services
builder.Services.AddLocalization(options =>
options.ResourcesPath = "Resources");
var app = builder.Build();
// Configure request localization middleware
var supportedCultures = new[] { "en-US", "fr-FR", "de-DE", "ja-JP" };
app.UseRequestLocalization(options =>
{
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
```text
### IStringLocalizer
The primary localization interface. Injectable via DI. Use everywhere: services, controllers, Blazor components,
middleware.
```csharp
public class OrderService
{
private readonly IStringLocalizer _localizer;
public OrderService(IStringLocalizer localizer)
{
_localizer = localizer;
}
public string GetConfirmation(int orderId)
{
// Indexer returns LocalizedString with implicit string conversion
return _localizer["OrderConfirmed", orderId];
// Resolves: "Order {0} confirmed" with orderId substituted
}
public bool IsTranslated(string key)
{
LocalizedString result = _localizer[key];
return !result.ResourceNotFound;
}
}
```text
### IViewLocalizer (MVC Razor Views Only)
Auto-resolves resource files matching the view path. Not supported in Blazor.
```cshtml
@* Views/Home/Index.cshtml *@
@inject IViewLocalizer Localizer
@Localizer["Welcome"]
@Localizer["ItemCount", Model.Count]
```text
Resource file location: `Resources/Views/Home/Index.en-US.resx`
### IHtmlLocalizer (MVC Only)
HTML-aware variant that HTML-encodes format arguments but preserves HTML in the resource string itself. Not supported in
Blazor.
```cshtml
@inject IHtmlLocalizer HtmlLocalizer
@* Resource: "Read our terms, {0}" *@
@* {0} is HTML-encoded, the tag is preserved *@