J18n 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package J18n --version 1.0.0
                    
NuGet\Install-Package J18n -Version 1.0.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="J18n" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="J18n" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="J18n" />
                    
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 J18n --version 1.0.0
                    
#r "nuget: J18n, 1.0.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 J18n@1.0.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=J18n&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=J18n&version=1.0.0
                    
Install as a Cake Tool

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
  • 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
  • Comprehensive XML documentation
  • Extensive test coverage

Installation

Install the package via NuGet Package Manager:

dotnet add package J18n

Or via Package Manager Console:

Install-Package J18n

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 should contain key-value pairs where values can include .NET composite format placeholders:

{
  "SimpleMessage": "Hello World",
  "ParameterizedMessage": "Hello, {0}!",
  "MultipleParameters": "User {0} has {1} items",
  "FormattedNumber": "Price: {0:C}",
  "FormattedDate": "Today is {0:yyyy-MM-dd}",
  "SpecialCharacters": "Café, naïve, résumé",
  "LongText": "This is a longer message that can span multiple lines and contain complex formatting."
}

Culture Fallback

The library follows standard .NET culture fallback patterns:

  1. Specific culture (e.g., en-US)
  2. Parent culture (e.g., en)
  3. English as final fallback
  4. 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

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

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. 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.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.1 170 8/24/2025
1.2.0 108 8/24/2025
1.1.1 48 8/23/2025
1.1.0 45 8/23/2025
1.0.0 94 8/22/2025