CodeDigest.Com Logo
Featured:

Create Multi Language WebSite in Asp.Net MVC – Localization

Tagged as: Asp.Net MVC OWIN Posted By

Businesses all over the world are going global and thus the services offered by them needs to be catered to people of different cultures. This means the services these businesses provide through a web based application needs to support multiple cultures i.e. the application should support multiple languages. This is where localization and globalization comes into picture when building web applications. From initial days, .Net Framework and Asp.Net has localization support using resources files which helps us to localize the views and thus preventing the need to build separate website for each locales. In this article, let’s see how to build a multi-language web site using Asp.Net MVC framework.

For easy understanding, let’s build a simple Employee Maintenance application that helps to maintain employee records using Asp.Net MVC 5.0 and Visual Studio 2015. We will use simple Employee-Department Model and Entity Framework Code First for data access. Assuming, you have the project created with all the necessary Nuget packages required to run Asp.Net MVC 5.0 and Entity Framework, let’s go ahead and add multi-language support to Employee Maintenance application. For simplicity, we will just add a Tamil language support in addition to the default English locale. Once built, the application will support both English and Tamil language as seen in the below screen shots.

Home Page

Multiple Language Text In Asp.NET MVC View

Employee List Page

Multiple Language Text In Asp.NET MVC View

Employee Detail Page

Multiple Language Text In Asp.NET MVC View

 

 

At high level, we need to do the below 3 steps to add multi-language support to the MVC application.

  1. Create Resource Files

  2. Modify Views to Use Resource Files

  3. Set Request Thread Culture to User Locale

 

  1. Create Resource Files

Asp.Net has special file called resource files (.resx) to define the default locale (English) and other language texts. In WebForms, we generally create one resource file for every .aspx files. In Asp.Net MVC, we can define one resource file for a view or for a controller whichever is best suited for your application.

For default locale English, the file extension should only include .resx and for other language we should include the culture code before the .resx extension. For Tamil, it is .ta.resx or .ta-IN.resx. Refer here to get the list of language culture codes for different cultures.

To add a new resource file, right click the project node in solution explorer, Add New Item. Select Resources File and rename the file to extension .ta.resx for adding Tamil language resource and only .resx when adding for English.

Add Resource File in Visual Studio 2015

Note - Please do not create your resource files under specialized folders App_LocalResources or App_GlobalResources folder for Asp.Net MVC application since they are compiled by Asp.Net Compilers. Refer here to know more.

You can specify a namespace for resource file from the property window of the added resource files. The below image shows “Resources” namespace added to the Global.ta.resx file. You can do this to all resource file for the code generator to include all resource class under the specified namespace.

Resource File Namespace

By default, the access modifier of the resource file is set to Internal. You can change this to Public from the Access Modifier dropdownlist from the resource file to make the resource files available to multiple assemblies (for example to access from unit tests, etc.).

Resource File access modifier

You can now add the resource key value pairs in the resource files as seen in the below figures.

For employee maintenance application, I have created one resource file for each controller in addition to a Global.resx file for storing application wide texts, ErrorMessage.resx for storing error messages and a Common.resx file to store any common text that can be shared in multiple views. The final list of resource files including Tamil is as seen below in solution explorer under Resources folder.

Resource files in visual studio solution explorer

 

  1. Modify Views to Use Resource Files

This step is where we will replace the hard coded texts in the view files to resource file keys for fetching the texts based on the locale. The _Layout.cshtml file has some application wide mark-ups which will be available across application. So, as said in earlier section, we have kept application wide global text under Global.resx file. The changed layout mark-up that uses the resources file is seen below.

