dotnet-resx

The preset for .NET. It reads .resx resources, IStringLocalizer lookups in C#, Razor and Blazor, and strongly typed Resources.Key access.

The dotnet-resx preset supports .NET localization with .resx resource files: ASP.NET Core MVC and Razor Pages, Blazor, and desktop apps with a generated Resources class.

Detection

The preset applies when the project has a *.csproj, *.vbproj or *.fsproj file and a *.resx file.

x18n.config.ts
import { defineConfig } from '@x18n/core'

export default defineConfig({
  presets: ['dotnet-resx'],
})

Locale files

The preset finds every *.resx file outside bin, obj and node_modules. The resx format reads the string <data> entries and writes edits in place. It keeps the schema, the headers, comments and the entries that hold files or images. x18n does not write a string under the name of such an entry, because two <data> with one name break the build. Keys stay flat, so a key can contain dots.

As in .NET satellite assemblies, Name.<culture>.resx holds a locale only when Name.resx exists. Every other file holds the source locale, so Views.Shared.Nav.resx is not the locale Nav. With the default sourceLocale: 'en', these files give the locales en, de and pt-BR:

Resources/SharedResource.resx
<data name="Hello" xml:space="preserve">
  <value>Hello {0}</value>
</data>
Resources/SharedResource.de.resx
<data name="Hello" xml:space="preserve">
  <value>Hallo {0}</value>
</data>

To translate into a new locale, x18n creates the file next to the source file: SharedResource.fr.resx. If your neutral language is not English, set sourceLocale.

The keys of all .resx files share one key space, as IStringLocalizer<SharedResource> does not show in the key. Two files with the same key, such as Views/Home/Index.resx and Views/About/Index.resx, give a key-conflict. So do two keys where one is the start of the other, such as Nav and Nav.Home.

Supported syntax

In .cs, .cshtml and .razor files, the preset reads:

  • an indexer on a localizer: Localizer["Hello"], @Localizer["Hello"], _localizer["Hello"], HtmlLocalizer["Hello"], L["Hello"] and Loc["Hello"]
  • localizer.GetString("Hello") and localizer.GetHtml("Hello")
  • the generated designer class: Resources.Hello and Properties.Resources.Hello

The key is the whole string, so a key can be the source text: Localizer["Save changes"].

Views/Home/Index.cshtml
@inject IViewLocalizer Localizer
<h1>@Localizer["Hello", Model.Name]</h1>
Controllers/HomeController.cs
ViewData["Title"] = _localizer["Hello"];

The preset does not read [Display(Name = "...")] and other data annotations, or strongly typed classes with other names than Resources.

Placeholders

Composite format items: {0}, {0:C}, {0:N2}, {0,-10} and {name}. {{ and }} are literal braces, not placeholders.

Extraction templates

FilesTemplate
**/*.cshtml, **/*.razor@Localizer["{key}"]
**/*.cs_localizer["{key}"]