J18n.Analyzers
1.2.1
dotnet add package J18n.Analyzers --version 1.2.1
NuGet\Install-Package J18n.Analyzers -Version 1.2.1
<PackageReference Include="J18n.Analyzers" Version="1.2.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="J18n.Analyzers" Version="1.2.1" />
<PackageReference Include="J18n.Analyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add J18n.Analyzers --version 1.2.1
#r "nuget: J18n.Analyzers, 1.2.1"
#:package J18n.Analyzers@1.2.1
#addin nuget:?package=J18n.Analyzers&version=1.2.1
#tool nuget:?package=J18n.Analyzers&version=1.2.1
J18n
A JSON-based localization library for .NET that provides a drop-in replacement for resx-based resources, fully compatible with IStringLocalizer<T>
and the Microsoft.Extensions.Localization ecosystem.
Features
- Drop-in replacement for resx resources using JSON files
- Full compatibility with
IStringLocalizer<T>
and Microsoft.Extensions.Localization - Nested JSON support with automatic flattening using dot notation (e.g.,
"User.Profile.Name"
) - Array handling with indexed access (e.g.,
"Messages[0]"
,"Items[1].Name"
) - Culture hierarchy fallback (specific → parent → English)
- Parameterized string formatting using .NET composite format syntax
- Thread-safe operations with built-in caching for optimal performance
- Graceful fallback for missing keys (returns key name)
- Easy dependency injection integration
- Roslyn analyzers for compile-time validation and code fixes
- Comprehensive XML documentation
- Extensive test coverage
Installation
Package | NuGet |
---|---|
J18n | |
J18n.Analyzers | |
J18n.SourceGenerators |
Install the main package via NuGet Package Manager:
dotnet add package J18n
Or via Package Manager Console:
Install-Package J18n
Optional: Roslyn Analyzers
For compile-time validation and code fixes, also install the analyzers package:
dotnet add package J18n.Analyzers
Or via Package Manager Console:
Install-Package J18n.Analyzers
Quick Start
1. Set up JSON resource files
Create JSON files in your Resources directory following the naming convention {ResourceName}.{Culture}.json
:
Resources/
├── Messages.en.json
├── Messages.es.json
├── Messages.fr.json
└── Errors.en.json
Note: Unlike resx files, JSON resource files only need to be set as "Copy to Output Directory" in their build action. They do not need to be embedded resources.
Example Messages.en.json
:
{
"WelcomeMessage": "Welcome to our application!",
"HelloUser": "Hello, {0}!",
"ItemCount": "You have {0:N0} items",
"ValidationError": "The field {0} is required"
}
2. Register services
In your Program.cs
or Startup.cs
:
var builder = WebApplication.CreateBuilder(args);
// Simple registration with default options
builder.Services.AddJsonLocalization();
// Or with custom configuration
builder.Services.AddJsonLocalization(options =>
{
options.ResourcesRelativePath = "Localization/Resources";
});
var app = builder.Build();
3. Use in your application
public class HomeController : ControllerBase
{
private readonly IStringLocalizer<Messages> _localizer;
public HomeController(IStringLocalizer<Messages> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
// Simple string
var welcome = _localizer["WelcomeMessage"];
// Parameterized string
var greeting = _localizer["HelloUser", User.Identity.Name];
// Formatted numbers
var itemCount = _localizer["ItemCount", 1234];
return View(new { welcome, greeting, itemCount });
}
}
Configuration Options
Default Configuration
services.AddJsonLocalization();
This uses:
- Resources directory:
Resources/
(relative to current directory) - Default fallback behavior
Custom Resource Path
services.AddJsonLocalization(options =>
{
options.ResourcesRelativePath = "Localization/Messages";
// or
options.ResourcesPath = "/absolute/path/to/resources";
});
Custom File Provider
var customFileProvider = new PhysicalFileProvider("/custom/path");
services.AddJsonLocalization(customFileProvider, "Resources");
Resource File Format
JSON resource files support both flat key-value pairs and nested object structures. Nested objects are automatically flattened using dot notation for easy access.
{
"WelcomeMessage": "Welcome to our app!",
"User": {
"Profile": {
"Greeting": "Hello, {0}!",
"Settings": {
"Language": "English"
}
}
},
"GoodbyeMessage": "See you later!"
}
Accessing Nested Values
Nested values are accessed using dot notation:
var welcome = localizer["WelcomeMessage"];
// Nested object access
var greeting = localizer["User.Profile.Greeting", "John"];
var language = localizer["User.Profile.Settings.Language"];
var status = localizer["User.Account.Status"];
// Array access with indexes
var firstMessage = localizer["Messages[0]"];
var secondMessage = localizer["Messages[1]"];
Culture Fallback
The library follows standard .NET culture fallback patterns:
- Specific culture (e.g.,
en-US
) - Parent culture (e.g.,
en
) - English as final fallback
- Key name if no translation found
Example with CultureInfo.CurrentUICulture = new CultureInfo("es-MX")
:
Resources/
├── Messages.es-MX.json ← First choice
├── Messages.es.json ← Second choice
├── Messages.en.json ← Third choice
└── Messages.json ← Final fallback
Advanced Usage
Getting All Strings
var allStrings = localizer.GetAllStrings(includeParentCultures: true);
foreach (var localizedString in allStrings)
{
Console.WriteLine($"{localizedString.Name}: {localizedString.Value}");
}
Checking if Resource was Found
var localized = localizer["SomeKey"];
if (localized.ResourceNotFound)
{
// Handle missing translation
Console.WriteLine($"Missing translation for key: {localized.Name}");
}
Using with Dependency Injection
public class EmailService
{
private readonly IStringLocalizer<EmailService> _localizer;
public EmailService(IStringLocalizer<EmailService> localizer)
{
_localizer = localizer;
}
public async Task SendWelcomeEmailAsync(string email, string name)
{
var subject = _localizer["WelcomeEmailSubject"];
var body = _localizer["WelcomeEmailBody", name];
await SendEmailAsync(email, subject, body);
}
}
Performance Considerations
- Resources are cached after first load for optimal performance
- Thread-safe operations allow concurrent access
- Lazy loading - resources loaded only when first accessed
- Memory efficient - shares resources across localizer instances
Source Generators (J18n.SourceGenerator)
The J18n.SourceGenerators package provides compile-time code generation for strongly-typed access to your JSON localization keys.
Features
- Strongly-typed access: Generates classes with properties for each localization key
- Compile-time safety: Eliminates runtime string key errors
Setup
Install the source generator package:
dotnet add package J18n.SourceGenerator
Include your JSON localization files as
AdditionalFiles
in your project:<ItemGroup> <AdditionalFiles Include="Resources/**/*.json" /> </ItemGroup>
Use the generated strongly-typed classes:
// Instead of: _localizer["WelcomeMessage"] // Use: _localizer[Messages.WelcomeMessage] var welcome = _localizer[Messages.WelcomeMessage]; var greeting = _localizer[Messages.User.Profile.Greeting, "John"];
Roslyn Analyzers (J18n.Analyzers)
The J18n.Analyzers package provides compile-time validation and code fixes for your JSON localization keys.
Features
- Missing Key Detection (LOC001): Identifies localization keys referenced in code but missing from JSON files
- Unused Key Detection (LOC002): Finds keys defined in JSON files but never used in code
- Partial Missing Keys (LOC003): Detects keys missing in some cultures but present in others
- Duplicate Key Detection (LOC004): Identifies duplicate keys within the same JSON file
- Code Fixes: Automatic suggestions for missing keys with nearest matches
Setup
Install the analyzer package:
dotnet add package J18n.Analyzers
Include your JSON localization files as
AdditionalFiles
in your project:<ItemGroup> <AdditionalFiles Include="Resources/**/*.json" /> </ItemGroup>
Diagnostic Rules
Rule | Severity | Description |
---|---|---|
LOC001 | Error | Referenced localization key not found in any culture |
LOC002 | Warning | Localization key defined but never used |
LOC003 | Warning | Key missing in some cultures but present in others |
LOC004 | Error | Duplicate key definition in the same JSON file |
Compatibility
- .NET 9.0 and later
- Microsoft.Extensions.Localization 9.0.8
- System.Text.Json for JSON parsing
- Full compatibility with existing
IStringLocalizer<T>
implementations
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Testing
Run the test suite:
dotnet test
The project includes comprehensive tests covering:
- Basic localization functionality
- Culture fallback scenarios
- Parameterized strings
- Error handling
- Dependency injection integration
License
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 4.14.0)
- System.Text.Json (>= 9.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.