Persiltech.Localizer
1.0.2
dotnet add package Persiltech.Localizer --version 1.0.2
NuGet\Install-Package Persiltech.Localizer -Version 1.0.2
<PackageReference Include="Persiltech.Localizer" Version="1.0.2" />
<PackageVersion Include="Persiltech.Localizer" Version="1.0.2" />
<PackageReference Include="Persiltech.Localizer" />
paket add Persiltech.Localizer --version 1.0.2
#r "nuget: Persiltech.Localizer, 1.0.2"
#:package Persiltech.Localizer@1.0.2
#addin nuget:?package=Persiltech.Localizer&version=1.0.2
#tool nuget:?package=Persiltech.Localizer&version=1.0.2
Persiltech.Localizer
A simple tool for localizing .NET projects: strongly typed access to .resx resource files,
resolved from the current UI culture — or from a culture you pass in explicitly.
Installation
dotnet add package Persiltech.Localizer
The contract
namespace Persiltech.Localizer;
public class LocalizationUtils<TEntity>
{
public static string GetValue(string field);
public static string GetValue(string field, CultureInfo cultureinfo);
}
public class CultureScope : IDisposable
{
public CultureScope(CultureInfo culture);
public void Dispose();
}
TEntity is a marker: it is never instantiated. Its name is what selects the resource
files, and the localizer built for it is cached in a static field, so it is not rebuilt on
every lookup.
A key with no translation returns the key itself. That is how IStringLocalizer reports a
missing entry, and this package neither throws nor substitutes a value of its own.
Usage
First, create the resource files. Each file name must follow the format
{Extractor}.{Culture}.resx, where:
- Extractor — the name of the class used to read the file, for example
Messages - Culture — the culture identifier, for example
en-USores-PE
So a class named Messages reads from:
Messages.en-US.resx(English, United States)Messages.es-PE.resx(Spanish, Peru)
In each file, create an entry with the same key and the value in the corresponding language:
| Name | Value (en-US) |
Value (es-PE) |
|---|---|---|
Hello |
Hello World! |
¡Hola Mundo! |
Then create the class that exposes each key:
using Persiltech.Localizer;
public class Messages
{
public static string Hello =>
LocalizationUtils<Messages>.GetValue(nameof(Hello));
}
And use it. The value follows the UI culture of the thread:
using System.Globalization;
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
Console.WriteLine(Messages.Hello); // Hello World!
Thread.CurrentThread.CurrentUICulture = new CultureInfo("es-PE");
Console.WriteLine(Messages.Hello); // ¡Hola Mundo!
Reading one value in another culture
When you need a single value in a specific culture without disturbing the thread, pass the
culture in. It is applied through a CultureScope, which restores the previous culture
afterwards — even if the call throws:
var greeting = LocalizationUtils<Messages>.GetValue(
nameof(Messages.Hello), new CultureInfo("es-PE"));
CultureScope is public, so you can use it directly to run a whole block under one culture:
using (new CultureScope(new CultureInfo("es-PE")))
{
// Everything in here sees es-PE, on this thread.
}
In an ASP.NET Core application
Configure the localization middleware so the UI culture is set per request:
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
string[] supportedCultures = ["en-US", "es-PE"];
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
Add it to the pipeline:
app.UseRequestLocalization();
And read the values as usual:
app.MapGet("/localizer/message", () => Results.Ok(Messages.Hello));
The value then follows the culture negotiated for each request, so the same endpoint answers
Hello World! to Accept-Language: en-US and ¡Hola Mundo! to Accept-Language: es-PE.
Design decisions
- Resource files are matched by the name of
TEntity, following the{Extractor}.{Culture}.resxconvention. - The localizer is built once per closed generic type and cached statically.
- A missing key returns the key itself, rather than throwing or substituting a placeholder.
CultureScopechanges bothCurrentCultureandCurrentUICulture, and restores both.
Out of scope
- Dependency injection registration: access is static, so there is nothing to register.
- The ASP.NET Core localization middleware, which belongs to the consuming application.
- Creating or writing resource files. This package only reads.
Compatibility
net10.0
Version history
The source code is not public, so this is the package's change log.
| Version | Changes |
|---|---|
| 1.0.2 | The package moves to its own repository and solution, out of the shared Persiltech monorepo. The project website now points to its portfolio page. The real licence text ships inside the .nupkg instead of an SPDX expression. The public surface is documented with XML comments, so IntelliSense works for consumers. No change to the public API. |
| 1.0.0 – 1.0.1 | Initial releases of LocalizationUtils<TEntity> and CultureScope. |
The public surface has not changed since 1.0.0: everything published so far fixes packaging
and documentation, never the contract. Updating is always safe.
Support
The source code of this package is not public. For questions, bug reports or feature requests, use the package page.
Support the development
If this package saves you work, you can support its maintenance on GitHub Sponsors.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Microsoft.Extensions.Localization (>= 10.0.9)
NuGet packages (9)
Showing the top 5 NuGet packages that depend on Persiltech.Localizer:
| Package | Downloads |
|---|---|
|
Persiltech.Result
An Result pattern implementation |
|
|
Persiltech.Exceptions
Custom exceptions with their respective handlers |
|
|
Persiltech.Membership.Shared
Contains basic classes and interfaces for use in backend and frontend membership projects. |
|
|
Persiltech.Mail.MailKit.Sender
An implementation of MailKit (a popular Mail library) |
|
|
Persiltech.DomainValidation
Una biblioteca .NET para validación de reglas de negocio en aplicaciones que implementan Clean Architecture, desarrollada durante el entrenamiento "Introducción a Clean Architecture en aplicaciones .NET" impartido por Miguel Muñoz Serafín. |
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.0.2
- The package moves to its own repository and solution, out of the shared Persiltech monorepo
- The project website now points to the portfolio page, where the package is documented
- The real licence text ships inside the .nupkg instead of an SPDX expression
- The public surface is documented with XML comments, so IntelliSense works for consumers