Getting Started With ASP.NET MVC i18n

May 11, 2020 · 10 min read
Let’s walk you through the foundational steps of getting ASP.NET MVC apps ready for different cultures.

ASP.NET MVC is a modern Model-View-Controller framework for building web applications built on Microsoft’s large and reliable .NET environment. You probably already knew that. In fact, you’re probably building an ASP.NET MVC app and you’re looking to globalize it so that you can serve it in different languages. Well, have no fear. In this article, we’ll build a small demo app and globalize its UI and routes, giving you a foundation to build on as you develop and deliver your app to users from all over the world. ASP.NET MVC i18n, here we come!

Globalization, i18n, l10n … Oh My!

Localization, or l10n, is the process of building on i18n and providing the actual translations and regional formatting that is required for a given locale. That’s mostly fancy talk for l10n == translation (although there’s a bit more to it).

Oh, and while we’re at it: A locale is a combination of a language and a region, like “Canadian English”, and is often denoted with a code like “en-CA”. In .NET, this is called a culture. Again, we’ll use the terms locale and culture interchangeably here.

Alright enough with the semantics. Let’s get to building.

The Demo App

Our home page will list constellations
Each constellation will have a details page

Nothing too crazy, and it will allow us to cover basic i18n pretty well.

Resource » You can get all the code for the app we will build here from the app’s GitHub repo.

Framework and Package Versions

  • Visual Studio 2019
  • .NET 4.7
  • ASP.NET MVC 5.2

We’ll also be working in C#, although a lot of what we cover should apply to any language that works on top of .NET.

Heads Up » We’re using the traditional .NET framework, which generally requires Windows, not to be confused with .NET Core, the newer cross-platform variant of .NET.

Creating the Project

Using the search box can help filter to the template we want

In the Configure your new project dialog, we can enter the name of our app, and click Create.

We’re using .NET 4.7 here

And, in the Create a new ASP.NET Web Application dialog, we can select the MVC template and click Create.

Would you create the project already?!

Alright, that should be it for creating the project. If we now run the project using the green play button in Visual Studio, we should be greeted with a placeholder home page.

Featuring out-of-the-box Bootstrap CSS for styling

Building our App

We’ll start with a mock view model that represents our constellations. We won’t be touching the database layer in this article. If you would like us to cover database globalization with ASP.NET MVC, please let us know in the comments below :). For now, some hard-coded data will get us globalizing the front end.

Constellation has a few simple properties, a hard-coded All() method that retrieves a List<Constellation>, and a FindById() method that finds and returns a constellation by its Id. Let’s wire this model up to our Home controller.

We just query the data and pass it on to our views. Speaking of which, let’s build those.

Our index view displays our constellations as columns, with images and names. The image and name of each constellation link to its respective details page.

In our details view, we simply display the constellation’s image and properties in an orderly fashion.

We also update our CSS, adding a Boostrap theme from Bootswatch called Cyborg, removing extraneous views and actions, and adding our constellation images.

Resource » If you would like to see all the changes we made up to this point, checkout the commit tagged “start” in the demo app’s GitHub repo. You can also checkout the start commit if you want to code along with us, and you want to get to globalization right away, without building everything we have up to this point yourself.

When we run our app now, we see this beauty:

Humans have always connected the dots peppering the void of space
The Great Bear growls

Using Resource Files for Localized Messages

Creating Resources Files in Visual Studio

Next, let’s create our default resources file. We can right-click on the folder we just created and select Add > New Item. There doesn’t seem to be a template for resources files in Visual Studio 2019, but there’s an easy workaround for this. We can select the Visual C# > General tab in the sidebar and select Text File. Then, we can name the file Resources.resx, and click Add.

Make sure to change the file extension to .resx

Once we’ve added the file, we can open it in Visual Studio.

A collection of name-value pairs

Heads Up » At this point, we need to make sure to click the Access Modifier dropdown and select Public. Otherwise, our resource file won’t work.

We just created our app’s default, English resource file. We can now repeat the above process for each additional culture our app supports. We need to follow the naming convention Resources.{culture-code}.resx, otherwise .NET won’t load the correct file when we switch cultures later. I’ll add an Arabic resource file named, and make sure to set its Access Modifier to Public.

Adding Translations to Resource Files

Don’t forget to save the file

If we want to add an Arabic translation for our app’s name, we can open our file and add a string with the same Name we used in our English Resources.resx. We then can add the Arabic translation as the Value for the string.

Same name, different language

Using Resource Strings in Our Views

Instead of the hard-coded string, we’re now using Heaventure.Resources.AppName.

To see the benefit of what we’ve just done, we can go into our HomeController‘s Index action and set the culture to Arabic before we return our view.

We’ll go through setting culture in more detail in a little bit. We’re just trying to see if our resource files are working for now. After adding the code above, we can run our app and visit the root route (/) to load the index view.

We now have translated messages!

We can now remove the hard-coded culture setting we added to HomeController; we won’t be needing it.

Note » .NET will automatically fall back onto the string with the same name in the default Resources.resx if it can’t find it in Resources.{current-culture}.resx.

Adding the Resources Namespace to Web.Config

Inside the <namespaces> element, we can <add namespace="Heaventure.Resources"/>. Once we do, we can type Resources.AppName instead of Heaventure.Resources.AppName in our views.

Alright, that’s basic translation strings taken care of. Now let’s see how we can set our app’s current culture via routes.

.NET Culture

CultureInfo is the class that defines culture in .NET. It contains a wealth of information about a given culture, including its name, currency format, calendar, and much more.

Resource » Check out the official .NET documentation for more information about CultureInfo.

The Difference Between Culture and UICulture

CurrentUICulture deals with resource files (.resx), like the ones we created above. If we set CurrentUICulture to Arabic, for example, .NET will load the file automatically.

CurrentCulture deals with almost everything else when it comes to localization: formatting and parsing of values and sorting, among other things.

Setting our App’s Culture

Localized Routes

Note that we’re redirecting our root route (/) to a localized route with our default culture (English in this case). To accomplish this, we’re setting a default culture value in our localized route. We’re also routing our root to BaseController.RedirectoToLocalized() action.

A Base Controller

The BaseController is also a good place to set the app’s culture based on the current culture route parameter. To do this, we can override Controller‘s OnActionExecuting(), which is run before every action on the controller.

We yank the culture value out of the RouteData.Values dictionary, and use it to set our CurrentCulture and CurrentUICulture in our app.

Now we can update our HomeController (and any other controller in our app) to derive from BaseController.

With that in place, when we attempt to hit the root route (/), we’re redirected to /en. If we go to /ar, we can see our app name appearing in Arabic.

Our localized routes are now setting our app’s culture

Resource » We go into setting an app’s culture in more detail in our dedicated article How Do I Set Culture in an ASP.NET MVC App?

A Simple Language/Culture Switcher

We’re using a Bootstrap .dropdown here, and we’re wrapping it in a .navbar-right so we can embed it in our main _Layout.cshtml.

Now, when we run the app, we have a working language switcher.

Clicking a language takes you to its localized route

Resource » Grab all the code for the demo app we built here from the app’s GitHub repo.

And with that in place, we have working globalization in our app!


Originally published on The Phrase Blog.

i18n and l10n Resources for Developers

Hand-curated resources and tutorials on software…


Written by


The leanest, fastest, and most reliable translation and localization management platform | Free Trial:

i18n and l10n Resources for Developers

Hand-curated resources and tutorials on software localization and internationalization


Written by


The leanest, fastest, and most reliable translation and localization management platform | Free Trial:

i18n and l10n Resources for Developers

Hand-curated resources and tutorials on software localization and internationalization

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store