Globalizing ASP.NET Applications With Non-Standard Languages
By Jason Salas
Introduction
Have you ever wanted to use a language, character set or encoding type not inherently supported in the .NET
Framework in your web applications? Perhaps you've got a comical interest to display your content in Pig Latin,
Ewok, GeekSpeak, or some unique dialect you and your friends developed between each other. Or, maybe you've got a
more legitimate business problem to solve, like displaying content for a certain race of people whose native tongue
isn't recognized by the International Standards Organization (ISO). If you've ever been in any of the above
situations, you'll want to read on. In this article, I'm going to show you how to easily extend the current
functionality of the .NET Framework to support rare, uncommon or even completely new languages for use in your
ASP.NET projects.
Programming With New/Non-Standard Languages
I came across a problem recently when I wanted to have certain sections of my company's Web site display information
in languages other than English. Doing so provides a rich level of customer service and allows us to interact with people
who might not use the Internet otherwise for information, or prefer to receive information in a manner more
convenient to them.
The problem was that that the languages I was looking to support – Chamorro (Guam's native language), and Tagalog (the dominant
dialect used in the Philippines) aren't recognized by the ISO. At first glace, it appears that using them in the
.NET Framework is impossible, because an overloaded constructor for the CultureInfo class, found in the
System.Globalization namespace, requires a string argument specifying an ISO-recognized culture.
However, not all is lost. I'm fortunate that both Chamorro and Tagalog are heavily influenced by Spanish, so that
date-time formatting strongly resembles that language. So, in creating new cultures, we're going to inherit from
Spanish as a base reference.
Localization Does Not Mean Automatic Translation
Before we get to the code, let's dispel a rumor that I'm accosted with at nearly every talk I give about globalizing
applications with .NET. Not surprisingly, many people jump to the conclusion when first hearing about .NET's
globalization capabilities that .NET apps will be able to take content in one language and automatically translate it
to another. While this would be an amazing feature to have available, it's sadly not available at the moment.
For that reason, I'm going to do in this article what I do in technical presentations I give on ASP.NET: avoid any
further use of the word "translate."
To display content in foreign languages in this example, I'm going to tap into resource files. Since the information
in these resource files are pre-populated with information, they're best used for static content areas like
headers, footers or greetings. However, services like AltaVista's Babel Fish Translation Service certainly make it
easy to translate dialogue from one language to another (oops…I'm supposed to be avoiding that word, aren't I?)
Get to the Code, Already!
OK, OK... onto the code! I'm going to borrow from an
excellent example from Francois Liger on creating custom cultures for use in applications. We only need to
define a custom type to create one or more cultures, setup some resource files, and we're done!
For purposes of simplicity, I'm coding the entire page and custom class inline within the same page. Of course, in
a practical localized application, you'd probably want the settings available to more than just a single page, so
the class would be stored in its own code file and stored as an assembly. Also, I'm going to create a file-based
resource manager instance, which in a more realistic environment would take a backseat to using satellite assemblies.
First, we import the necessary namespaces to make use of the methods and properties we'll call and set. These
@Import directives are added to the ASP.NET Web page, since I am using the server-side script block
approach for this example. If you were using Visual Studio .NET's code-behind model, you'd use using (C#)
or Imports in your code-behind class file:
Next, we create a custom class, CustomGuamCulture class, inheriting from CultureInfo and
overriding some of the base class's public properties. Pay particular importance to how the base Parent
property is overridden by creating a new CultureInfo instance, which is the parent culture specified in
the overloaded class constructor. This ensures we derive from an existing culture, and therefore, we can use the
base class's number and date formatting.
public override CultureInfo Parent
{ get { return new CultureInfo(this._parent); } }
One thing to note is that because the constructor of CustomGuamCulture takes an existing culture as its
parent, the .txt files containing the multilingual content need to be named so that they reference the
parent and the custom culture:
customCulture.txt (the neutral culture file)
customCulture.es-ES-gu-CH.txt
customCulture.es-ES-pi-TA.txt
Then, just use the ResGen tool to make the .resources files using, and you're all set!
Now, we've got all we need to use our custom languages in an ASP.NET Web page! Just add the logic into the page's
Load event. Notice how I use a C# switch statement to figure out what value the user selected within a
RadioButtonList control I placed declaratively on the page: if the value of the RadioButtonList is either
Chamorro or Tagalog, the CultureInfo variable ci uses our custom class. Any other
selection would trigger the default action, which is to use the normal CultureInfo class.
protected void Page_Load(object sender, EventArgs e)
{
CultureInfo ci;
switch (Radiobuttonlist1.SelectedValue.ToString())
{
// if the user selected either CHAMORRO or TAGALOG as their preference,
//load the resource file for that language
case "gu-CH" :
case "pi-TA" :
ci = new CustomGuamCulture("es-ES",
Radiobuttonlist1.SelectedItem.Value.ToString(),
Radiobuttonlist1.SelectedItem.Text);
break;
default :
ci = new CultureInfo(Radiobuttonlist1.SelectedValue.ToString());
break;
}
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
ResourceManager rm = ResourceManager.CreateFileBasedResourceManager("resource",
Server.MapPath("resources") + Path.DirectorySeparatorChar, null);
lblGreeting.Text = rm.GetString("Greeting");
lblNames.Text = rm.GetString("FirstName") + " " + rm.GetString("LastName");
lblDate.Text = DateTime.Now.ToString("D");
lblCulture.Text = "Using culture: " + ci.EnglishName;
}
The page-level CurrentCulture and CurrentUICulture properties for the currently-executing
thread are set to the instance of ci. We also create a ResourceManager by mapping to the
/resources folder within the web app and then write out the value of the appropriate resource file to a
series of Label controls. The complete code sample can be downloaded from a link at the end of this article.
The following three images show screenshots of the ASP.NET Web page in action. Note that as the culture choice is
changed, the format of the date/time and the messages are changed to reflect the selected culture. The first screenshot
shows the output when the English culture is selected, the second shows the French culture, and the third and final
screenshot shows the output when using our custom Tagalog culture.
Further Extensions
Of course, this is only a simple demonstration of how a developer can extend globalization. Both languages
demonstrated derive from Roman, and as such, use an alphabet common to English, Italian, German, and other
languages. If you were using a language with an entirely different character set, like Chinese, Japanese, Korean, Cyrillic
or Arabic (or, you made up your own language), you'd have encoding and unique character concerns to deal with.
In fact, Christian Nagel has a fun example on how to do this for a language not deriving from anything the ISO
provides by default - Klingon (see http://www.christiannagel.com/My+Downloads/71.aspx).
But, it is possible. And maybe, just maybe, one day, the .NET Framework will provide the ultimate goal of automated
translation. Dang... did it again.
Summary
I hope you've found this article interesting, in demonstrating that extending the current collection of languages provided
by .NET's globalization capabilities provides makes for a whole new world of opportunity. And in doing so, it's
really quite easy. Hopefully, this will lead to other interesting and creative projects for you in your own
programming. I'd love to hear about them, drop me a line at jason@kuam.com and share your work.