Hendrik Bulens All about .NET development

Injecting resource files as plain JavaScript objects in ASP.NET Core

Localization and internationalization are much-discussed topics and many terrific solutions have been developed to easily create multilingual applications. I would like to introduce a different way of localizing web-based applications. As the title suggests, I will show you how to inject resource files as plain JavaScript objects to the web client. The result is a simple JavaScript object which is globally available to the client. I found this so useful that I did a similar thing for translated content and even the application’s settings (which are stored in a database).

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:

  • Labels.resx
  • Labels.es.resx

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 Startup class.

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 Configure method:

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 all that is needed to get started with converting resource files to JavaScript. See what I meant with unobtrusive?

Converting resource files to JavaScript objects

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:

The 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:

In a nutshell, this class uses ASP.NET Core’s localization system and then converts it into JavaScript object using ServiceStack’s text serializer. There is nothing special happening here: we use the out-of-the box dependency injection container by accepting an instance of 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 resources tag. To create a nicely formatted JavaScript object we wrap the resources into an object of type ResourceGroup. This step will become clearer when you look at the following code sample. The ToJavaScript method is a particular interesting one:

This is the only time I found the use of ExpandoObject appropriate. You can do some really interesting things with it! The ToJavaScript method essentially builds up a JavaScript object and creates a dictionary of resource values per resource file.

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:

On the server…
… in the client
… and 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.


3 comments

Leave a Reply

  • Thank you for this article; it works wonders for me. One thing I might add is that if you use localized view resources then you’ll have to update your path in the tag to match that.

    Suppose this is the “Resources” folder structure:
    |– Resources
    |– Views
    |– SampleView
    |– ViewLabels.es.resx
    |– Labels.es.resx
    |– …

    Then if you want strings from both shared and view resources you will use:

    • Comment again due to me not understanding how WordPress formatting work:

      If your resource file is Resources\Views\SampleView\ViewLabels.es.resx for example, instead of putting only the file name “ViewLabels” in the array for the tag helper you have to use “Views.SampleView.ViewLabels”.

      • Good point. There is certainly room for improvement in the area of resolving the resource file with some kind of identifier, strong type, predicate, .. I should check if ASP.NET Core has new capabilities which one could use to do this.

By Hendrik Bulens
Hendrik Bulens All about .NET development