It doesn't matter if a class derives from Controller.
It is important that your objects are created by the Dependency Injection Container and not by using the new operator, as described here. If you want to use the ASP.NET Core localization mechanism in all your classes, you must adopt this pattern for object creation.
This page gives a good description of how to create objects, but I will try to give an example of how it works with localization.
I have created a class MyHelper. The class expects the localizer object to be passed in to the constructor. It contains a single property Hello, which returns a localized string.
namespace AddingLocalization.Classes
{
public class MyHelper
{
private readonly IStringLocalizer<MyHelper> _localizer;
public MyHelper(IStringLocalizer<MyHelper> localizer)
{
_localizer = localizer;
}
public string Hello
{
get
{
return _localizer["Hello World."];
}
}
}
}
In the ConfigureServices method in the Startup class, I have added the boilerplate code described here and added a line to register the class MyHelper with the Dependency Injection container.
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opts => opts.ResourcesPath = "Resources");
services.AddMvc()
.AddViewLocalization (
LanguageViewLocationExpanderFormat.Suffix,
opts => opts.ResourcesPath = "Resources" )
.AddDataAnnotationsLocalization();
// This line registers the class MyHelper with the
// Dependency Injection Container.
services.AddTransient<MyHelper>();
}
In my controller class, I have added a parameter of type MyHelper to the constructor, which is stored in a member variable.
public class HomeController : Controller
{
private readonly IStringLocalizer<HomeController> _localizer ;
private readonly MyHelper _h ;
public HomeController ( IStringLocalizer<HomeController> localizer,
MyHelper h )
{
_localizer = localizer;
_h = h ;
}
...
public IActionResult About()
{
ViewData["Message"] = _h.Hello ;
return View();
}
...
}
Because the class MyHelper has been registered with the dependency injection container, it creates this object and passes it in to the constructor automatically. This is the magic performed by the dependency injection container.
In the About() method, I fetch the property from the MyHelper object.
That's about it for the code, but I wanted to be certain that it will actually read the string from a resource file.
The naming convention for resource files is described here:
It is based on the full name of the class, without the name of the assembly. In my case class is called AddingLocalization.Classes.MyHelper and the assembly is called AddingLocalization, so the relevant name is Classes.MyHelper.
There are actually two naming conventions, using dots or subdirectories, so we can call the resource file one of
- Classes.MyHelper.resx
- Classes\MyHelper.resx
The boilerplate code in ConfigureServices specified the ResourcesPath "Resources", so this is where we must place the resource file. I chose the second naming option, so my resource file is
- Resources\Classes\MyHelper.resx
as you can see in the solution explorer
We do not need Visual Studio to create a file MyHelper.Designer.cs to access the resources, so we should clear out the CustomTool property for the resource file.
This is important, because the names will not be valid resource names and will probably generate error messages, if we do not disable the custom tool.
(Previous localization methods (from Microsoft) have always used fabricated resource names (e.g. with underscrore instead of space) to access resources. The new ASP.NET core localization uses the original string as the resource name.)
Finally I have defined a resource string as shown below:
I haven't actually tried accessing resources in a different language (yet), but the localizer object did read the resource correctly.
IStringLocalizer
is resolved through ASP.NET Core built-in DI container. You could injectIStringLocalizer
in constuctor in any class which is resolved through DI too. Could you try it? – Plasty