I’ve been learning about Localization in ASP.NET AJAX and I’m not a big fan of the resources that are currently available so I thought I would write down my thoughts in the hopes that other people might find them useful. It looks like this will be a three part series on Localization in ASP.NET Ajax and this first entry will be about localization in ASP.NET without the Ajax portion.
Edit: After writing this post, I found an excellent resource on the basics of localization in ASP.NET. Rick Strahl, a resource for many in the .NET Community and co-publisher of CoDe magazine, wrote an excellent article a while back on Localization: Introduction to Localization in ASP.NET 2.0. While I’m glad that I went through the process of writing this article and I believe that some of my insights come from a different angle than Rick’s, if you’re just starting out with Localization, his article is a must read.
Another decent resource is ASP.NET 2.0 Localization Features: A Fresh Approach to Localizing Web Applications
Part 3: How to localize ASP.NET AJAX using embedded resources
What is Localization?
Building your application to support multiple cultures and languages is called localization. Localization includes not only displaying information to the user in the language they speak or read, but also displaying information in their culture (i.e. Spanish, Mexico instead of Spanish, Spain).
In the programming world, a culture is defined by a code. For example, en-us stands for English language, United States culture, en-gb stands for English language, Great Britain culture, and de-au stands for German, Austrian culture.
There are also general language codes that don’t specify a culture, en for English, es for Spanish, it for Italian, etc.
When we specify a culture that our application should run under, we are telling the application to display information with that culture in mind. Unfortunately for us developers, we have to help the application along and tell it what we want we’d like localized. The process of instructing our application what should change when we specify a different culture is called localizing our application.
Localizing our ASP.NET Application
One of the great things about ASP.NET is its ability to support localization without too much trouble.
The key steps of localizing our application are
- Determining what needs to be localized (i.e. strings, pictures, currency, dates, and numbers)
- Setting up your application to localize values when they’re displayed to the user (i.e. using resource files and string formatting),
- Getting your application to figure out which culture to apply (implicitly or explicitly setting the current thread’s culture).
Determining What Needs to be Localized
When determining what needs to be localized you need to consider the different types of information that your application provides because almost all of it will need to be localized if you are going to fully support another language and culture. The basics of what needs to be localized are currencies, dates, numbers, strings, and graphics. If you think about it, this covers the majority of your application’s user interface. The other thing that you’ll need to look out for are layout issues. English words tend to be short when compared to say German. If you only allow for 15 characters of space before your line will wrap, the German will look really weird.
Once you’ve determined what in your application needs to change in appearance when the application is running under different cultures you can move onto the next step.
Localizing Displayed Values
Truthfully, this is where 90% of the work in localization takes place. In this step, you need to actually write your code to use localized values. We can break down the things that are localized into two categories: those that ASP.NET will automatically localize for us and those that we have to manually localize.
What ASP.NET can automatically localize are currencies, dates, and numbers. Let’s dive into that a bit deeper by looking at how a date is automatically displayed differently when our application is running in two different cultures.
When I create a new date, I can display it using the ToString() method attached to the Date object. Using the ToString() method automatically displays the date in the current culture’s default format. As you probably know, assuming you’re a U.S. citizen, the U.S. writes its dates our Month/Day/Year (unless you’re military). A lot of the world, including the French, write their dates out Day/Month/Year. If I were running my application under the French culture, I would expect that the date be displayed Day/Month/Year. Lucky for us, ASP.NET takes care of this for us.
A simple page that will display two strings
The code behind that will output the date in the two different formats.
Finally, the outputted display
By setting the culture, I’ve altered how the date automatically displays itself when outputted. As you can see, the time formatting also changes with the French being in 24hr time.
This idea continues through numbers, dates, and currencies. Whenever you use the ToString or String.format methods to output a string from a integer, float, double, date, long, etc. object, ASP.NET internally uses the current culture’s formatting information to alter the display for that culture. (Note: You can override the default culture and by specifying a format provider in the ToString or String.format methods.)
What ASP.NET doesn’t automatically localize we must do manually. The types of objects we must manually localize are strings, images, files, icons, etc. Things where ASP.NET cannot automatically determine what the output should be. This means that we need to help ASP.NET along. We help ASP.NET along using resource (resx) files.
There are two different types of resource files:
- Master Resource File
- Culture Specific Resource Files
Master Resource File
The Master Resource File represents the default (or invariant) culture. This file contains the master list of all things that you are going to manually localize and their default values. A common name for this file is Resource.resx and it does not specify a culture in its name such as Resource.it.resx. (The first part of the name, Resource, is important because it becomes the class name of the compiled resource. As we’ll see if we want to override the default values in a culture specific resource file we must use the same file name.)
Culture Specific Resource Files
Culture Specific Resource files files contain culture specific information. For every culture that we want to support we create a resource file and name it appropriately. For instance, if want to support the Spanish, Mexico culture (es-MX), we need to have a resource file named Resource.es-mx.resx. If we intend to support Italian, we need to have a file named Resource.it.resx. (Notice it has the same first part of the name as our master resource file.)
These resource files contain the overrides for the master resource file. For instance, if we had the resource named “MyText” in the master resource file with the value “Hello World!” and we wanted to override it in Italian resource file, we’d have the same resource named “MyText” but would set its value to “Ciao Mondo!” instead.
Now that you understand the two different types of resource files, let’s look at how they work in ASP.NET
Creating Resource Files in a Website Project
Depending on how we want to use the localized information, resource files can be stored in various locations. For the purposes of this example let’s assume we’re using a website project. The first thing we do is add a special ASP.NET folder called App_GlobalResources to our website application. Once we do that we create the master resource file and add it to App_GlobalResources folder.
We then need to define our resources and their default values. We open up the Resource editor by double clicking on the resource file and add our resources to it.
In the background, Visual Studio is building an XML document that contains our resourced values.
This XML is then converted into a class that we can access in a couple of ways. The easiest way to see how to access the resource is through code behind so that’s create a page and assign our resources to a couple of labels through code behind. (You can also use a databinding expression.)
The Code behind
Note: Accessing resources through the strongly typed auto-generated classes as we do in this brief example performs poorly. Accessing it through a Global Resource Object or implicit or explicit tags performs better. This article explains why it performs poorly.
When we run this we see that our labels are populated with the resources.
Pretty straight forward so far, eh?
But now we want to support the Italian general culture. First, we need to create an Italian resource file and add it to our App_GlobalResources directory.
Now we need to override our two resources so they have Italian values. Using Babel Fish to figure out the translations we end up with a resource file that looks like
Now in a real world application we’d wait for an Italian user to come along and request our page, but since we’re testing this, we’ll force our code to run under the Italian culture (we’ll go over this in detail in the next section).
Now when our page runs we see the Italian text instead of the English.
To demonstrate one final point in this section, let’s add one more culture, es-MX to our application.
In our es-mx resource file, we’ll only override the MyText resource and not the MyOtherText resource.
Updating our code behind so that it uses the es-MX culture instead of the Italian.
And then running the application
Notice how it used the value from the es-mx resource file for the Hello World portion of the page, but it defaulted to the invariant culture file for the Goodbye World portion. It did this because we didn’t override the master file’s MyOtherText resource. What actually happens here is that ASP.NET combines the valid resource files for the current culture, giving higher precedence to the most specific culture file’s value.
In reality, a culture can have three resource files working at once. The invariant, the general language, and the culture specific language. We’ve talked about the invariant resource file and the culture specific language resource file, but we haven’t talked about the general language file. General culture files are those that leave off the culture portion of the code (i.e. MX) and just reflect the language: Resources.es.resx or Resources.en.resx. We can reduce the number of resources we have to override by using this hierarchy of resource files to our advantage and only overriding those that differ between each level.
Figuring Out Which Culture to Apply
In .NET, the culture is attached to the current thread. You can access it through
System.Threading.Thread.CurrentThread.CurrentCulture and System.Threading.Thread.CurrentThread.CurrentUICulture.
In the case that you want to implicitly set the current culture, you really don’t do anything. In this case, the browser sends back the languages it accepts, for example en-us (English U.S.), es-MX (Spanish, Mexico), or it (Italian, general), and the ASP.NET runtime sets the current thread’s culture automatically based upon these values. (The browser sends back these values based upon your browser’s language settings, which you can change in the various browsers.)
In the case that you want to explicitly set the current culture, you have to override the implicit settings.
If wanted to set the current culture to es-MX, we would execute code in the page’s InitializeCulture method that does this.
Once this is done, our page would be running under the Spanish, Mexico culture for both resources and formatting of numbers, currencies, and dates. If you only wanted to access the localized resources, but leave the dates, currencies, and numbers displayed using the current culture, you would leave off the CurrentCulture assignment.
Well, that concludes are somewhat cursory look at localizing an ASP.NET application. The next posts will focus on using resources with ASP.NET Ajax.