Globalizing Your ASP.NET Applications

Taking Advantage of the System.Globalization Namespace

asp:feature

Languages: VB

Technologies: Internationalization | Globalization | System.Globalization

 

Globalizing Your ASP.NET Applications

Taking Advantage of the System.Globalization Namespace

 

By Alex Fedorov

 

This is the first article of a two-part series on the globalization and localization features that are implemented in the Microsoft .NET Framework and available for ASP.NET developers. In this first part, I will look at the globalization features implemented in the System.Globalization namespace through different classes and enumerations. I also will create several example programs that show how to use these features in ASP.NET.

 

The second part of this article will deal with localization. I will explore how cultural information corresponds to language selections and how to create resource-based ASP.NET applications. I will create several examples to show you how to use the ResourceManager class to manage resources stored in resources files and how to use satellite assemblies.

 

Overview

Before I jump into the details, let me define some terms. Globalization is the process of developing a Web application core whose features and code design aren't based on a single language or locale and whose source-code base makes it easier to create editions of the application in different languages. Localization is the process of adapting a Web application so it is appropriate for the area, or locale, for which it is used. In an international market, this means translating the user interface and the content, customizing features (if necessary), and testing the results to ensure the site or program still functions correctly. A localizable application is an application that is ready for translation - all the strings and images are separated from the code.

 

A good localization and globalization solution is an essential part of any multilingual project, and it should be considered during the early stages of the project design. There may be different approaches to technical implementation. For example, I could create a fixed set of Web pages for different languages and store them in separate directories, or I could use online translation software. I also could use in-memory dictionaries (e.g., the Dictionary object that is part of the Microsoft Scripting Engine, the Lookup Table object, or the MessageManager object that is part of the Microsoft Commerce Server 2000) that will be accessed on a per-term basis.

 

Another option is to use the XML-based dictionaries. They serve the same purpose but are more flexible in terms of multilingual support. As for globalization, I can use some limited support available in the ASP object model and create COM objects. That would provide the access to National Language Support functionality of the Microsoft Windows platform and its API.

 

.NET Platform Features

To simplify development of multilingual applications, the .NET platform uses the concepts of culture and region. These concepts, supported by appropriate classes, define the information that contains cultural conventions and regional settings. This information is very useful for the globalization of Web applications.

 

To help Web developers localize their applications, the .NET platform extends the concept of resources to Web applications. Resources in .NET can be stored in files with the resources extension or in satellite assemblies and can be managed through the new ResourceManager class. Resources can be used with normal Windows applications as well as in Web applications. Using Visual Studio .NET allows developers to create all the files required for localization. By simply attaching XML-based resources (resx files) to my project, I easily can create applications that support different languages and provide a fallback for the neutral resource (default language), if the resource for a particular language cannot be found.

 

Globalization

The globalization features available in the .NET Framework are implemented in the System.Globalization namespace through different classes and enumerations.

 

The two main classes for globalization in this namespace are CultureInfo and RegionInfo. The CultureInfo class contains country-specific cultural information, such as language, calendar, sorting, and so on. Note that culture is the client-defined "value." You specify it as the locale when you install your operating system. The RegionInfo class contains region-specific information, such as region name, currency symbol, metric-system indicator, and other information. FIGURE 1 shows the members of the System.Globalization namespace.

 


FIGURE 1: The System.Globalization namespace members.

 

System.Globalization classes include Calendar, which represents time in divisions such as weeks, months, and years. There are different calendars for different cultures: GregorianCalendar, HebrewCalendar, HijriCalendar, JapaneseCalendar, JulianCalendar, KoreanCalendar, TaiwanCalendar, and ThaiBuddhistCalendar. The DateTimeFormatInfo class defines how the selected culture affects the values of the DateTime structure, NumberFormatInfo defines how the selected culture affects numeric values, StringInfo is used to iterate string values, and TextInfo defines code pages and other functions to work with text.

 

Language Negotiation

Language negotiation occurs when the user sets his or her preferred language, in order of preference, in the browser. Then, the browser negotiates with the server to attempt to find a page in a suitable language. For example, in Internet Explorer, you can specify a set of preferred languages by selecting Tools | Internet Options and clicking on the Languages button as shown in FIGURE 2.

 


FIGURE 2: Specifying language prioritization in Internet Explorer.

 

The server code can extract this information later because it's sent as part of the HTTP request and stored in the HTTP_ACCEPT_LANGUAGE variable. (The HTTP_ACCEPT_LANGUAGE variable is supported by most HTTP 1.1 browsers.) Sometimes language negotiation can produce results that aren't suitable for the user. For example, although the default language may be specified as French, the user may prefer to browse the English version of the site. In this case, you might provide a language-selection menu on the start page.

 

Some Web sites use another scenario: They try to guess a user's language preference by looking up the country extension in the IP address. For example, if the user is surfing from proxy.myprovider.co.uk (a provider based in the United Kingdom), the sites assume the user speaks English. This is often a convenient strategy, but is not necessarily the most accurate. For example, many users browse from .com, .net, or similar address suffixes that do not have any obvious relationship to a particular language.

 

