VolocyNazad.ResxAnalyzer 1.2.0

dotnet add package VolocyNazad.ResxAnalyzer --version 1.2.0
                    
NuGet\Install-Package VolocyNazad.ResxAnalyzer -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="VolocyNazad.ResxAnalyzer" Version="1.2.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="VolocyNazad.ResxAnalyzer" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="VolocyNazad.ResxAnalyzer">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add VolocyNazad.ResxAnalyzer --version 1.2.0
                    
#r "nuget: VolocyNazad.ResxAnalyzer, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package VolocyNazad.ResxAnalyzer@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=VolocyNazad.ResxAnalyzer&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=VolocyNazad.ResxAnalyzer&version=1.2.0
                    
Install as a Cake Tool

Toolkit.ResxAnalyzer

NuGet GitHub release GitHub license build-and-test.yml

A Roslyn analyzer that warns at build time about incomplete or broken .resx resource tables: a culture-specific satellite file (Strings.ru.resx, Strings.de.resx, ...) missing a key from the neutral file (Strings.resx) of the same group, a satellite with a key the neutral file no longer has, a key declared twice in one file, a translation whose {0}/{1}/... format placeholders don't match the neutral value's, a translation that's empty, a resource group that is missing a satellite file entirely for a culture that other resource groups in the project do have, a satellite file that has no neutral file of its own at all, or (opt-in) a resource key that does not match a configured naming convention. See Diagnostics below for the full list (RESX001-RESX008).

The check works on the .resx files themselves, so it applies no matter how the resources are consumed at runtime - ResourceManager, Microsoft.Extensions.Localization.IStringLocalizer, a generated strongly-typed accessor, or anything else.

Installation

  • Grab the latest package on NuGet.
  • Reference it as an analyzer-only, build-time dependency:
<ItemGroup>
  <PackageReference Include="VolocyNazad.ResxAnalyzer" Version="x.y.z">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
</ItemGroup>

No further setup is required: the package automatically exposes every .resx EmbeddedResource item in the referencing project to the analyzer.

How resource groups are matched

Files are grouped by their path with the trailing culture segment removed. Strings.resx is the neutral file of the group; Strings.ru.resx, Strings.pt-BR.resx, Strings.zh-Hans.resx, etc. are its culture-specific satellites, matched by parsing the segment before .resx as a CultureInfo name. A group without a neutral file (no plain <Name>.resx) is skipped for RESX001/RESX002/RESX004/RESX005, since there is then no key set to treat as canonical - it is reported by RESX007 instead. RESX003 (duplicate key in one file) is checked per file and does not depend on grouping, so it still applies even to a satellite file with no matching neutral file. RESX006 also does not depend on a group having a neutral file - it compares which cultures each group has satellites for.

Basic usage

Given:

Strings.resx      Greeting, Farewell
Strings.ru.resx    Greeting

building the project reports:

warning RESX001: Resource key 'Farewell' defined in 'Strings.resx' is missing in 'Strings.ru.resx'

That's one example (RESX001); the other diagnostics fire the same way, as ordinary build warnings, whenever their condition is met - see Diagnostics.

Diagnostics

RESX001

A resource key defined in a group's neutral .resx file is missing from one of its culture-specific satellite .resx files.

RESX002

A culture-specific satellite .resx file declares a key that does not exist in the group's neutral .resx file - typically a stale translation left behind after the key was renamed or removed.

RESX003

The same resource key is declared more than once within a single .resx file. Checked independently of resource grouping, so it also catches a broken satellite file that has no matching neutral file.

RESX004

A translation's {0}, {1}, ... format placeholders don't match the neutral value's placeholders (order doesn't matter, but the set of indices must). This is the most common cause of a FormatException at runtime after a translation edit. Escaped braces ({{/}}) are not treated as placeholders.

RESX005

A translation value is empty or contains only whitespace - the key exists in the satellite file but was never actually translated. Only checked for satellite files, not the neutral file itself.

RESX006

A resource group has no satellite .resx file for a culture that at least one other resource group in the project does have - for example, Strings.ru.resx exists but Errors.ru.resx doesn't. The set of "required" cultures is inferred automatically as the union of every culture used anywhere in the project; there is no configuration for it. Reported once per missing group/culture combination, not tied to a specific file (there is no missing file to point at).

RESX007

A culture-specific satellite .resx file exists (for example Strings.ru.resx), but its group has no neutral file (Strings.resx) at all. Reported against the orphaned satellite file itself. Unlike RESX006, this does not depend on any other resource group - a single stray satellite with no neutral counterpart is enough. RESX001/RESX002/RESX004/RESX005 never run for such a group, since there is no neutral key set to compare against; RESX003 (duplicate keys) still runs independently, since it doesn't need one.

RESX008

A resource key's name does not match a configured naming convention. This rule is opt-in and does nothing unless a convention is configured - it is the only diagnostic controlled by .editorconfig rather than firing unconditionally. Configure it under a [*.resx] section:

[*.resx]
resx_analyzer.key_naming_convention = PascalCase

Supported values for resx_analyzer.key_naming_convention:

  • PascalCase - e.g. SaveButtonText.
  • camelCase - e.g. saveButtonText.
  • snake_case - e.g. save_button_text.
  • kebab-case - e.g. save-button-text.
  • hierarchical - the key is split on a separator (. by default, configurable via resx_analyzer.key_naming_hierarchical_separator) and each segment is checked against a sub-convention (PascalCase by default, configurable via resx_analyzer.key_naming_hierarchical_segment_convention) - e.g. Login.SaveButton.Text.
  • custom (alias regex) - the key must fully match a pattern supplied via resx_analyzer.key_naming_regex.

An unrecognized or missing value leaves the rule disabled - nothing is checked. Checked against every group's neutral file (and, since there is no neutral file to prefer, against orphaned satellites reported by RESX007 as well), so each key is validated once regardless of how many satellites exist.

Development documentation

Contributing

Read CONTRIBUTING.md before submitting changes.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 123 9/21/2026
1.1.0 136 9/18/2026
1.0.1 91 9/18/2026