_Layout.cshtml

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            @Html.ActionLink(Resources.Global.APP_NAME, "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li>@Html.ActionLink(Resources.Global.Home_Menu, "Index", "Home")</li>
                <li>@Html.ActionLink(Resources.Global.About_Menu, "About", "Home")</li>
                <li>@Html.ActionLink(Resources.Global.Contact_Menu, "Contact", "Home")</li>
            </ul>
        </div>
    </div>
 

Similarly, the Employee.resx can be used in the views related to Employee controller. The below code shows employee list page changes using resource file.

EmployeeSummary.cshtml

@model IEnumerable<EmployeeMaintenance.Models.Employee>

@{

    ViewBag.Title = Resources.Employee.Summary_Title;

    Layout = "~/Views/Shared/_Layout.cshtml";

}

<h2>@Resources.Employee.Summary_Title</h2>

 

Note – I have just added few properties for simplicity, you can add key-value pairs for the entire view UI elements in your case.

 

  1. Set Request Thread Culture to User Locale

This is the final step where the application need to know which resource file (or language) it has to choose when rendering the view. This can be done by setting current request’s thread culture to user preferred locale.

There are multiple way of doing it, here in this article let’s see 2 of the very common ways of setting the thread’s culture.

  1. Using Global.asax Application_AcquireRequestState

This is one of the common way to set the current request thread culture to user locale so that the Asp.Net MVC picks the correct resource file for the selected locale. The below code helps to do that.

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    string culture = "en-US";
    if (Request.UserLanguages != null)
    {
        culture = Request.UserLanguages[0];              
    }
    Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
    Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
}
 

In the above code, the user preference of locale is got by Request.UserLanguages collection that is populated from the User Agent or Browser which made the request. The Request.UserLanguages[0] will give the user’s first preferred locale which will be used to pick correct resource file. When the user preferred locale is not available, it will be fall back to the default locale which is English.

Note - To make the browser add the language header, in Firefox, go to Tools>Options>Content. Click Choose.. button under Languages. Add the preferred language (Tamil in this article) from the dropdown and use the Move Up button to make it as first preference.

Set preferred language in FireFox Browser

 

  1. Using OWIN Startup.cs and IControllerActivator

This is the preferred approach when you use OWIN start-up and for future portability to OWIN based application. We need to create a custom controller activator and configure the MVC to use it when creating controller instance. The custom controller activator that adds the user’s preferred locale to request thread is below.

namespace EmployeeMaintenance.Infrastructure
{
    public class MultiLanguageControllerActivator : IControllerActivator
    {
        private string FallBackLanguage = "en-US";
        public IController Create(RequestContext requestContext, Type controllerType)
        {
            if (requestContext.HttpContext.Request.UserLanguages != null)
            {
                FallBackLanguage = requestContext.HttpContext.Request.UserLanguages[0] ?? FallBackLanguage;
            }

            Thread.CurrentThread.CurrentCulture = new CultureInfo(FallBackLanguage);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(FallBackLanguage);

            return DependencyResolver.Current.GetService(controllerType) as IController;
        }
    }
}
 

Now, we need to configure the MVC to use this custom activator by configuring it from OWIN Startup class. Code below.

[assembly: OwinStartup(typeof(EmployeeMaintenance.Startup))]
namespace EmployeeMaintenance
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new MultiLanguageControllerActivator()));

            //Removed for brevity
            
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
        }
    }
}
 

Please make sure you have Microsoft.Owin.Host.SystemWeb Nuget package already added for the above code to work. Alos, make sure you have set owin:AutomaticAppStartup property to true in Web.Config file.

 

<add key="owin:AutomaticAppStartup" value="true"/>

 

 

Adding Localization Support to DataAnnotation Attributes

Since, we extensively use DataAnnotation attributes to render view elements in Asp.Net MVC we need to add localization support to those attributes as well. For example, the @Html.DisplayNameFor(model => model.FirstName), @Html.DisplayNameFor(model => model.LastName) helper methods use Display attributes to get the display column names in Employee Edit and Details screen. To add multi-language support or localization support to these atttibutes, read my article Using Resource File for DataAnnotations Display Attribute with Multi Language Support in Asp.Net MVC.

 

That’s it! You can run the application and see the Asp.Net MVC localization in action. Full source is attached with this article, please download and see it in action.

In my next article, we will see some advanced scenarios like giving user the option to change language on the site and sending the user preferred locale as a route parameter, etc.



Feedback

Comments

Resources Folder
This is not working for me the layout does not take the Resources folder when i am trying to call it
Commented by Mfundo on 11/2/2020 1:46:54 AM

