Skip to content →

Globalization in ASP.NET Core MVC and Elasticsearch

In today’s technological age, companies can sell their products to people in different cities through e-commerce websites. The topic of “globalization” is important for companies who want to sell their products in a wider area and sell them in different countries.

In this arcticle, I will try to describe how we can provide globalization in ASP.NET Core MVC and Elasticsearch.

1) Globalization in ASP.NET Core MVC

Let’s take a look at how we can perform globalization in ASP.NET Core MVC after the small intro about the importance of globalization. As for globalization topic, ASP.NET Core provides us with the middleware and services we need, to be able to apply localization in our applications for different “languages” and “cultures” info.

There are three main steps to follow when applying localization:

  1. Make application content “localizable”.
  2. We need to have localized “resource” files.
  3. We need to configure and define an “implementation strategy”.

First, we will take a look how we can make the application content localizable.

NOTE: I will use “ASP.NET Core Web App (Model-View-Controller)” template as a sample. “dotnet new mvc

1) Make application content “localizable”

Actually, localizer is similar to the “.resx” resource files in ASP.NET. If we remember, we were adding a “.resx” resource file for each culture supported in the application. Then we were getting localized content by accessing “Resources.Name“.

In ASP.NET Core, there are two abstractions to get localized content instead of using the “Resources.Name” approach. “IStringLocalizer” and “IStringLocalizer

For example:

Can you see the use of Localizer? We set the content in the localizer instead of a key. The most important thing is if localized content cannot be found, then the localizer will use the content which we was set as a resource. Thus we don’t need to create a resource for the main culture. Actually, I can’t say I like it so much, because I’m obsessive about the “magic strings” when I do code reviews. 🙂

NOTE: For HTML content, there are also “IHtmlLocalizer” and “IHtmlLocalizer” types.

We can also use “IStringLocalizerFactory” to create a different type of localizer.

For example, we can use access to a “shared resource”, for example:

We can create a localizer for the requested resource with the “Create” method in the factory.

To localization of Views, we have an “IViewLocalizer” as a service. “ViewLocalizer” implements the “IHtmlLocalizer“. At this point, Razor does not HTML-encode the localized string except for parameters.

Using of the “IViewLocalizer“:

and the result:

We see that Razor did not HTML-encode the localized string except for the parameters.

We have seen how we can localize the views in the simplest way. Now let’s look at the localization of data annotations. At this point it is very simple. Data annotations in ASP.NET Core are already localized with “IStringLocalizer“.


2) We need to have localized “resource” files

In fact, as I mentioned at the beginning of this article, localized resource files are the same as a “.resx” resource files in ASP.NET. We can add a resource file in Visual Studio as shown below:

NOTE: Currently we can not add a resource files in Visual Studio Code and Visual Studio for MAC. 🙁

At this point, one of the important topics is the naming of resource files.

The localizers that we use in both classes and views can access to localized resource in two different ways.

  1. Fully-qualified class names. E.g: “Controllers.TodoController.en-US.resx” – “Views.Todo.Index-en-US.resx
  2. Folder structures. E.g: “Resources/Controllers/TodoController.en-US.resx” – “Resources/Views/Todo/Index.en-US.resx”

We can choose either of these methods.

3) Configuration and Implementation Strategy

So far, we have looked at how we can localize content in an application. Now, we will look at how we can configure and add localization services in an application.

First, we can specify the path of the resource files, in the Startup class as shown below.

NOTE: If we can not specify a path, localization service will look at the root folder of the application for resource files.

We need to add view localization service to the service collection to enable localization of views.

If we want to create views based on cultures separately instead of creating resource files, it is possible with the “LanguageViewLocationExpanderFormat” parameter.

LanguageViewLocationExpanderFormat” enum has the “SubFolder” and “Suffix” values.

  • Suffix: “Todo.en-US.cshtml
  • SubFolder: “en-US/Todo.cshtml

For data annotations, we can provide localization using the “AddDataAnnotationsLocalization” method.

Also if we want to use a shared resource for data annotations, we need to configure the data annotation localizer.

Another important piece of middleware that we need to add for the “Configure” method is Request Localization middleware.

Here we can specify supported languages and default culture info in the application.

Now let’s look at the last part of the localization. Request localization middleware has 3 default options to select current culture.

  1. QueryStringRequestCultureProvider
    QueryStringRequestCultureProvider” is the first provider in “RequestCultureProvider“. It provides localization with query string. E.g: “http://localhost:5000/?culture=en-US
  2. CookieRequestCultureProvider
    CookieRequestCultureProvider” is a good option for tracking the user’s selected culture.
  3. AcceptLanguageHeaderRequestCultureProvider
    AcceptLanguageHeaderRequestCultureProvider” determines the culture information of a request via the value of the Accept-Language header.

There is an optional provider called “RouteDataRequestCultureProvider” that we can use. However, localization is possible via routing. E.g: “http://localhost:5000/en-US/home

To achieve this:

We grabbed the culture information before the localization middleware works by using the “MapMiddlewareRoute” method. The reason is the localization middleware works before the MVC router. So we inserted the “RouteDataRequestCultureProvider” provider be the first request culture provider. Then we added the culture info in the route template. With this configuration, the localization will be applied with the culture info from the route.

NOTE: I will share a sample project that contains localization implementations.

2) Globalization in Elasticsearch

We will provide multi-language support with creating indices for each culture separately. At this point, there are a few different methods. For example, it is possible to provide multi-language support with multi-fields on a single index. Providing multi-language support by creating different indices will make it easier to add different culture info in the future easily. In addition, it will also easy to configure the analyzers for each language. (I used it like this before)

Anyway, let’s implement NEST library in our ASP.NET Core MVC sample. First, create an interface called “IProductService“.

We will create an index using the “CreateIndexAsync” method, and feed products to an index which we will create with “IndexAsync” method. Then based on the culture info requested by the user, we will perform the search operation with the “SearchAsync” method.

Now let’s implement “IProductService” interface as shown below.

Using the “IndexAsync” method, we have created an index name called “products_ {langCode}“, and we will feed products to this index. With the “SearchAsync” method, we will perform a full-text search in the fields “Name” and “Description” with the user’s requested culture info.

Let’s create a controller as an example:

We will create an index for the Turkish and English cultures in the “Index” method of the controller, and we will index the products. In the “Products” action, we will provide product search operation with the user’s requested culture.

Create a view for the “Products” action as shown below.

For testing, let’s run an Elasticsearch as a single-node on the Docker.

Finally, in the “Startup” class, perform the injection operation to the service collection of the “ProductService” and “ConnectionSettings” classes as shown below.

That’s all.

Now let’s run the project with the command “dotnet run“. Then open the URL “http://localhost:5000/tr-TR/home“. Thus, product index will be created, and the products will be indexed.

Now let’s test it with the URL “http://localhost:5000/tr-TR/home/products?keyword=Cep Telefonu” and see the result.

If we look at the response, we can see that the resources were localized based on the culture and the product results were searched in the “products_tr” index.

Also, change the culture to “en-US” and the keyword to “mobile” and let’s see the response again. So the URL: “http://localhost:5000/en-US/home/products?keyword=Cell Phone

Now, the resources were localized with the “en-US” culture, and the product results were searched in the “products_en” index.

Here is a sample project:


Bu makale toplam (1438) kez okunmuştur.


Published in ASP.NET Core Search Engine


  1. Emre Emre

    Böyle kaliteli Türkçe kaynaklar için çok teşekkür ederim

Leave a Reply

Your email address will not be published. Required fields are marked *