The most common approach to use when internationalizing ASP.NET MVC applications is to use the .NET framework's built in resource system. Another viable option is to use the i18n standard format that's provided by GNU gettext. In this post, we'll try to set up an ASP.NET MVC application that uses gettext
.
The benefit of using gettext
is that it's much easier to manage the translation files than it is with the ASP.NET globalization framework. Next to that, the i18n standard is much more common in the opensource world than the .NE resource files, and many good editors exist to simplify the translation of applications.
Daniel Crenna has created an ASP.NET MVC implementation of i18n at github. By the end of this blog post, we'll have a sample application that successfully utilizes the i18n framework Daniel wrote.
First, we'll have to create a new ASP.NET MVC application by using:
File > New Project > Web > ASP.NET MVC 3 Web Application (Note: Make sure to choose ASP.NET MVC 3).
Choose the project name you like and in the following dialog, choose the Internet application project template with the Razor view engine (see screenshot).
At the time of writing, a working nuget package was unavailable, so we'll do the installation manually (which comes in handy in case you decided not to like nuget). Next to the unavailability of a nuget package, we'll use a slightly patched version of Daniel's library that contains a few bug fixes and optimizations. Our version excludes the obj folder from the gettext
parser and fixes a bug with obsolete translations in the .po files (see here and here).
Download the patched version here from github, and extract it in the solution folder under Libraries\i18n.
Next we need to build the i18n libraries before we can use them, the easiest way to do that is to add the libraries to our current solution. In Visual Studio, choose File > Add > Existing project, and add both the i18n project, and the i18n.Postbuild project to the solution. Next add references to both these projects in our ASP.NET MVC project (right click project > add reference > projects tab > select both projects). The final result should look something like this:
Now that we referenced the i18n libraries, there are three more things we need to do:
- Copy the gettext directory to the bin folder which is needed by the postbuild script.
- Modify the build properties of the MVC project to parse the .cshtml files for internationalized
string
s using i18n.PostBuild - Create a basepage that makes it easy to call the translation method in the mvc views, and register that basepage in web.config.
Firstly, copy the gettext folder from Internationalization.SampleWebsite\Libraries\i18n\tools\gettext-0.14.4 to Internationalization.SampleWebsite\Internationalization.SampleWebsite\bin\gettext.
After that, right click the MVC project and choose properties, navigate to the Build events tab, and in the "Post-build event command line:", add:
"$(TargetDir)i18n.PostBuild.exe" "$(ProjectDir)"
So that it looks like this:
Verify that your project still builds and that the output window doesn't display any errors and continue the setup.
If you build, a folder named locale will automatically be created in your MVC projects' root folder, this folder contains all translation files which will automatically be generated by the i18n.PostBuild executable after building the project.
The third and last step is to add a new base page to your MVC project which will facilitate the easy access of your translation method, which will be accessible as @_("string to be translated").
Under the models folder, create a new file TranslatedWebViewPage.cs which looks like this:
namespace Internationalization.SampleWebsite.Models
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using i18n;
public abstract class TranslatedWebViewPage : WebViewPage, ILocalizing
{
private ILocalizingService service = new LocalizingService();
public IHtmlString _(string text)
{
string[] languages;
if (Session["CurrentLanguage"] == null)
{
languages = new string[] { CultureInfo.CurrentCulture.Name };
}
else
{
languages = new string[] { Session["CurrentLanguage"].ToString() };
}
return new HtmlString(this.service.GetText(text, languages));
}
}
public abstract class TranslatedWebViewPage<T> : WebViewPage<T>, ILocalizing
{
private ILocalizingService service = new LocalizingService();
public IHtmlString _(string text)
{
string[] languages;
if (Session["CurrentLanguage"] == null)
{
languages = new string[] { CultureInfo.CurrentCulture.Name };
}
else
{
languages = new string[] { Session["CurrentLanguage"].ToString() };
}
return new HtmlString(this.service.GetText(text, languages));
}
}
}
Now in web.config under the Views folder, we need to change the basepage that is used to edit the following section:
<system.web.webPages.razor>
<pages pageBaseType="Internationalization.SampleWebsite.Models.TranslatedWebViewPage">
Note: This is the web.config under the views folder, not the one in the root.
Now that this is done, we are almost there, under the locale folder add new folders for the languages that you want to translate, for example:
The i18n library will first try to get a translation for the most specific locale, e.g. en-US if that translation doesn't exist, it will try to use en and if that translation is unavailable as well it will use the text in the translation function call: @_("text to be translated").
Now that we have created the locale folders, it's time to add the most important element, the translation strings in the Views.
Open the index view under the home controller and replace:
"To learn more about ASP.NET MVC visit <a href=http://asp.net/mvc
title="ASP.NET MVC Website">http://asp.net/mvc</a>."
with:
@_("To learn more about ASP.NET MVC")
This translatable text will now be available in the .po files under the locale folder, and can be translated to any of the languages specified in the locale folder.
The easiest way to edit the .po files is using poeditor, I hope that this post was useful and if you have any questions or suggestions, please add them in the comments.
Attached to this post, you can find the sample website, as well as here on github. You can download the patched version of the i18n library from github as well here.