I'm making a ASP.NET Core 1.1 app and trying to setup localization.
When I make on my ValuesController
the implementation of IStringLocalizer
it works fine and localize my resource file.
public ValuesController(IStringLocalizer<ValuesController> localizer, IService<BaseEntity> service)
{
_localizer = localizer;
_service = service;
}
The code above locate my resources at "Resources/Controllers/ValuesController.en-US.resx".
But, when I try to inject the IStringLocalizer
with a generic service it can't find my resource file.
public class Service<T> : IService<T>
where T : BaseEntity
{
#region Properties
protected IRepository Repository { get; set; }
protected IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
private readonly ILogger _logger;
private readonly IStringLocalizer _localizer;
#endregion
#region Ctor
public Service(IRepository repository, IUnitOfWorkFactory unitOfWorkFactory,
ILogger<Service<T>> logger, IStringLocalizer<Service<T>> localizer)
{
Repository = repository;
UnitOfWorkFactory = unitOfWorkFactory;
_logger = logger;
_localizer = localizer;
}
}
The code above doesn't locate my resource at "Resources/Services/Base/Service.en-US.resx"
Any idea on how to do it ?
--- EDIT
MyControl.Api (Startup.cs)
namespace MyControl.Api
services.AddLocalization(options => options.ResourcesPath = "Resources");
This line is inside "MyControl.Api", with is in the namespace "MyControl.Api".
The resources folder in this aplication work for "Resources/Controllers"
My services are in namespace "MyControl.Services"
The resources folder in this Project (two projects inside same solution) are
"Resources/Services/Base"
The namespace of my service file is "MyControl.Services.Services.Base"
Explanation
You're right, the problem is in generic class. Accordingly to the source code of ResourceManagerStringLocalizer
(it's default IStringLocalizer
implementation) - that class contains _resourceBaseName
private field. The same string also is used to locate resource files as a search path parameter in ResourceManager
class.
When IStringLocalizer
is injected into a closed generic type instance, this field is set incorrectly with something like:
FooProject.Resources.Services.FooService`1[[System.Double, System.Private.CoreLib...
Instead of correct one:
FooProject.Resources.Services.FooService
You can check the localizer _resourceBaseName
value in debugger. It's probably a bug and you would open an issue about it on GitHub: https://github.com/aspnet/Localization/issues.
Workaround
It is possible to create a ResourceManagerStringLocalizer
instance manually. We should take this baseName
part from a class full name without a csproj-file name and without a class name itself:
Full class name:
MyCsprojFileName.AnyFolder.SubFolder.FooClass
baseName
:
AnyFolder.SubFolder
For the code you provided baseName
is probably "Services.Base"
.
Let's write some code to get it in generic way:
public class FooService<T>
{
private readonly IStringLocalizerFactory _factory;
public FooService(IStringLocalizerFactory factory)
{
_factory = factory;
}
public IStringLocalizer GetLocalizer()
{
var type = typeof(FooService<>);
string assemblyName = type.GetTypeInfo().Assembly.GetName().Name;
string typeName = type.Name.Remove(type.Name.IndexOf('`'));
string baseName = (type.Namespace + "." + typeName).Substring(assemblyName.Length).Trim('.');
var localizer = _factory.Create(baseName, assemblyName);
return localizer;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With