To access a user's language preferences in ASP.NET, you can use the UserLanguages property of the HTTPRequest class that contains a weighted string array of client language preferences. The fact that they're weighted means that if the user has specified more than one language, the first one will be the default language, and others will have numeric weights indicating how far the particular language is from the default one. For example, the languages shown in FIGURE 2 have the weighted string array shown in FIGURE 3.

 


FIGURE 3: Language preference weights for the languages specified in FIGURE 2.

 

The source code for the page shown in FIGURE 3 (langpref.aspx) is provided in the download files accompanying this article (see end of article for details).

 

I'll use this feature to create a menu based on client languages that will be used in later examples of this article. Note that although I easily could specify the default language as the main language for an application, it is always better to give the user a chance to change the default language. FIGURE 4 contains the Visual Basic .NET code that populates a list box with the region names, extracted from the list of languages.

 

Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

  Dim UserLangs() As String

  Dim Count As Integer

  Dim Pos   As Integer

  Dim Lang  As String

 

 If Not IsPostBack Then

  UserLangs = Request.UserLanguages

   For Count = 0 To UserLangs.GetUpperBound(0)

    Pos = InStr(1, UserLangs(Count), ";")

     If Pos > 0 Then

      Lang = Left(UserLangs(Count).ToUpper, Pos-1)

     Else

      Lang = UserLangs(Count).ToUpper

     End If

    Pos = InStr(1, Lang, "-")

    If Pos > 0 Then

      Lang = Lang.Substring(Pos, Lang.Length-Pos)

    End If

    LangList.Items.Add(Lang)

   Next Count

  End If

 End Sub

FIGURE 4: Populating the list box with region names.

 

Using RegionInfo Class

Now I am ready to use the RegionInfo class. I'll create an application that will allow me to check various region settings for specified regions. To do this, I need to implement the OnSelectedIndexChanged event handler for my list box that was populated with the code from FIGURE 4. The code for the event handler is shown in FIGURE 5.

 

Sub Index_Changed(sender As Object, e As EventArgs)

  Dim Region As RegionInfo

 

  Region = New RegionInfo(LangList.SelectedItem.Text)

 

   AddRow(RegTable, "Name",        Region.Name)

   AddRow(RegTable, "EnglishName", _

    Region.EnglishName)

   AddRow(RegTable, "DisplayName",   _

    Region.DisplayName)

   AddRow(RegTable, "CurrencySymbol", _

    Region.CurrencySymbol)

   AddRow(RegTable, "ISOCurrencySymbol",   _

    Region.ISOCurrencySymbol)

   AddRow(RegTable, "IsMetric",   Region.IsMetric)

   AddRow(RegTable, "TwoLetterISORegionName", _

    Region.TwoLetterISORegionName)

   AddRow(RegTable, "ThreeLetterISORegionName", _

    Region.ThreeLetterISORegionName)

   AddRow(RegTable, "ThreeLetterWindowsRegionName", _

    Region.ThreeLetterWindowsRegionName)

End Sub

FIGURE 5: This code populates a table with RegionInfo information.

 

On each list-box click, I create a new RegionInfo object with the specified region name and show its attributes. For example, information for the United States is shown in FIGURE 6.

 


FIGURE 6: Regional information for the United States that was populated with information from the RegionInfo class.

 

Note that the IsMetric property value is set to False. That means that for this region, I should perform conversions of the length and weight measurements because the current region does not use the metric system.

 

For all countries that are part of the European Community, the CurrencySymbol property will contain the Euro symbol, and the ISOCurrencySymbol will contain EUR. The Euro currency became the official currency in January. FIGURE 7 shows the regional information for Spain.

 


FIGURE 7: Regional information for Spain. Note the Euro symbol in the CurrencySymbol property.

 

FIGURE 8 shows the members of the RegionInfo class. The complete source code for the RegionInfo page is provided in the download files accompanying this article.

 


FIGURE 8: Members of the RegionInfo class.

 

Using the CultureInfo Class

Before I can build an application that will use the CultureInfo class, I need to modify the code that builds the menu. I need to include the full name of the language in the form ll-RR, in which ll represents the language, and RR the region. This conforms to the RFC 1766 standard, in which language code is a lowercase, two-letter code derived from ISO 639-1 standard; and in which region code is an uppercase, two-letter code derived from ISO 3166 standard. For more information about these standards, refer to the References section at the end of this article. The modified menu-building code is shown in FIGURE 9.

 

Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

  Dim UserLangs() As String

  Dim Count As Integer

  Dim Pos   As Integer

  Dim Lang  As String

 

 If Not IsPostBack Then

  UserLangs = Request.UserLanguages

   For Count = 0 To UserLangs.GetUpperBound(0)

    Pos = InStr(1, UserLangs(Count), ";")

     If Pos > 0 Then

      Lang = Left(UserLangs(Count).ToUpper, Pos-1)

     Else

      Lang = UserLangs(Count).ToUpper

     End If

    LangList.Items.Add(Lang)

   Next Count

  End If

 End Sub

