Lesson 1: Choosing an Approach
Before you begin the process of localization, you need to understand the advantages and disadvantages of the different approaches to globalizing Web applications. In this lesson, you ll learn about three different ways to structure your application for globalization. These approaches are organized from simplest to most complex. The last approach is covered in more detail in Lesson 2.
After this lesson, you will be able to
Choose a globalization approach that best meets your needs
Detect and respond to a user s culture
Create a culture-specific Web application using settings in Web.config
Change the culture used within your application to evaluate dates, format currencies, and handle other culture-dependent tasks
Detect the culture currently in use by the application
Explain the difference between the CurrentCulture and CurrentUICulture properties
Estimated lesson time: 30 minutes
Ways to Globalize Web Applications
There are several different approaches to creating Web applications that support multiple cultures. Each approach is based on the globalization tools that the .NET Framework provides. Choose a single approach or a combination of approaches based on your applications needs, as described in Table 15-1.
All three of the approaches depend on detecting the user s culture at run time and then forming a response based on that information. The following sections show in greater detail how to detect the user s culture and respond by using each of these approaches. These sections also provide more detail on the relative advantages of each approach.
Approach | Description | Best for |
Detect and redirect | Create a separate Web application for each supported culture, and then detect the user s culture and redirect the request to the appropriate application. | Applications with lots of text content that requires translation and few executable components. |
Run-time adjustment | Create a single Web application that detects the user s culture and adjusts output at run time using format specifiers and other tools. | Simple applications that present limited amounts of content. |
Satellite assemblies | Create a single Web application that stores culture-dependent strings in resource files that are compiled into satellite assemblies. At run time, detect the user s culture and load strings from the appropriate assembly. | Applications that generate content at run time or that have large executable components. |
Detecting the User s Culture
The .NET Framework provides components for supporting multiple cultures and language in the System.Globalization namespace. The CultureInfo, Calendar, and comparison classes that you use throughout this chapter are all part of that namespace. Use the following line to import that namespace so that you can use its classes without qualifying the references:
Visual Basic .NET
Imports System.Globalization
Visual C#
using System.Globalization;
Microsoft ASP.NET uses the Request object s UserLanguages property to return a list of the user s language preferences. The first element of the array returned by UserLanguages is the user s current language. You can use that value to create an instance of the CultureInfo class representing the user s current culture.
To get the user s culture at run time, follow these steps:
Get the Request object s UserLanguages property.
Use the returned value with the CultureInfo class to create an object representing the user s current culture.
For example, the following code gets the user s culture and displays the English name and the abbreviated name of the culture in a label the first time the page is displayed:
Visual Basic .NET
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Run the first time the page is displayed If Not IsPostBack Then Dim sLang As String ' Get the user's preferred language. sLang = Request.UserLanguages(0) ' Create a CultureInfo object from it. Dim CurrentCulture As New CultureInfo(sLang) lblCulture.Text = CurrentCulture.EnglishName & ": " & _ CurrentCulture.Name End If End Sub
Visual C#
private void Page_Load(object sender, System.EventArgs e) { // Run the first time the page is displayed if (!IsPostBack) { // Get the user's preferred language. string sLang = Request.UserLanguages[0]; // Create a CultureInfo object from it. CultureInfo CurrentCulture = new CultureInfo(sLang); lblCulture.Text = CurrentCulture.EnglishName + ": " + CurrentCulture.Name; } }
TIP
The CultureInfo class s Name property and the Request object s UserLanguages array values use different capitalization schemes. If you re comparing the two values, be sure to convert the Name property to lowercase.
Redirecting to Culture-Specific Web Applications
Conceptually, redirecting is the simplest way of dealing with multiple cultures. When a user requests the default page for your application, you detect his or her culture and then redirect the response to the appropriate Web application, as shown in Figure 15-1.
Figure 15-1. Detect and redirect
This approach has some advantages in addition to conceptual simplicity:
Content is maintained separately, so this approach allows the different applications to present very different information, if needed.
Users can be automatically directed to sites that are likely to be geographically close, and so can better meet their needs.
Content files (Web forms and HTML pages, for example) can be authored in the appropriate natural language without the complexity of including resource strings.
Maintaining content separately is best suited for Web applications that present large amounts of content that must be translated or otherwise changed for other cultures. Using this approach requires that the executable portion of the Web application be compiled and deployed separately to each culture-specific Web site. This requires more effort to maintain consistency and to debug problems across Web sites.
Redirecting Based on Primary Language
Both the Request object s UserLanguages array and the CultureInfo class s Name property return culture information in two parts: the first two letters are the language code; the last two letters contain a region code. For example, English US (en-US) and English United Kingdom (en-GB) both use English, but they display different currencies and date order.
To redirect requests based on language alone, follow these steps:
Get the user s preferred language or CurrentCulture, as shown previously.
Get the first two letters of the returned value.
Compare those letters to the list of language codes.
For example, the following code detects the user s language and then redirects the user to one of several different language-specific Web sites:
Visual Basic .NET
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim sLang As String ' Get the user's preferred language. sLang = Request.UserLanguages(0) ' Get the first two characters of language. sLang = sLang.Substring(0, 2) ' Redirect user based on his/her culture. Select Case sLang Case "en" ' Use US site. Response.Redirect("http://www.contoso.com/usa") Case "es" ' Use Spanish site. Response.Redirect("http://www.contoso.com/es") Case "de" ' Use German site. Response.Redirect("http://www.contoso.com/de") Case "zh" ' Use Chinese site. Response.Redirect("http://www.contoso.com/zh") Case Else ' Use US site. Response.Redirect("http://www.contoso.com/usa") End Select End Sub
Visual C#
private void Page_Load(object sender, System.EventArgs e) { // Get the user's preferred language. string sLang = Request.UserLanguages[0]; // Get the first two characters of language. sLang = sLang.Substring(0, 2); // Redirect user based on his/her culture. switch (sLang) { case "en": // Use US site. Response.Redirect("http://www.contoso.com/usa"); break; case "es": // Use Spanish site. Response.Redirect("http://www.contoso.com/es"); break; case "de": // Use German site. Response.Redirect("http://www.contoso.com/de"); break; case "zh": // Use Chinese site. Response.Redirect("http://www.contoso.com/zh"); break; default: // Use US site. Response.Redirect("http://www.contoso.com/usa"); break; } } }
See the CultureInfo Class topic in the Microsoft Visual Studio .NET online Help for a listing of the language and culture codes.
Setting Culture in Web.config
Use the Web.config file s globalization element to create a culture-specific Web application. The culture attribute of the globalization element specifies how the Web application deals with various culture-dependent issues, such as dates, currency, and number formatting.
Web.config globalization settings in subordinate folders override the globalization settings in the application s root Web.config file. You can store content for various cultures in subfolders within your application, add Web.config files with the globalization settings for each culture, then direct users to the appropriate folder based on the user s CurrentCulture. For example, the following Web.config entry handles the Web application s requests and responses using the Arabic (Saudi Arabia) [ar-SA] culture:
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="ar-SA" />
At run time, the Web application displays dates, currency, and number formats according to the culture attribute setting in the Web.config s globalization element, as shown in Figure 15-2.
Figure 15-2. A culture-specific response
In Figure 15-2, the dates, times, numbers, and currencies are displayed using the Arabic (Saudi Arabia) settings. However, the entire page is not displayed in right-to-left formatting, as you might expect for Arabic. To display the page correctly, you must set the HTML dir attribute for the page s body element, as shown here:
<body dir="rtl">
You can use the dir attribute individually in panels, text boxes, or other controls as well. Setting the dir attribute on the body element applies right-to-left formatting to the entire page, as shown in Figure 15-3.
Figure 15-3. Right-to-left formatting
Adjusting to Current Culture at Run Time
By default, Web applications run on the server using a neutral culture. Neutral cultures represent general languages, such as English or Spanish, rather than a specific language and region. When you set the culture attribute for a Web application in Web.config, ASP.NET assigns that culture to all the threads running for that Web application. Threads are the basic unit to which the server allocates processor time ASP.NET maintains multiple threads for a Web application within the aspnet_wp.exe worker process.
Using Web.config to set the culture creates a static association between the application and a specific culture. Alternatively, you can set the culture dynamically at run time using the Thread class s CurrentCulture property, as shown here:
Visual Basic .NET
Imports System.Globalization Imports System.Threading Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim sLang As String ' Get the user's preferred language. sLang = Request.UserLanguages(0) ' Set the thread's culture to match the user culture. Thread.CurrentThread.CurrentCulture = New CultureInfo(sLang) End Sub
Visual C#
using System.Globalization; using System.Threading; private void Page_Load(object sender, System.EventArgs e) { // Get the user's preferred language. sLang = Request.UserLanguages[0]; // Set the thread's culture to match the user culture. Thread.CurrentThread.CurrentCulture = new CultureInfo(sLang); }
The preceding code detects the user s culture and then sets the culture of the current thread to match. ASP.NET will then format date, currency, and numeric strings using the user s culture.
Setting the culture dynamically at the thread level has the following advantages over creating separate Web applications for each culture:
All cultures share the same application code, so the application doesn t have to be compiled and deployed for each culture.
The application resides at a single Web address you don t need to redirect users to other Web applications.
The user can choose from a full array of available cultures.
Setting the culture dynamically is best suited for simple Web applications that don t contain large amounts of text that must be translated into different languages. To provide large amounts of translated content through a single Web application, use the technique described in the section Using Satellite Assemblies, later in the chapter.
Setting the Current Culture
The following code illustrates the main advantages of setting the culture dynamically at the thread level. The first time the page loads, the code builds a list of all available cultures and stores them in a drop-down list box. When the user chooses a culture from the drop-down list, the code assigns that culture to the current thread, and ASP.NET displays the Web form using the selected culture.
Visual Basic .NET
Imports System.Globalization Imports System.Threading Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Add cultures to drop-down ' list box the first time the page is displayed. If Not IsPostBack Then ' Create an array of specific cultures. Dim arrCultures() As CultureInfo = _ CultureInfo.GetCultures(CultureTypes.SpecificCultures) Dim item As CultureInfo ' For each specific culture For Each item In arrCultures ' Add the name of the culture as an item in the list box. drpCulture.Items.Add(New ListItem(item.EnglishName, item.Name)) ' If the item is the thread's current culture, select it. If item.Name = Thread.CurrentThread.CurrentCulture.Name Then ' Select this list item drpCulture.SelectedIndex = drpCulture.Items.Count - 1 End If Next End If End Sub Private Sub drpCulture_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles drpCulture.SelectedIndexChanged ' Change the culture of the current thread to match selection. Thread.CurrentThread.CurrentCulture = New _ CultureInfo(drpCulture.SelectedItem.Value) ' Get the culture for the selected item. Dim SelectedCulture As New CultureInfo(drpCulture.SelectedItem.Value) End Sub Private Sub Page_PreRender(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.PreRender ' Display the culture's native name in the heading. head1.InnerHtml = Thread.CurrentThread.CurrentCulture.NativeName ' Display Date, Currency, and Numeric strings formatted for the culture. Label1.Text = DateTime.Now.ToString("F") Label2.Text = 1234567890.ToString("C") Label3.Text = 1234567890.ToString("N") End Sub
Visual C#
using System.Globalization; using System.Threading; private void Page_Load(object sender, System.EventArgs e) { // Add cultures to drop-down // list box the first time the page is displayed. if (!IsPostBack) { // Create an array of specific cultures. CultureInfo[] arrCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures); // For each specific culture foreach (CultureInfo item in arrCultures) { // Add the name of the culture as an item in the list box. drpCulture.Items.Add(new ListItem(item.EnglishName, item.Name)); // If the item is the thread's current culture, select it. if (item.Name == Thread.CurrentThread.CurrentCulture.Name) // Select this list item drpCulture.SelectedIndex = drpCulture.Items.Count - 1; } } } private void drpCulture_SelectedIndexChanged(object sender, System.EventArgs e) { // Change the culture of the current thread to match selection. Thread.CurrentThread.CurrentCulture = new CultureInfo(drpCulture.SelectedItem.Value); // Get the culture for the selected item. CultureInfo SelectedCulture = new CultureInfo(drpCulture.SelectedItem.Value); } private void Page_PreRender(object sender, System.EventArgs e) { // Display the culture's native name in the heading. head1.InnerHtml = Thread.CurrentThread.CurrentCulture.NativeName; // Display Date, Currency, and Numeric strings formatted for the culture. Label1.Text = DateTime.Now.ToString("F"); Label2.Text = 1234567890.ToString("C"); Label3.Text = 1234567890.ToString("N"); }
The preceding code sets the heading and label text in the PreRender event so that the culture change takes place before the text is stored in those controls. The ToString method uses format specifiers to format each string according to the current culture. For more information about format specifiers, see the Formatting Types topic in the Visual Studio .NET online Help. Figure 15-4 shows the preceding code in action on a Web form.
Figure 15-4. Setting the culture at the thread level
When the user selects a new culture from the drop-down list in Figure 15-4, the heading, calendar, date, currency, and numeric strings are translated automatically.
Responding to the Thread s Culture
You can also get the culture that a Web application is running under by using the thread s CurrentCulture property. For example, the following code displays a panel on a Web form using right-to-left formatting if the current culture is Arabic or Hebrew:
Visual Basic .NET
Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Get culture of current thread. Dim CurrentCulture As CultureInfo = Thread.CurrentThread.CurrentCulture ' Get the primary language. Dim sLang As String = CurrentCulture.Name.Substring(0, 2) ' If it's Arabic or Hebrew, display right-to-left. If sLang = "ar" or sLang = "he" Then panel1.Attributes.Add("dir", "rtl") End If End Sub
Visual C#
private void Page_Load(object sender, System.EventArgs e) { // Get culture of current thread. CultureInfo CurrentCulture = Thread.CurrentThread.CurrentCulture; // If culture is Arabic or Hebrew, use right-to-left layout. string sLang = CurrentCulture.Name.Substring(0, 2); if ((sLang == "ar") (sLang == "he")) { Panel1.Attributes.Add("dir", "rtl"); } }
Using Satellite Assemblies
The preceding section showed you how to handle cultural differences within a single Web application, but it omitted one important detail: how do you handle translated content? That s a job for satellite assemblies.
Satellite assemblies allow you to store the translated strings for each culture in a separate, resource-only assembly file that you can load automatically based on the setting of the CurrentUICulture property. Using satellite assemblies provides the same advantages as adjusting to the culture at run time, plus satellite assemblies simplify displaying content from multiple translated sources. The next lesson describes how to create and use satellite assemblies in detail.