Click here to Skip to main content
15,891,777 members
Articles / Web Development / ASP.NET

i18n globalization with gettext and ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
2 Oct 2011CPOL4 min read 29.6K   6   5
i18n globalization with gettext and ASP.NET MVC

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:

  1. Copy the gettext directory to the bin folder which is needed by the postbuild script.
  2. Modify the build properties of the MVC project to parse the .cshtml files for internationalized strings using i18n.PostBuild
  3. 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:

C#
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;

    // For non-strongly typed view pages
    public abstract class TranslatedWebViewPage : WebViewPage, ILocalizing
    {
        private ILocalizingService service = new LocalizingService();

        public IHtmlString _(string text)
        {
            // If the session doesn't contain the users selected language, 
            // default to the processes current culture (can be defined 
            //in web.config to a specific language,
            // or to be the users browser language see below) 
            // <system.web>
            // <globalization culture="auto" uiCulture="auto" />
            // <globalization culture="en-US" uiCulture="en-US" />
            string[] languages;
            if (Session["CurrentLanguage"] == null)
            {
                languages = new string[] { CultureInfo.CurrentCulture.Name };
            }
            else
            {
                // this can ofcourse be switched to for example cookies for 
                // persistence that lasts longer then the lifetime of the session
                languages = new string[] { Session["CurrentLanguage"].ToString() };
            }

            return new HtmlString(this.service.GetText(text, languages));
        }
    }

    // For strongly typed view pages
    public abstract class TranslatedWebViewPage<T> : WebViewPage<T>, ILocalizing
    {
        private ILocalizingService service = new LocalizingService();

        public IHtmlString _(string text)
        {
            // If the session doesn't contain the users selected language, 
            // default to the processes current culture (can be defined 
            //in web.config to a specific language,
            // or to be the users browser language see below) 
            // <system.web>
            // <globalization culture="auto" uiCulture="auto" />
            // <globalization culture="en-US" uiCulture="en-US" />
            string[] languages;
            if (Session["CurrentLanguage"] == null)
            {
                languages = new string[] { CultureInfo.CurrentCulture.Name };
            }
            else
            {
                // this can ofcourse be switched to for example cookies for
                // persistence that lasts longer then the lifetime of the session
                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:

XML
<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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Dexchange Outsourcing
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionUrdu translation Pin
Dakait Gujjar30-Oct-12 7:46
Dakait Gujjar30-Oct-12 7:46 
QuestionSuggestions for DataAnnotations? Pin
p0rg14-Nov-11 15:35
p0rg14-Nov-11 15:35 
GeneralRe: Suggestions for DataAnnotations? Pin
wullinkm14-Nov-11 22:21
wullinkm14-Nov-11 22:21 
Hello Patrick,

In the project where I used this library for we didn't use data annotations. But you certainly make a valid point, I'll investigate this a little bit and will update (later today) the example to include data annotations.

Michael
AnswerRe: Suggestions for DataAnnotations? Pin
wullinkm17-Nov-11 23:47
wullinkm17-Nov-11 23:47 
GeneralRe: Suggestions for DataAnnotations? Pin
p0rg18-Nov-11 6:44
p0rg18-Nov-11 6:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.