FIGURE 9: Menu-building code.

 

The difference here is that I preserve the language name if it is in the ll-RR form. For languages that contain only the region name, such as FR, DE, ES, and IT in this example, I add the missing part programmatically. I do this in the event handler for the list box, which starts with the following code:

 

Sub Index_Changed(sender As Object, e As EventArgs)

  Dim Culture As CultureInfo

  Dim CID As String

 

  CID = LangList.SelectedItem.Text

  If InStr(1, CID, "-") = 0 Then

     CID += "-" & CID

   End If

 

In .NET terms, the neutral culture is the culture associated with a language but not with a country or region.

 

FIGURE 10 shows the members of the CultureInfo class.

 


FIGURE 10: Members of the CultureInfo class.

 

In .NET, each individual thread maintains its own culture information. The default culture information is available through Thread.CurrentThread.CurrentCulture object of CultureInfo type. To change the current culture, you need to create a new object of CultureInfo type and assign a new culture ID:

 

Culture = New CultureInfo(CID)

 

I will do that in the event handler for the list box:

 

Culture = New CultureInfo(CID)

Thread.CurrentThread.CurrentCulture=Culture

 

After I have changed the current culture to the one the user selected, I can display some of its properties, as shown in FIGURE 11.

 

  With Culture

   AddRow(CultTable, "Name",         .Name)

   AddRow(CultTable, "DisplayName",  .DisplayName)

   AddRow(CultTable, "EnglishName",  .EnglishName)

   AddRow(CultTable, "NativeName", _     

    .TextInfo.ToTitleCase(.NativeName))

   AddRow(CultTable, "Parent",       .Parent.Name)

   AddRow(CultTable, "TextInfo",     .TextInfo.ANSICodePage)

   AddRow(CultTable, "LCID",         .LCID)

   AddRow(CultTable, "Calendar",     .Calendar.ToString())

   AddRow(CultTable, "DateTime",      DateTime.Now.ToString("D", _

     Nothing))

   AddRow(CultTable, "DayNames",      GetDayNames(Culture))

   AddRow(CultTable, "MonthNames",    GetMonthNames(Culture))

  End With

FIGURE 11: Displaying properties of the current culture using an instance of the CultureInfo class.

 

The result of this code, for French language used in Switzerland, is shown in FIGURE 12.

 


FIGURE 12: The cultureinfo.aspx page displays information about a particular culture.

 

In the code shown in FIGURE 11, I'm using several properties of the CultureInfo class as well as other classes. For example, I use the TextInfo instance that allows me to find the code page information for the currently selected culture. TextInfo also allows me to perform lowercase-to-uppercase conversion (ToTitleCase method). I have also used the DateTime.Now method to display the current date in a country-specific format.

 

Two custom functions, GetDayNames and GetMonthNames, are used to create strings with day and month names for the selected language, respectively. The symbol, used to separate the list, is taken from the ListSeparator property of the TextInfo instance. The code for the GetDayNames function is shown in FIGURE 13.

 

 Function GetDayNames(C As CultureInfo) As String

  Dim I         As Integer

  Dim DayNames  As String()

  Dim SDayNames As String

 

  DayNames = C.DateTimeFormat.DayNames

 

   For I=0 to DayNames.GetUpperBound(0)

    SDayNames += DayNames(I)

    If I < DayNames.GetUpperBound(0) Then

     SDayNames += C.TextInfo.ListSeparator & " "

    End If

   Next

   GetDayNames = SDayNames

 

 End Function

FIGURE 13: Code for the GetDayNames function, which is used to create a list of day names for the selected culture.

 

Note that I could achieve the same result by using the DayNames property of the DateTimeFormatInfo class.

 

The complete source code for the CultureInfo page is provided in the accompanying download files.

 

Conclusion

By combining the information found in the RegionInfo and CultureInfo objects, I have all the information required for globalizing a Web application. The next thing to do is localize the application, which involves translating the user interface and all the content. To do so in ASP.NET applications I can use the culture info provided by the CultureInfo class, resources, and the ResourceManager class. I will cover localization of ASP.NET applications in the conclusion of this two-part series.

 

References

 

The complete source code for the projects referenced in this article is available for download.

 

Alex Fedorov is a chief technology officer for Netface SA, based in Lausanne, Switzerland (http://www.netface.ch). He co-authored Professional Active Server Pages 2.0 and ASP Programmer's Reference published by Wrox, as well as Advanced Delphi Developer's Guide to ADO, published by Wordware Publishing. Alex also has contributed several articles to Delphi Informant Magazine.

 

Tell us what you think! Please send any comments about this article to [email protected]. Please include the article title and author.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish