An increasing number of applications are being designed to be configurable by the user to display content in a one of a number of alternative languages, currencies, date formats and other cultural aspects. It is better and easier to make such localization support intrinsic to the design rather than to retro-fit it. So what is the best way of doing so in ASP.NET MVC?
The .NET Framework has always offered basic support for localization. The support for localization, though, never extended beyond providing some basic features such as translation of strings and simplified switching between cultures and their specific aspects such as currency and date and time formats.
While this is mostly sufficient at the general level of a development framework, it runs short of the features you need when you tackle application frameworks such as ASP.NET. For any ASP.NET application with a long life expectancy and an international audience, there are three essentials to localization to bear in mind:
- Manage to make all resources localizable and not just strings and literals;
- Enable sites to switch to different locales according to a well-defined logic, whether IP detection, browser settings and/or explicit selection;
- Storage of localized information, whether external services, databases or hard-coded libraries;
Before going any further, though, it is important to recall a bit of terminology and clarify any possible doubts and misconceptions.
What are I18N and L10N all about?
When it comes to culture-specific versions of any software, there are two recurring terms with apparently similar meaning and intent. They are internationalization and localization. Internationalization is shortened to I18N where the number (18) refers to the length of the word. Similarly, L10N is short for localization and the number 10 refers to the length of the word.
Sometimes the two terms are used as synonyms, which they aren’t. Sometimes, a third term—globalization—is used to merge the meaning and intention of both internationalization and localization together. Internationalization refers to designing a software application in such a way it can be adapted to different languages and cultures without touching the source code. This generally means replacing literals, images, and forms. Localization is, instead, the actual process of adapting software to a specific culture. More precisely, localization consists in translating text and adapting images and forms. Localization usually takes place several times—one for each supported culture—and it relies on the service and flexibility provided by the internationalization layer of code.
Most ASP.NET web sites are localized for two or more cultures. One is generally the English language—regardless of the culture, whether us, uk and so forth. For sites hosted in different countries there’s of course the need of addressing the local culture first. Depending on the nature of the site, its content and expected audience it can be necessary to localize the site in one or two additional languages such as Spanish, Chinese, Portuguese or Arab.
This is to say that a layer of internationalization is necessary in almost any web site. This entails using literals that are read from localizable stores and providing a mechanism to switch quickly and easily between languages.
When it comes to designing an internationalization layer, you first need to decide how to select a culture. There are a few options:
- By default, the culture should match the settings of the current browser settings of the user and use a neutral culture if no match exists;
- Let the user choose between a few predefined cultures and remember the selection in a cookie;
- Use some external geo-localization service that reads the IP, determines the country from it and, from there, the culture;
Most sites just use the first option; but in general any of the above options is valid. Selecting one is mostly a matter of preference.
Planning an Internationalization Layer
When it comes to making an application support multiple languages and cultures, a common mistake is to just look into providing the appropriate literals and programmatically-calculated strings. Microsoft does a good job in the .NET Framework to provide primitives to detect the current culture and related settings. It doesn’t do the same good job in the .NET Framework—and the ASP.NET framework in particular—to help developers to write code that supports localization for aspects other than plain text. For example, there’s no official support for meeting a requirement such as providing a default naming convention to pick up localized images or localized user controls and partial views.
The simplest approach to localizing text in a .NET Framework application is to create a RESX resource file and have Visual Studio create a designer class around it. The designer class exposes one static property for each entry in the RESX file. All you need do as a developer in an ASP.NET MVC application is to simply use the following code instead of a plain literal.
When you display a web page displayed in another language, It is not just the text itself that you need to change. Sometimes the text can’t just be translated and adapted. When translated, for example, it may become too long or too short for the space allocated. To fix this problem, it may be necessary to make some changes to the HTML layout. Some images and colors may need fixes to look good for other cultures. In general, an ASP.NET developer that wants to build an effective internationalization layer must be ready to create his own mechanism to quickly replace—possibly even on the fly—resources such as images and partial views.
You can add multiple RESX files to the project using the culture identification to distinguish files. You can have strings.resx for all localizable text to be used by default and strings.it.resx for text to be displayed to, say, Italian users. A similar mechanism can be used for images, partial views, and other resources such as CSS files and, in some very special cases, script files. The cost of creating such a translation engine is entirely yours. The outline of a solution for images might be using a HTML helper to display the image which accepts the URL of the neutral image and actually displays the localized image, if any. Here’s an example:
The HTML helper will generate an IMG element that links foo.jpg if no localized version of the image exists and switch to foo.it.jpg (or whatever that will be) in case of localized images. This example also illustrates fairly well the role and meaning of internationalization. It’s all about writing the code in such a way that by simply configuring the system differently it automatically adapts to a different culture.
As far as CSS or script files are concerned, you can opt for a customized version of the Url.Content method that also includes a bit of logic to detect the current culture and look for an analogous resource with a localized name. For HTML partial views you can use the same engine and apply it to a customized version of the Html.Partial method.
As a side note, you might want to consider that ASP.NET MVC display modes are a possible way to implement an extended localization engine for views. A display mode is a Boolean expression that can be based on any data included in the HTTP context. If you can detect the current culture in the expression, you can have the ASP.NET MVC engine to select a different view based on the suffix of the display mode. The trick definitely works, but it can be applied to HTML views. In general I prefer writing a custom engine that renames resource URLs and use it for just everything—CSS, scripts, images and views.
Resource Provider for Localized Text
Localized strings are saved into RESX text files that are compiled into an assembly. This is a consolidated solution in the .NET Framework, but it is not really ideal when it comes to adding support for a new culture to an existing and already deployed application. Suppose, for example, that you want to add a new language to an existing ASP.NET application. You would need to write a new RESX file and compile it to an assembly. This, however, has two drawbacks. First, you need to compile and make a new deployment. Second, while the RESX file is a text file it doesn’t have an editor outside Visual Studio. In other words, at least in the default scenario you would need Visual Studio to add support for a new language; it’s a developer gig that, however, requires a separate expertise for the actual translation of the literals into the target language.
Another possibility is to use a non-default resource provider. This means that instead of storing localized text in a RESX file, you save it to a different store—for example, a database. In this case, you gain an immediate benefit. Text can be updated offline without any need of redeploying the application. In addition, language experts can work without using Visual Studio and also arranging a quick tool for them to use and translate and save translated text is much easier to do. A Nuget package that helps with having resources stored to, and edited from, a SQL Server database is https://www.nuget.org/packages/Westwind.Globalization.
External Services for Localized Text
Yet another possibility for localized text is using an external service. This means that all the text the application needs in any given language is taken from an external translation service. The translation service has very little in common with Google or Bing universal translators as it will only store a global dictionary and return localized text for specific keywords.
Having a service poses some performance issues. The application can hardly afford the costs of making a remote call for each line of text to display for each build of the page. The entire set of translated text will be loaded once and kept in memory. How would you invalidate the cache when a new language is added to the service or changes to translated text are made?
This is a fundamental point to answer; however, the answer is that it’s all upon your shoulders. You should find a way to cache data and notify the application when translation data in the service changes. An external localization service also has the advantage that changes and fixes will be applied well beyond the realm of the application. An external localization service is not necessarily a service set up and maintained by the same team who sets up and maintains the ASP.NET application. It will most likely be an external team and an external company with true language experts.
Auto-adapting ASP.NET MVC Applications
Most applications that need multiple languages are ‘auto-adapting’ in the sense that they decide the culture to use based on user-provided information. The most common way of selecting the culture to use is to rely on the browser settings. The application reads the list of accepted languages that the browser sends with each request and matches that with the user’s settings in the particular browser. The application picks the favorite user’s language and sets that to the current .NET thread serving the request. Setting the culture on the current thread is the classic .NET way of setting a language. In this way, a user that configures its browser to use, say, English will receive the English version of a site regardless of the language of the operating system and the country from which she connects. To enable this approach, you need to turn on globalization settings in web.config.
<globalization culture="auto" uiCulture="auto" />
The same configuration element can be used to select offline a specific language. Here’s how.
<globalization culture="it" uiCulture="it" />
The attribute Culture refers to all application-wide settings, such as dates, currency, and numbers. The attribute UICulture, instead, refers to the language being used to load resources.
Another approach is based on geo-localization, where the ASP.NET application in some way gets the current location of the user from the IP address or just the client-side geo-localization) and chooses the culture accordingly.
Resources are just user interface items that you might want to adapt to a specific culture. Resources span the entire application and are not limited merely to the text to translate. Localizable items may include images, CSS files, HTML views and, in some cases, even script files. The .NET Framework doesn’t offer a comprehensive way to handle resources. It offers facilities for literals and text resources, but that’s all. Everything else, therefore, is up to you. In addition to internationalizing the application so that it can load localized resources, developers must find out the most efficient way to load localized resources—local assemblies, database or even services. Finally, a localized application must decide how to choose the culture, whether from a cookie, the browser or the location of the IP.
This article offered a global perspective of localization of ASP.NET MVC applications so that you know all aspects of it and don’t find unpleasant surprises just around the corner.