My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
SampleMvcProject  
Walkthrough for creating an internationalized ASP NET MVC site using Gettext.
Project-Sample
Updated Dec 2, 2010 by spallad...@manas.com.ar

Introduction

This page will guide you towards the creation of an internationalized ASP NET MVC site using Gettext, storing resources in plain po files in the site folder. The source code for this sample can be found here.

This tutorial assumes that you already know how to create a simple console project using these tools, and that you are familiar with ASP NET MVC framework.

Creating the Project

First of all, create an ASP NET MVC project in the solution. In our case, we will name it Gettext.Samples.Mvc. As with previous examples, the first step is to include the T4 template that adds the Strings.T translation function.

T4 Template

Include the Strings.tt template as usual, and add the value this.ServerMapPath = true to force the ASP NET application to map the logical path to the physical path to the resources in local disk. To specify the path to the resources, instead of relying on this.ResourceDir, this time we will specify that value via web config. Simply add an app setting with the value you want, in the case, ~/bin/Gettext/Po:

<appSettings>
	<add key="ResourcesDir" value="~/bin/Gettext/Po/"/>
</appSettings>

Also, create a Gettext/Po folder in your application root that will be where you will copy the translated po files when ready.

Add Translation ASP NET Control

The usual way for translating strings in web pages is to use the <%= %> syntax to introduce code, and invoke the translation function there. For example, should we want to output an internationalized Hello world string in the home page, we may write:

<p><%= Strings.T("Hello world") %></p>

Remember to add the namespace where the Strings class is defined to the web config, in the pages/namespaces section, so you can use the Strings class without its fully qualified name. Another sample that makes use of the Strings class interpolation would be the following:

<%= Strings.T("Go to the {0} page.", Html.ActionLink(Strings.T("home"), "Index", "Home")) %>

This line outputs an action link to the Home page, with internationalized text, creating the link only in the word home. The translator will have to deal with two separate strings in this case: Go to the {0} page and home.

Although this way of writing internationalized strings in web pages works, for simple strings it might be a little to cumbersome. An option is to create an ASP NET control that runs at server and internationalizes its content. The base for this control is provided in the Gettext.Cs.Web core project. To make use of it, create an AspTranslateControl class in your application that inherits from the base control, and fill the abstract Translate function, like this:

namespace Gettext.Samples.Mvc.Controls
{
    public class t : Gettext.Cs.Web.AspTranslate
    {
        protected override string Translate(string text)
        {
            return Strings.T(text);
        }
    }
}

Make sure you also add the Gettext.Samples.Mvc.Controls to the web config, in this case to the pages/controls section, and using a short and convenient prefix, such as t:

<controls>
	<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
	<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
	<add tagPrefix="t" namespace="Gettext.Samples.Mvc.Controls" assembly="Gettext.Samples.Mvc"/>
</controls>

Now if you want to translate a simple string in an ASP NET page, you only have to wrap it in a t:t control, including the runat=server attribute so it is processed and translated server-side:

<t:t runat=server>Hello world</t:t>

Of course, the Strings.T function is still available for use in views and in any other part of the application, such as controllers, models, services, etc.

Choosing culture

There are multiple ways of allowing the user to specify which culture he or she perfers. A usual way is to present a combo box or list of languages, and when the user selects one of them, store that information in a cookie or server-side. Keeping language information in the URL itself is also a good practice when SEO is important.

For the sake of this example we will use the most simple one: use the browser's default. To instruct ASP NET MVC to use as UICulture the browser's language, add the following node to the system.web in the web config:

<globalization uiCulture="auto"/>

This will use the Accept-Language headers sent to the server by the browser and apply them to the current thread. So in order to test the site in different languages, you will have to change your browser's languages. In Firefox, for example, just go to Tools, Options, and choose to change language:

Extracting strings

The GNU gettext strings extractor, xgettext, supports a number of languages, but does not handle <t:t> tags in ASP NET pages. It may also ocassionally presents some issues when attempting to parse Strings.T c-sharp functions inside an ASP NET page.

The ExtractAspNetStrings batch file takes care of these cases, by invoking the AspExtract tool in the solution, by creating intermediate files from all aspx, asxc and Master files that can be understood by xgettext.

This batch requires a number of environment variables to be set before being invoked, see the example file for more details:

  • path_xgettext Path to the xgettext executable
  • path_aspextract Path to the aspextract tool executable included in this solution's tools
  • path_output Output path for the template file
  • file_list List of files to be processed by xgettext
  • asp_files_root Where to obtain all ASP NET files to be processed
When running this batch on the sample project, the result is the following Strings.pot gettext template, with all the strings in both the code and the ASP NET pages.

#: E:\Gettext\cs-utils\Gettext.CsUtils\Samples\Gettext.Samples.Mvc\Controllers\HomeController.cs:14
msgid "Welcome to internationalized ASP.NET MVC!"
msgstr ""

#: E:\Gettext\cs-utils\Gettext.CsUtils\Samples\Gettext.Samples.Mvc\Views\Home\Index.aspx.postrings:1
msgid "Hello world"
msgstr ""

#: E:\Gettext\cs-utils\Gettext.CsUtils\Samples\Gettext.Samples.Mvc\Views\Home\Index.aspx.postrings:2
#, csharp-format
msgid "Go to the {0} page."
msgstr ""

#: E:\Gettext\cs-utils\Gettext.CsUtils\Samples\Gettext.Samples.Mvc\Views\Home\Index.aspx.postrings:3
msgid "home"
msgstr ""

Note that strings from ASP NET pages have an additional postrings extension, these are temp files generated with a syntax easily understandable by xgettext for procession. The downside of this solution is that line numbers are not preserved, this is a pending issue in the tool.

Executing the Project

Copy the po files for the different cultures in the Gettext/Po folder you created earlier. Make sure to specify that these files are copied to the output directory, so it can be properly accessed. Now run the project, set your browser's language to spanish, and check the results:

Comment by jlade...@gmail.com, Mar 21, 2011

Santiago, instead of the use of po files and tt ones, why you don´t create a new routing to the translated page?

Something like this: Intead of have t tags <t:t runat=server>Hello world</t:t> (good for development purpose), when you compile your project translate each string to each language you have defined. <t:t runat=server>Hello world</t:t> will transform in Ciao mondo in the "it" or "hola mundo" in the 'sp' globalization.

Why your approach don't like me? because if you have 100 strings in a file you must search the translation for each one, instead with my approach you will have 0 string to find and replace.

Do you like my approach? besT

Comment by spallad...@gmail.com, May 14, 2011

Your approach is interesting, but there is a caveat: translation becomes tied to deployment. This is, whenever a translator comes up with an updated .po file, you have to recompile and redeploy your whole application. By looking up the strings (which, by the way, is how most i18n engines work), you only have to updated the .po files, restart the server to ensure the cache is cleaned, and the new translations are ready.

Comment by yangzhi...@gmail.com, Feb 16, 2012

how to ..... please....

<asp:DropDownList ID="aaa" runat="server">

<asp:ListItem Value="0">否</asp:ListItem> <asp:ListItem Value="1">是</asp:ListItem>
</asp:DropDownList>

<asp:GridView ID="GridView1" CssClass="table textcenter" AutoGenerateColumns="False" runat="server">

<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ID" DataNavigateUrlFormatString="" HeaderText="详细" Text="详细" />
</Columns>
</asp:GridView>


Sign in to add a comment
Powered by Google Project Hosting