Context
I am currently working on a .net Core 3.1 API that will replace an old .NET Framework and Delphi back-end. The API needs to supports globalization and localization to translate error messages and a few data values.
The localization is passed in through the route for example:
http://localhost/en-US/controller/action/params
. So connected apps can quickly switch from localization.
The API has a Resources
folder with the following files:
Resources:
- SharedResources.resx default and fallback language file nl-NL)
- SharedResources.en-US.resx
- SharedResources.de-DE.resx
In the Startup.cs
I use installers to seperate concerns.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Extensions method that execute the install function on all classes that implement
// IInstaller interface
services.InstallServicesInAssembly(Configuration);
}
}
And I made a specific installer for the localization:
public class LocalizationInstaller : IInstaller
{
public void InstallServices(IServiceCollection services, IConfiguration configuration)
{
var localizationConfig = new LocalizationConfig();
configuration.GetSection(nameof(LocalizationConfig)).Bind(localizationConfig);
services.AddSingleton(localizationConfig);
services.AddLocalization(options => options.ResourcesPath = LocalizationConfig.ResourcePath);
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = LocalizationConfig.GetDefaultRequestCulture();
options.SupportedCultures = LocalizationConfig.GetSupportedCultures();
options.SupportedUICultures = LocalizationConfig.GetSupportedCultures();
options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider { Options = options } };
});
services.Configure<RouteOptions>(options =>
{
options.ConstraintMap.Add("culture", typeof(LanguageRouteConstraint));
});
}
The Data of LocalizationConfig
is from the appsettings.json file.
"LocalizationConfig": {
"ResourcePath": "Resources",
"SupportedCultures": [ "nl-NL", "en-US", "de-DE" ],
"DefaultRequestCulture": "nl-NL"
}
The problem
[HttpGet("{version}/{culture}/Index")]
public IActionResult Index()
{
var culture = $"CurrentCulture{CultureInfo.CurrentCulture.Name},CurrentUICulture{CultureInfo.CurrentUICulture.Name}";
var value = _localizer["HelloWorld"].Value;
return Ok(value);
}
When I make a request to the API with the culture being nl-NL or a random value it returns the default value in the SharedResources.resx like it is supposed to do.
For example:http://localhost/1/nl-NL/Controller/Index
returns Hallo Wereld!
.
But when I make a request with the culture being either en-US or de-DE it still returns the value from the SharedResources.rex
file instead of the SharedResources.en-US.resx
file or SharedResources.de-DE.resx
file
while the culture from my variable var culture
is being set to en-US or de-DE.
Notes
When I name my SharedResoures.en-US.resx
to SharedResources.en.resx
it does seem to work and the application finds the translation files. But this does not solve my issue that I want to specify the region code so that i can support both en-GB and en-US.
The Question
Why can the application find the file without the region code and not the file that does contain the region code?
Microsoft docs: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1