Faster
Using resources is the faster method. If you use database to setup language in a front end is more process to load data and to move to the frontend. You can leave resource without embedding to allow editing. If you need translate database data, you must use additional tables to allow keep a key pair between language and translated word.
Commented by Eduardo edusie@yahoo.com on 8/27/2020 7:46:01 AM

Great job!!
I just need this topic. Very detailed, if you have worked before with resources you understand this is the best Microsoft way ;). Translation is a heavy work, don't expect to be easy.
Commented by Eduardo Sierra on 8/27/2020 7:40:23 AM

Why resources?
Why not database? can you edit resource files after publish?
Commented by Kaan on 7/26/2020 12:09:56 PM

Why resources?
Why not database? can you edit resource files after publish?
Commented by Kaan on 7/26/2020 12:09:14 PM

sqmtrs
Very Useful Information I found on Internet. I think the content you cover through the post is quite interesting, good work and great efforts. I found it very enjoyable and enjoyed reading it all... keep up, beautiful work.. This paragraph gives clear idea for the new viewers for Real Estate Property Portals, Thanks you. You're doing a great job Man, Keep it up. https://www.sqmtrs.com https://www.sqmtrs.com/contact https://www.sqmtrs.com/project/27240001-Sadguru-Universal-panvel-navi-mumbai https://www.sqmtrs.com/project/27240002-Millennium-Hilton-panvel-navi-mumbai https://www.sqmtrs.com/project/27210001-Atlantis-bandmbuildcon-ghansoli-thane-navi-mumbai https://www.sqmtrs.com/project/27240003-Sadguru-Planet-kalamboli-panvel-navi-mumbai https://www.sqmtrs.com/project/27240004-Majestic-Villa-dronagiri-uran-navi-mumbai https://www.sqmtrs.com/project/27240005-Sky-Heritage-dronagiri-uran-navi-mumbai https://www.sqmtrs.com/project/27240006-Sky-Copper-dronagiri-uran-navi-mumbai https://www.sqmtrs.com/project/27240007-Anant-Corner-dronagiri-uran-navi-mumbai https://www.sqmtrs.com/project/27210002-Plutonium-Business-Park-turbhe-thane-navi-mumbai
Commented by Amruta on 5/10/2020 10:01:33 PM

Very long time taking process
it takes a very long time to create resource values for all views and set translate values for each label and text etc... is there not another way
Commented by junaid on 5/6/2020 7:44:39 PM

Small minds
You guys are pretty much dumb. Programmers should think out of the box. I've used this example to build my app, this even works on common applications, you just wont use Namespace.File.String. You need to build a "Manager" to get strings for you inside of the file. And then you're gonna use it like: MyResourceMgr.GetString(db["id_lang"]);
Commented by Felipe Vieira Vendramini on 1/10/2020 1:23:16 PM

cc
ccc
Commented by cc on 8/22/2019 4:06:03 AM

ATTACHMENT TO BIG QUESTION
My email is xatabadich@gmail.com
Commented by Vlad on 7/21/2019 10:55:41 PM

BIG QUESTION
How to translate data? I mean: firstName, LastName, Address. Could anyone send a link to approach where the data also translated or better a link to a project that realize the kind of logic. Thank you!
Commented by Vlad on 7/21/2019 10:54:37 PM

Beware
Ran the app and all it did was trash my localhost configuration. Now I got to figure out what this did to break a perfectly running VS web environment. P.S. I've download hundreds of examples over the years and NEVER did they mess up my environment like this.
Commented by Where do I send the bill on 8/15/2018 12:43:11 PM

Very interesting article..
but how will we do when we want change the language of database data..?
Commented by Shahjad on 4/10/2018 5:59:05 AM

most of the data is inside the database, not outside
great for translating error messages and the like but since most the information presented on any given site is extracted from the databse, pretty much useless in a real world app.
Commented by Guillaume Lachance on 2/3/2018 3:41:36 PM

Back-end
Good article. But what about translating the database's data?
Commented by Azizjan on 12/10/2017 2:24:59 AM