Example Scenarios






Example Scenarios

Let's consider a couple scenarios in which internationalization might make a valuable impact for users. Many people view internationalization as a scary, ill-defined thing, mostly because it has little to do with technology per se and more to do with the minutia of formatting and translating content. We'll see two quick examples: first, how to deliver translated content and second, how to display numbers, currencies, and dates formatted in a regionally appropriate manner.

Delivering Localized Content

People in different locations of the world speak different languages. (I can hear you right now: "Really?") Thus, it'd be nice if the application or API were tailored to communicate in their native tongue. This is the most obvious form of delivering culture-specific information. Much of the supplementary material — such as user documentation and setup instructions, for example — will likely need to be translated, too. Even the web site that is responsible for marketing and distributing (or selling) an application will need this. We'll only consider the application itself for now, but provided that the other content is generated using software written on the .NET Framework, the same techniques can be applied there, too.

For example, say that you wanted to show a message to the user as follows:

System.Windows.Forms.MessageBox.Show("An error has occurred.");

The resulting message box will likely make sense for English users. (Presumably a real error message would have more helpful information.) But what then if you then decided to deploy your application to an audience whose primary language is German? Some might understand English, while others would probably get upset at your blatant bias against them, leaving them with an unintelligible error message.

You could add some form of configuration to the application so that you could change the message depending on whether the user speaks English or German. Pretend that we always have a CurrentUser object in scope with various configuration settings:

if (CurrentUser.PrefersGerman)
    System.Windows.Forms.MessageBox.Show("An error has occurred.");
else
    System.Windows.Forms.MessageBox.Show("Eine Strung ist aufgetreten.");

In this example, if the user set the configuration such that he or she preferred German over English, PrefersGerman would be true. While this would certainly work — those who prefer English would see an English error message and those who prefer German would see a German error message — you'd end up with a large set of similar if statements scattered throughout your code. If you needed to add support for more languages you might want to use a string to store the language, but then everywhere you had such logic, you'd need to add a switch or lengthy set of if statements. This approach certainly does not scale very well.

Using Resources

Resources enable you to store text in culture-specific resource packages. Based on the user's language preference at runtime, the right string message will be loaded and delivered. For example, you might have both an English and German resource file (LocalizedStrings.resx and LocalizedStrings.de.resx, respectively); users who prefer German would see text from the LocalizedStrings.de.resx file, while everybody else would see text from the LocalizedStrings.resx file.

You could of course enable more languages, but English in this case is our default fallback language:

ErrorOcurred=An error has occurred.

And here is the corresponding German version (LocalizedStrings.de.resx). Notice that the keys are the same for both. They have to be since they're used to look up the localized values across resource bundles:

ErrorOcurred=Eine Strung ist aufgetreten.

There are a few steps that we'll omit for brevity here (i.e., making the application aware of which resource file it should be using and bundling and packaging it correctly). We'll revisit them later on in this chapter. But all of these steps are trivial (especially with the assistance of Visual Studio and the introduction of strongly typed resources in 2.0).

At the end we have a single LocalizedStrings class that has a property for each key-value text pair we defined. It retrieves the correct version based on the language. We then change the message box code to reference the resources:

System.Windows.Forms.MessageBox.Show(LocalizedStrings.ErrorOccurred);

Without strongly typed resources, you must create a ResourceManager and ask it for a specific resource string using the string-based key, for example:

ResourceManager rm = new ResourceManager("LocalizedStrings",
    Assembly.GetExecutingAssembly());
System.Windows.Forms.MessageBox.Show(rm.GetString("ErrorOccurred"));

We'll see details on both ways of accessing resources later on in the related sections.

Note that this entire discussion also applies to non-UI software. For example, were you creating a reusable library, your exception strings might need to be localized, too. For example, as in throw new MyApplicationException(LocalizedStrings.ErrorOccurred).

Regional Formatting

Different areas of the world use different symbols to represent currencies, separators between number groups, dates and times, among other things. For example, the number 1,000.99 as represented in the United States is represented as 1.000,99 in many European countries. (Notice the swapping of the period and comma.) Furthermore, consider the various ways a simple date can be represented depending on region:

  • The separator characters between fragments of a date and time may differ. Further, the ordering of these fragments can change. For example, "3/1/05" in the United States would be represented as "1.3.05" in Great Britain (and so on).

  • Month and week day names should appear in their native language. For example, "Saturday, April 02, 2005" in the United States would be represented as "sbado, 02 de abril de 2005" in Spain.

  • A calendar other than the Gregorian calendar might be more appropriate. For example, in Japan, you'd likely want to utilize the Japanese calendar. Even for situations not driven by culture, you may need this functionality. For example, in many manufacturing and food goods settings, the Julian calendar is used to mark significant dates and times.

  • The local time zone should be used in order to represent dates and times in a manner that is relevant to a user. For example, records in a database will ordinarily be serialized using a universal format (UTC) but should be converted to local time before presentation.

Most of the intricate formatting details like this are taken care of for you by the Framework. Thankfully. Some specialized things are less easily discernable and require special coding logic. If you need to display Celsius versus Fahrenheit or metric versus the English measurement system based on a user's culture, for example, you will need to take matters into your own hands. Or if you're creating a driving simulation program, drivers in the United Kingdom might be confused if your program placed them in a situation where they needed to drive on the right-hand side of the road. These are all still critical pieces of properly internationalizing an application but are outside of the scope of the .NET Framework's internationalization subsystem. (Of course, having culture information handy is the first step.)

Let's consider a quantity of currency represented in the United States, Great Britain, Japan, and Saudi Arabia. This code demonstrates that printing the same quantity will change based on the current user's culture. Don't worry if some of the classes or methods are unfamiliar for now; just examine the output:

decimal money = 1250.75m;
string[] cultures = { "en-US", "en-GB", "ja", "ar" };
foreach (string culture in cultures)
{
    CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(culture);
    Console.WriteLine("{0} == {1}",
        cultureInfo.DisplayName, money.ToString("C", cultureInfo));
}

The output of running this code is:

English (United States) == $1,250.75
English (United Kingdom) == 1,250.75
Japanese (Japan) == 1,251
Arabic (Saudi Arabia) == _._._ 1,250.75

Note

While encoding hasn't been discussed explicitly yet, you might notice a problem if you tried running the above code. In particular, the MS-DOS console uses an ASCII-based character set by default. The and characters are supported in this encoding through the extended 128 upper characters, but the Arabic characters are not. Thus you'll likely see something like ?.?.? in their place. We discuss this among other encoding issues you are likely to run into later in the Encodings section of this chapter. If we added a line to the above code, Console.OutputEncoding = Encoding.UTF8, however, it would solve the problem (assuming the active font for the console supports the extended characters).

So the above conversion seems nice at first. But performing lexical translations without their corresponding data conversions can be confusing and even harmful to applications. If you don't perform the necessary monetary conversion from the source to the target currency — whether it's based on an approximate or a real-time rate (the business scenario should dictate the requirement) — somebody might mistakenly interpret a quantity incorrectly.

To illustrate this fact, imagine a system where business transaction data is stored in a database using U.S. Dollars (USD) denomination. Consider a transaction worth $100.00. If somebody ran your application in England and saw this $100.00 prefixed with a British pound (GBP) symbol, that is, 100.00, they would certainly interpret it incorrectly! A British pound is equivalent to roughly two English dollars. If they performed business transactions using the data as presented, this would lead to trouble. Namely, somebody would end up losing or gaining around $100.00, depending on your perspective.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows