Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1384 Chapter 30: Localization Response.Write("<b>Culture’s Parent Name:</b> " & ci.Parent.Name.ToString() & _ "<br>") Response.Write("<b>Culture’s Display Name:</b> " & ci.DisplayName.ToString() & _ "<br>") Response.Write("<b>Culture’s English Name:</b> " & ci.EnglishName.ToString() & _ "<br>") Response.Write("<b>Culture’s Native Name:</b> " & ci.NativeName.ToString() & _ "<br>") Response.Write("<b>Culture’s Three Letter ISO Name:</b> " & _ ci.Parent.ThreeLetterISOLanguageName.ToString() & "<br>") Response.Write("<b>Calendar Type:</b> " & ci.Calendar.ToString() & "</p >") End Sub C# protected void Page_Load(object sender, EventArgs e) { CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture; Response.Write("<b><u>CURRENT CULTURE’S INFO</u></b>"); Response.Write("<p><b>Culture’s Name:</b> " + ci.Name.ToString() + "<br>"); Response.Write("<b>Culture’s Parent Name:</b> " + ci.Parent.Name.ToString() + "<br>"); Response.Write("<b>Culture’s Display Name:</b> " + ci.DisplayName.ToString() + "<br>"); Response.Write("<b>Culture’s English Name:</b> " + ci.EnglishName.ToString() + "<br>"); Response.Write("<b>Culture’s Native Name:</b> " + ci.NativeName.ToString() + "<br>"); Response.Write("<b>Culture’s Three Letter ISO Name:</b> " + ci.Parent.ThreeLetterISOLanguageName.ToString() + "<br>"); Response.Write("<b>Calendar Type:</b> " + ci.Calendar.ToString() + "</p >"); } Figure 30-2 1384 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1385 Chapter 30: Localization This bit of code in the Page_Load event checks the CurrentCulture property. You can place the result of this value in a CultureInfo object. To get at this object, you import the System.Globalization namespace into your Web page. The CultureInfo object contains a number of properties that provides you with specific culture information. The following items, which are displayed in a series of simple Response.Write statements, are only a small sampling of what is actually available. Running this page produces results similar to what is shown in Figure 30-2. From this figure, you can see that the en-US culture is the default setting in which the ASP.NET thread executes. In addition to this, you can use the CultureInfo object to get at a lot of other descriptive infor- mation about the culture. You can always change a thread’s culture on the overloads provided via a new instantiation of the CultureInfo object. This is presented in Listing 30-2. Listing 30-2: Changing the culture of the thread using the CultureInfo object VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("th-TH") Dim ci As CultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture Response.Write("<b><u>CURRENT CULTURE’S INFO</u></b>") Response.Write("<p><b>Culture’s Name:</b> " & ci.Name.ToString() & "<br>") Response.Write("<b>Culture’s Parent Name:</b> " & ci.Parent.Name.ToString() & _ "<br>") Response.Write("<b>Culture’s Display Name:</b> " & ci.DisplayName.ToString() & _ "<br>") Response.Write("<b>Culture’s English Name:</b> " & ci.EnglishName.ToString() & _ "<br>") Response.Write("<b>Culture’s Native Name:</b> " & ci.NativeName.ToString() & _ "<br>") Response.Write("<b>Culture’s Three Letter ISO Name:</b> " & _ ci.Parent.ThreeLetterISOLanguageName.ToString() & "<br>") Response.Write("<b>Calendar Type:</b> " & ci.Calendar.ToString() & "</p >") End Sub C# protected void Page_Load(object sender, EventArgs e) { System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("th-TH"); CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture; Response.Write("<b><u>CURRENT CULTURE’S INFO</u></b>"); Response.Write("<p><b>Culture’s Name:</b> " + ci.Name.ToString() + "<br>"); Response.Write("<b>Culture’s Parent Name:</b> " + ci.Parent.Name.ToString() + "<br>"); Response.Write("<b>Culture’s Display Name:</b> " + ci.DisplayName.ToString() + "<br>"); Response.Write("<b>Culture’s English Name:</b> " + ci.EnglishName.ToString() + "<br>"); Response.Write("<b>Culture’s Native Name:</b> " + ci.NativeName.ToString() + "<br>"); Response.Write("<b>Culture’s Three Letter ISO Name:</b> " + ci.Parent.ThreeLetterISOLanguageName.ToString() + "<br>"); Response.Write("<b>Calendar Type:</b> " + ci.Calendar.ToString() + "</p>"); } 1385 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1386 Chapter 30: Localization In this example, only a single line of code is added to assign a new instance of the CultureInfo object to the CurrentCulture property of the thread being executed by ASP.NET. The culture setting enables the CultureInfo object to define the culture you want to utilize. In this case, the Thai language of Thailand is assigned, and the results produced in the browser are illustrated in Figure 30-3. Figure 30-3 From this figure, you can see that the .NET Framework goes so far as to provide the native name of the language used even if it is not a Latin-based letter style. In this case, the results are presented for the Thai language in Thailand, and some of the properties that are associated with this culture (such as an entirely different calendar than is the one used in Western Europe and the United States). Remember that you reference System.Globalization to get at the CultureInfo object. Server-Side Culture Declarations ASP.NET enables you to easily define the culture that is used either by your entire ASP.NET applica- tion or by a specific page within your application. You can specify the culture for any of your ASP.NET applications by means of the appropriate configuration files. In the default install of ASP.NET, no culture is specified as is evident when you look at the global web.config.comments file (meant for documen- tation purposes) found in the ASP.NET 2.0 CONFIG folder ( C: \ WINDOWS \ Microsoft.NET \ Framework \ v2.0.50727 \ CONFIG ). Remember that ASP.NET 3.5 is built on top of ASP.NET 2.0 and uses the same configuration files. In the web.config.comments file, you find a < globalization > section of the config- uration document. This section is presented in Listing 30-3. Listing 30-3: The <globalization> section in the web.config.comments file <globalization requestEncoding="utf-8" responseEncoding="utf-8" fileEncoding="" culture="" uiCulture="" enableClientBasedCulture="false" responseHeaderEncoding="utf-8" resourceProviderFactoryType="" enableBestFitResponseEncoding="false" /> Note the two attributes represented in bold — culture and uiCulture .The culture attribute enables you to define the culture to use for processing incoming requests, whereas the uiCulture attribute 1386 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1387 Chapter 30: Localization enables you define the default culture needed to process any resource files in the application. (The use of these attributes will be covered later in the chapter.) As you look at the configuration declaration in Listing 30-3, you can see that nothing is specified for the culture settings. One option you have when specifying a culture on the server is to define this culture in the server version of the web.config file found in the CONFIG folder. This causes every ASP.NET 3.5 application on this server to adopt this particular culture setting. The other option is to specify these settings in the web.config file of the application as illustrated in Listing 30-4. Listing 30-4: Defining the <globalization> section in the web.config file <configuration> <system.web> <globalization culture="ru-RU" uiCulture="ru-RU" /> </system.web> </configuration> In this case, the culture established for just this ASP.NET application is the Russian language in the country of Russia. In addition to setting the culture at either the server-wide the application-wide level, another option is to set the culture at the page-level. This is illustrated in Listing 30-5. Listing 30-5: Defining the culture at the page level @page using the directive <%@ Page Language="VB" UICulture="ru-RU" Culture="ru-RU" %> This example determines that the Russian language and culture settings are used for everything on the page. You can see this in action by using this @Page directive and a simple calendar control on the page. Figure 30-4 shows the output. Figure 30-4 Client-Side Culture Declarations In addition to using server-side setting to define the culture for your ASP.NET pages, you also have the option of defining the culture with what the client has set as his preference in a browser instance. When end users install Microsoft’s Internet Explorer and some of the other browsers, they have the option to select their preferred cultures in a particular order (if they have selected more than a single culture preference). To see this in action in IE, select Tools ➪ Internet Options from the IE menu. On the 1387 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1388 Chapter 30: Localization first tab provided (General), you see a Languages button at the bottom of the dialog. Select this button and you are provided with the Language Preference dialog shown in Figure 30-5. In this figure, you can see that two cultures are selected from the list of available cultures. To add any additional cultures to the list, select the Add button from the dialog and select the appropriate culture from the list. After you have selected cultures that are present in the list, you can select the order in which you prefer to use them. In the case of Figure 30-5, the Finnish culture is established as the most preferred culture, whereas the U.S. version of English is selected as the second preference. A user with this setting gets the Finnish language version of the application before anything else; if a Finnish version is not available, a U.S. English version is presented. Figure 30-5 After the end user selects, you can use the auto feature provided in ASP.NET 3.5. Instead of specifying a distinct culture in any of the configuration files or from the @Page directive, you can also state that ASP.NET should automatically select the culture provided by the end user requesting the page. This is done using the auto keyword, as illustrated in Listing 30-6. Listing 30-6: Changing the culture to the end user’s selection <%@ Page Language="VB" UICulture="auto" Culture="auto" %> 1388 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1389 Chapter 30: Localization With this construction in your page, the dates, calendars, and numbers now appear in the preferred cul- ture of the requestor. What happens, however, if you have translated resources in resource files (shown later in the chapter) that depends on a culture specification. What if you only have specific translations and so cannot handle every possible culture that might be returned to your ASP.NET page? In this case, you can specify the auto option with an additional fallback option if ASP.NET cannot find the culture settings of the user (such as culture-specific resource files). This usage is illustrated in Listing 30-7. Listing 30-7: Providing a fallback culture from the auto option <%@ Page Language="VB" UICulture="auto:en-US" Culture="auto:en-US" %> In this case, the automatic detection is utilized, but if the culture the end user prefers is not present, then en-US is used. Translating Values and Behaviors In the process of globalizing your ASP.NET application, you may notice a number of items that are done differently than building an application that is devoid of globalization, including how dates are represented and currencies are shown. This next section touches upon some of these topics. Understanding Differences in Dates Different cultures specify dates and time very differently. For instance, take the following date as an example: 08/11/2008 What is this date exactly? Is it August 11, 2008 or is it November 8, 2008I repeat: When storing values such as date/time stamps in a database or other some type of back-end system, you should always use the same culture (or invariant culture) for these items so that you avoid any mistakes. It should be the job of the business logic layer or the presentation layer to convert these items for use by the end user. Setting the culture at the server-level or in the @Page directive (as was discussed earlier) enables ASP.NET to make these conversions for you. You can also simply assign a new culture to the thread in which ASP.NET is running. For instance, look at the code listing presented in Listing 30-8. Listing 30-8: Working with date/time values in different cultures VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Dim dt As DateTime = New DateTime(2008, 8, 11, 11, 12, 10, 10) System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US") Response.Write("<b><u>en-US</u></b><br>") Response.Write(dt.ToString() & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("ru-RU") Response.Write("<b><u>ru-RU</u></b><br>") Response.Write(dt.ToString() & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("fi-FI") Continued 1389 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1390 Chapter 30: Localization Response.Write("<b><u>fi-FI</u></b><br>") Response.Write(dt.ToString() & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("th-TH") Response.Write("<b><u>th-TH</u></b><br>") Response.Write(dt.ToString()) End Sub C# protected void Page_Load(object sender, EventArgs e) { DateTime dt = new DateTime(2008, 8, 11, 11, 12, 10, 10); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Response.Write("<b><u>en-US</u></b><br>"); Response.Write(dt.ToString() + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("ru-RU"); Response.Write("<b><u>ru-RU</u></b><br>"); Response.Write(dt.ToString() + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI"); Response.Write("<b><u>fi-FI</u></b><br>"); Response.Write(dt.ToString() + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("th-TH"); Response.Write("<b><u>th-TH</u></b><br>"); Response.Write(dt.ToString()); } In this case, four different cultures are utilized, and the date/time construction used by that culture is written to the browser screen using a Response.Write command. The result from this code operation is presented in Figure 30-6. Figure 30-6 1390 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1391 Chapter 30: Localization As you can see, the formats used to represent a date/time value are dramatically different from one another — and one of the cultures, the Thai culture (th-TH), even uses an entirely different calendar that labels this year as 2551. Understanding Differences in Numbers and Currencies In addition to date/time values, numbers are constructed quite differently from one culture to the next. How can a number be represented differently in different cultures? Well, it has less to do with the actual number (although certain cultures use different number symbols), and more to do with how the number separators are used for decimals or for showing amounts such as thousands, millions, and more. For instance, in the English culture of the United States (en-US), you see numbers represented in the following fashion: 5,123,456.00 From this example, you can see that the en-US culture uses a comma as a separator for thousands and a period for signifying the start of any decimals that might appear after the number is presented. It is quite different when working with other cultures. Listing 30-9 shows you an example of representing numbers in other cultures. Listing 30-9: Working with numbers in different cultures VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Dim myNumber As Double = 5123456.00 System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US") Response.Write("<b><u>en-US</u></b><br>") Response.Write(myNumber.ToString("n") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN") Response.Write("<b><u>vi-VN</u></b><br>") Response.Write(myNumber.ToString("n") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI") Response.Write("<b><u>fi-FI</u></b><br>") Response.Write(myNumber.ToString("n") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-CH") Response.Write("<b><u>fr-CH</u></b><br>") Response.Write(myNumber.ToString("n")) End Sub C# protected void Page_Load(object sender, EventArgs e) { double myNumber = 5123456.00; System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Response.Write("<b><u>en-US</u></b><br>"); Response.Write(myNumber.ToString("n") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN"); Response.Write("<b><u>vi-VN</u></b><br>"); Continued 1391 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1392 Chapter 30: Localization Response.Write(myNumber.ToString("n") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI"); Response.Write("<b><u>fi-FI</u></b><br>"); Response.Write(myNumber.ToString("n") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-CH"); Response.Write("<b><u>fr-CH</u></b><br>"); Response.Write(myNumber.ToString("n")); } Running this short example produces the results presented in Figure 30-7. Figure 30-7 From this example, you can see that the other cultures represented here show numbers in quite a different format than that of the en-US culture. The second culture listed in the figure, vi-VN (Vietnamese in Viet- nam), constructs a number exactly the opposite from the way it is constructed in en-US. The Vietnamese culture uses periods for the thousand separators and a comma for signifying decimals. Finnish, on the other hand, uses spaces for the thousand separators and a comma for the decimal separator, whereas the French-speaking Swiss use a high comma for separating thousands and a period for the decimal sep- arator. As you can see, it is important to ‘‘translate’’ numbers to the proper construction so that users of your application can properly understand the numbers represented. You also represent numbers is when working with currencies. It is one thing to convert currencies so that end users understand the proper value of an item, but it is another to translate the construction of the currency just as you would a basic number. Each culture has a distinct currency symbol used to signify that a number represented is an actual cur- rency value. For instance, the en-US culture represents a currency in the following format: $5,123,456.00 1392 Evjen c30.tex V2 - 01/28/2008 3:57pm Page 1393 Chapter 30: Localization The en-US culture uses a U.S. Dollar symbol ($), and the location of this symbol is just as important as the symbol itself. For en-US, the $ symbol directly preceeds the currency value (with no space in between the symbol and the first character of the number). Other cultures use different symbols to rep- resent a currency and often place those currency symbols in different locations. Change the previous Listing 30-9 so that it now represents the number as a currency. The necessary changes are presented in Listing 30-10. Listing 30-10: Working with currencies in different cultures VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Dim myNumber As Double = 5123456.00 System.Threading.Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US") Response.Write("<b><u>en-US</u></b><br>") Response.Write(myNumber.ToString("c") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN") Response.Write("<b><u>vi-VN</u></b><br>") Response.Write(myNumber.ToString("c") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI") Response.Write("<b><u>fi-FI</u></b><br>") Response.Write(myNumber.ToString("c") & "<br>") System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-CH") Response.Write("<b><u>fr-CH</u></b><br>") Response.Write(myNumber.ToString("c")) End Sub C# protected void Page_Load(object sender, EventArgs e) { double myNumber = 5123456.00; System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Response.Write("<b><u>en-US</u></b><br>"); Response.Write(myNumber.ToString("c") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN"); Response.Write("<b><u>vi-VN</u></b><br>"); Response.Write(myNumber.ToString("c") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI"); Response.Write("<b><u>fi-FI</u></b><br>"); Response.Write(myNumber.ToString("c") + "<br>"); System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-CH"); Response.Write("<b><u>fr-CH</u></b><br>"); Response.Write(myNumber.ToString("c")); } Run this example to see how these cultures represent currency values, as illustrated in Figure 30-8. From this figure, you can see that not only are the numbers constructed quite differently from one another, but the currency symbol and the location of the symbol in regard to the number are quite differ- ent as well. 1393 . purposes) found in the ASP. NET 2.0 CONFIG folder ( C: WINDOWS Microsoft .NET Framework v2.0 .50 727 CONFIG ). Remember that ASP. NET 3. 5 is built on top of ASP. NET 2.0 and uses the same configuration. new culture to the thread in which ASP. NET is running. For instance, look at the code listing presented in Listing 30 -8. Listing 30 -8: Working with date/time values in different cultures VB Protected. currency in the following format: $5, 1 23, 456 .00 139 2 Evjen c30.tex V2 - 01/28/2008 3: 57 pm Page 139 3 Chapter 30 : Localization The en-US culture uses a U.S. Dollar symbol ($), and the location of