As with many other concepts in the ASP.NET Core world, expansive documentation exists regarding Globalization & Localization within applications. However, the documentation is in the form of a user's guide and a simple implementation example. Rarely do our final projects end up matching the single-project solution structures that are used as examples. After recently setting up a new project to support localization, I thought I would share a more "real-world" example from the implementation.
The Goal
The goal is simple, we have a multi-project ASP.NET Core application that needs to support localization. We are primarily concerned with the following features.
- Localization of DataAnnotations & Validations in View Models
- Localization of static content in views
- Localization of messages/information from controllers
- Standard support for language switching/detection
Our Project Structure
For simplicity we will only look at the two application tiers involved in this example:
- MyProject.Services - This contains View Models & Service Implementation
- MyProject.Web - This contains the actual ASP.NET Core web project.
Although in this example we are working with two assemblies, in the end, we can repeat this pattern regardless of the number of assemblies or complexity of your project.
Enabling Localization
Before we update any of our existing View Models, or Views, we begin by configuring our application to support localization. This is completed with two small changes to the Startup.cs file within our web project.
Changes to ConfigureServices
Your configure services method might have a lot of complexity depending on the features you have enabled, however, our starting point is a default project setup, with MVC enabled and looks like the following.
We need to add three statements to this method; the first enables Localization support and configures where to find the resources. The second and third statements configure the application to add localization support to our data models & views automatically.
The order of these elements is important. The first statement's definition of a ResourcePath is the most critical for downstream processing. The path specified creates a pattern where resource files can be identified based on the object's fully qualified name within each assembly; more on this later.
The remaining two elements add the required elements to wire-up the needed components for automatic localization support.
Configure Method Changes
Next, we need to configure the application to enable language selection based on the incoming pipeline information, this is completed in the Configure method of Startup.cs. You should add this BEFORE any app.UseEndpoints()
or other element that will need to be aware of the requested locale.
At this point, we have completed all necessary configuration elements, we can now start adding resource files to our projects and handling localization on a case-by-case basis.
Localizing ViewModels
In our theoretical sample project, we have a folder called "ViewModels" within the service project that contains a very simple Model
As you can see from this snippet we have added a Display
attribute with a name. All we need to do to support localization is to add a new Resources file for each of our languages in the format SimpleModel.{Language}.resx
. This file should be created at the same nesting level, within a "Resources" folder inside of our current project for proper identification. This means our final tree structure will be.
- Resources
- ViewModels
- SampleModel.en.resx
- SampleModel.es.resx
- ViewModels
- ViewModels
- SampleModel.cs
This is the critical pathway, we can continue to distribute our resources with our individual libraries if we follow this structure. Inside of the resource file, we can have a single key/value pair for the actual text, English example below.
Name | Value |
---|---|
ApplicationName | ApplicationName |
This method is supported for data annotations used for display names, validators and similar without any additional support on your side.
Enable Localization of Views
Localization of views is even easier, you may simply add additional files alongside of any of your views using the same suffix format utilized for the resource files.
If you have a view "Sample.cshtml" you can create a Spanish version using "Sample.es.cshtml" and simply update with the proper information.
Language Detection?
Using default configuration as outlined in this posting your application will now support automatic language switching using one of three different methods.
- Querystring - Utilizing the culture & ui-culture query string parameters. (?culture=es_es for example)
- Cookie - Utilizing a default
.AspNetCore.Culture.
named cookie with c and/or uic values (c=es_es for example) - Accept-Header - This will use the user's browser default language.
You will need to build into your application a language switcher or otherwise if desired. Often times, user preferences are used to store these values.
In Summary
Following these quick steps we setup our ASP.NET Core application to support localization. There are still further methods of customization and implementation, however, this gets off the ground running! For existing applications, it is important to note that any missing language values will fall-back gracefully to the end-user which lessens the burden of beginning the transition.