View on GitHub
Clean Architecture Toolkit for .NET
Clean Architecture Toolkit is a clean, modular architecture foundation for .NET applications.
It embraces SOLID principles and focuses on maintainability, testability, and scalability through clear boundaries and pluggable design.

|   HOME   |   MODULE OVERVIEW   |   DEMO   |

Cat.Localizations

Cat.Localizations defines a contract for looking up localized strings by key, so the rest of your app doesn’t need to know which localization provider sits behind it.

The module ships with a no-op implementation that returns the key as-is, with placeholders filled in. It’s a safe default, and handy in tests. Plug in your own ICatLocalizer backed by resource files, a translation service, or whatever fits your app, when you need real localization.

Table of contents

NuGet packages

NuGet Version

Package Role Install Downloads
Cat.Localizations.Abstractions Contracts dotnet add package gmarginet.Cat.Localizations.Abstractions NuGet Downloads
Cat.Localizations Implementation dotnet add package gmarginet.Cat.Localizations NuGet Downloads

Namespaces

Namespace What it holds
Cat.Localizations.Abstractions The ICatLocalizer interface.
Cat.Localizations The no-op localizer and the module registration.

Dependencies

Module Why Cat.Localizations needs it
Cat.Extensions Small helpers for service registration.

Usage

Register the module

Call AddCatNoLocalizationLocalizer to register ICatLocalizer as a singleton, backed by the no-op implementation.

using Cat.Localizations.Extensions;

services.AddCatNoLocalizationLocalizer();

Look up a string

Resolve the localizer and use its indexers. One takes a key. The other takes a key and the values for its placeholders.

using Cat.Localizations.Abstractions;

var localizer = serviceProvider.GetRequiredService<ICatLocalizer>();

var title = localizer["Order.Title"];
var message = localizer["Order.Created", orderId];

The no-op implementation returns the key itself. It only fills in placeholders when the key contains them, in the order of the arguments:

localizer["Order.Title"];                              // "Order.Title"
localizer["Order {OrderId} was created", 42];          // "Order 42 was created"

Inject the localizer into the classes that need text:

public class OrderMessages
{
    private readonly ICatLocalizer _localizer;

    public OrderMessages(ICatLocalizer localizer)
    {
        _localizer = localizer;
    }

    public string Created(int orderId) => _localizer["Order.Created", orderId];
}

Write your own localizer

Implement ICatLocalizer and register it instead of the no-op one. Fill the placeholders of the localized text from arguments, in order.

using Cat.Localizations.Abstractions;
using Cat.String.Extensions;

public class ResourceCatLocalizer : ICatLocalizer
{
    private readonly IStringProvider _stringProvider;

    public ResourceCatLocalizer(IStringProvider stringProvider)
    {
        _stringProvider = stringProvider;
    }

    public string this[string key] => _stringProvider.Get(key) ?? key;

    public string this[string key, params object[] arguments] => this[key].NamedFormat(arguments);
}

services.AddSingleton<ICatLocalizer, ResourceCatLocalizer>();

Errors and exceptions

The contract doesn’t define errors. A localizer returns a string for every key, and it doesn’t use responses.

Situation What you get
The no-op localizer gets any key The key itself. It never fails on an unknown key.
The key has more placeholders than arguments A FormatException from the no-op localizer.
The key has fewer placeholders than arguments The extra arguments are ignored.
ICatLocalizer isn’t registered An InvalidOperationException from the service provider when you resolve it.

What your own localizer does for a missing key is up to you. Returning the key, as in the example, makes a missing translation easy to spot in the UI.