The main reason why I use this approach myself is because it is simple and unobtrusive: there is no need to dig deep into your application to make it work with a internationalization framework. An added advantage is that requests can be cached, which improves the performance. It is even possible to return only a subset of resources, depending on the security levels of the user making the request.
The original solution was made back in 2015 for a ASP.NET MVC 5 solution. However in this post I will apply the same ideas for an ASP.NET Core application. All source code can be found on GitHub.
Creating the application
Create a new ASP.NET Core application. It doesn’t matter which type you choose, I suggest you go for
dotnet new razor or
dotnet new webapp.
Run the following commands in the project’s folder:
dotnet add package ServiceStack.Text.Core -s https://api.nuget.org/v3/index.json dotnet add package Microsoft.AspNetCore.Razor -s https://api.nuget.org/v3/index.json
It’s time to add some resources to the application. Create a folder named ‘Resources’ and add two resource files:
Note: You can optionally add
PublicResXFileCodeGenerator to the custom tool property of the Labels.resx file. This won’t have any effect on the end result though.
Add some entries to both files and you’re done. Now we have everything to get started with configuring the
Configuring the application
ASP.NET Core has a wonderful built-in localization mechanism so we are going to use that to retrieve the resources. Modify the
ConfigureServices method so it looks something like this:
The only line that matters now is this one:
Similar story with the
In real life you’ll probably want to use the authenticated user’s culture (using a setting he can configure himself) but that’s out of scope of this post. Now we’ll just set the default culture to Spanish.
This is where the fun starts. With ASP.NET Core’s tag helpers, you can decide on a view-per-view basis if the resource files are required or not:
names attribute of the
resources tag is an array of resource file (or class) names. Here we only have one item named "Labels" which will be mapped to the Labels resource file in the web project.
Now we have to make sure there is a tag helper for the
resources tag. Besides obviously adding code, don’t forget to modify the
_ViewImports partial view with an extra
@addTagHelper with the namespace and assembly in which you create this class.
The next code sample is where all the magic happens:
IStringLocalizerFactory in the constructor, which is used to fetch the resources from the list of resource names that you passed in the
names attribute of the
ResourceGroup. This step will become clearer when you look at the following code sample. The
This is the only time I found the use of
ExpandoObject appropriate. You can do some really interesting things with it! The
In the client, the resources will be available under one root variable named "Resources". Depending on the amount of resource files you declared in the tag helper, the Resources object will have a variable number of properties. In this example, the Resources object will have just one property named "Labels". The Labels object is very similar to the server-side Labels class. You can access the resource by its name and the value will be returned.
Let’s say this is how the Resources folder looks like:
|-- Resources |-- Labels |-- HelloWorld: Hello world! |-- GoodbyeWorld: Goodbye world! |-- ...
If you want to have the GoodbyeWorld resource, simply enter
Resources.Labels.GoodbyeWorld and you will receive the (localized) value. See for yourself if you enter
Resources in the console:
All subsequent scripts will have access to this variable. You could feed this data into a library or you could the object directly, it’s all up to you!
If you use ‘standard’ ASP.NET then I wouldn’t recommend this approach. However when you use very little of the framework to generate the GUI, this may be useful. It may not be the most elegant solution but it is one that works, and with some careful redesigning it can be made into something beautiful.