In this article, we are going to learn how to implement JSON Based Localization in ASP.NET Core and club it with Caching to make it even more efficient. In a previous article (Globalization and Localization in ASP.NET Core), we learned the basics of localization where we developed an MVC solution that gives us the option to switch between various languages /cultures making use of RESX files, where we stored the corresponding language strings. But now, let’s use JSON files to store the localized strings and implement middleware to switch languages via language keys in the request header.
You can find the entire source code of this implementation here.
What we’ll build?
We will be building a simple .NET 5.0 WebAPI which returns messages based on the request header’s Accepted Language. Behind the scenes, we will also cache the string via IDistributedCache. The main objective of this implementation is to read the language strings from a JSON file rather than a RESX file. For this, we will be adding in a new implementation for the IStringLocalizer. This will be a pretty straightforward and simple article yet helps a lot in production-ready applications. Who doesn’t want JSON files? :D
It will be as simple as adding 3 new classes and a couple of service registrations. Let’s get started!
Getting started with JSON Based Localization in ASP.NET Core
Open up your favorite IDE (I use Visual Studio 2019 Community), and create a new ASP.NET Core Web API Project. Make sure to select .NET 5.0 Framework (or the latest one at the time of reading this article. Note that .NET 6 LTS is just around the corner!).
To keep this implementation simple, I will not be adding in any additional class libraries. I removed the weather controllers and related files from the WebAPI solution to tidy up the project.
As mentioned earlier, we have two parts to this implementation:
- A Middleware that can determine the language code passed in at the request header by the client (which will be postman in our case).
- An implementation of the IStringLocalizer to support JSON files. I intend to store the JSON file by the locale name (en-US.json) under a Resources folder. Note that we will also use IDistributedCache to make our system more effecient.
Let’s create a new class and name it JsonStringLocalizer.cs
Note that we are implementing the IStringLocalizer interface.
Line #3: we use IDistributedCache here.
Line #27 - 44: GetAllStrings() here we try to read the JSON file name according to the CurrentCulture, and return a list of LocalizedString objects. Note that this list would contain both the key and values of all the entries in the found JSON file. Each of the read JSON values is deserialized.
Line #45 - 59: GetString() this is the function that is responsible for localizing strings. Here too, the file path is determined in accordance with the current culture of the request. If the file exists, a cache key is created with a pretty unique name. Ideally, the system tries to check if any value exists in the cache memory for the corresponding key. If a value is found in the cache, it is returned. Else, the application accesses the JSON file and tries to get and return the found string.
Line #60 - 78: GetValueFromJSON() as the name suggests, this method accepts the property name and file path of the JSON file, which is then opened in Read Mode. If the corresponding property is found within the JSON file, it is returned. Else a null value would be returned.
Line #9 - 16: this[string name] This is the entry method that we would be using in our controller. It accepts a key and tried to find the corresponding values from the JSON file using the previously explained method. It’s important to note that the method would return the same key if there is no value found in the JSON file.
Next, let’s add a Factory class that would be responsible for internally generating the JsonStringLocalizer instance. Name the new class as JsonStringLocalizerFactory.
Next comes the interesting part where we create a Middleware that can read the Accept-Language key from the request header and set the language of the current thread if the culture is valid.
Create a new class and name it LocalizationMiddleware.
Line #5: Here we read the Accept-Language from the request header of the current HTTP context.
Line #8-13: If a valid culture is found, we set the current thread culture.
With that done, let’s add some language files. Create a new folder named Resources and add in 2 new JSON files. We will be naming the JSON files as en-US.json and de-DE.json.
Here is a sample en-US.json
Next,de-DE.json. PS, the following was translated via Google Translate.
As you can see, we have 2 keys, hi and welcome which are meant to be translated by the application depending on the request header.
Now comes the important part where we do the service registrations of our middleware and the JSONLocalizer. Open up Startup.cs and add the following under ConfigureServices method.
Under the Configure method, add in the following. Note that we are defining en-US as the default culture of our application. You can easily make this configurable by moving it to the appsettings as well.
Finally, let’s create a new API Controller to demonstrate the usage of our JSON localizer. Add in a new Controller and name it DemoController.
Line #3-9: Constructor Injection of ILogger and IStringLocalizer instances.
Line #11-16: Here is a simple test where we try to print the localized version of the key ‘hi’ onto the console as well as return it as a response.
Line #17-22: Here, we pass in a random name to this endpoint, and the application is expected to return a localized version of “Welcome xxxx, how are you?“. As simple as that.
Line #23-28: This method would ideally return all the keys and values found in the corresponding JSON file.
Testing with Postman
With that done, let’s fire up Postman and run some basic tests.
Here is what you get as a response when you send a GET request to the /demo endpoint with the Accept-Language as de-DE
Accept-Language is set to en-US. Simple, yeah?
Now, I try to send a GET request to the /demo endpoint along with my name. Accept-Language set to en-US
Accept-Language set to de-DE.
Finally, when you send a GET request to the /demo/all endpoint, you get to see all the key/value pairs of our strings in the JSON file related to the relevant accept language.
Pretty handy to have in your projects, right? That’s a wrap for the article.
Summary
In this article, we learnt a rather simple way to achieve JSON Based Localization in ASP.NET Core applications. Do share this article with your colleagues and dev circles if you found this interesting. You can find the source code of these mentioned implementations here. Thanks!