Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 140 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
140
Dung lượng
3,47 MB
Nội dung
To display the information that is associated with a RegionInfo object, in the method ShowRegion Information() a RegionInfo object is constructed passing the selected culture identifier. Then access the properties DisplayName, CurrencySymbol, ISOCurrencySymbol, and IsMetric properties to display this information. private void ShowRegionInformation(int culture) { RegionInfo ri = new RegionInfo(culture); textRegionName.Text = ri.DisplayName; textCurrency.Text = ri.CurrencySymbol; textCurrencyName.Text = ri.ISOCurrencySymbol; checkIsMetric.Checked = ri.IsMetric; } Starting the application you can see all available cultures in the tree view, and selecting a culture lists the cultural characteristics as shown in Figure 17-7. Figure 17-7 Sorting Sorting strings is dependent on the culture. Some cultures have different sorting orders. One example is Finnish where the characters V and W are treated the same. The algorithms that compare strings for sort- ing by default use a culture-sensitive sort where the sort is dependent on the culture. 520 Chapter 17 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 520 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com To demonstrate this behavior of a Finnish sort I have created a small sample Console application where some U.S. states are stored unsorted inside an array. We are going to use classes from the namespaces System.Collections, System.Threading, and System.Globalization, so these namespaces must be declared. The method DisplayNames() shown below is used to display all elements of an array or of a collection on the console: static void DisplayNames(IEnumerable e) { foreach (string s in e) Console.Write(s + “ - “); Console.WriteLine(); } In the Main() method, after creating the array with some of the U.S. states, the thread property CurrentCulture is set to the Finnish culture, so that the following Array.Sort() uses the Finnish sort order. Calling the method DisplayNames() displays all the states on the console. static void Main(string[] args) { string[] names = {“Alabama”, “Texas”, “Washington”, “Virginia”, “Wisconsin”, “Wyoming”, “Kentucky”, “Missouri”, “Utah”, “Hawaii”, “Kansas”, “Lousiana”, “Alaska”, “Arizona”}; Thread.CurrentThread.CurrentCulture = new CultureInfo(“fi-FI”); Array.Sort(names); Console.WriteLine(“\nsorted ”); DisplayNames(names); After the first display of some U.S. states in the Finnish sort order, the array is sorted once again. If we want to have a sort that is independent of the users’ culture, which would be useful when the sorted array is sent to a server or stored somewhere, we can use the invariant culture. We can do this by passing a second argument to Array.Sort(). The Sort() method expects an object implementing IComparer with the second argument. The Comparer class from the System.Collections namespace implements IComparer. Comparer.DefaultInvariant returns a Comparer object that uses the invariant culture for comparing the array values for a culture-independent sort. // sort using the invariant culture Array.Sort(names, Comparer.DefaultInvariant); Console.WriteLine(“\nsorted with invariant culture ”); DisplayNames(names); } Figure 17-8 shows the output of this program: a sort with the Finnish culture and a culture-independent sort are shown in. As you can see in this sort, Washington is listed before Virginia. 521 Localization 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 521 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 17-8 In addition to a locale-dependent formatting and measurement system, depending on the culture strings also have different values or locale-dependent pictures. This is where resources come into play. Resources Resources such as pictures or string tables can be put into resource files or satellite assemblies. Such resources can be very helpful when localizing applications, and .NET has built-in support to search for localized resources. Before we show you how to use resources to localize applications, we discuss how resources can be cre- ated and read without looking at language aspects. Creating Resource Files Resource files can contain such things as pictures and string tables. A resource file is created by using either a normal text file or a .resX file that utilizes XML. We will start with a simple text file. A resource that embeds a string table can be created by using a normal text file. The text file just assigns strings to keys. The key is the name that can be used from a program to get the value. Spaces are allowed in both keys and values. This example shows a simple string table in the file strings.txt: Title = Professional C# Chapter = Localization Author = Christian Nagel Publisher = Wrox Press If sorting a collection should be independent of a culture the collection must be sorted with the invariant culture. This can particularly be useful when sending the sort result to a server or storing it inside a file. 522 Chapter 17 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 522 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ResGen The resgen.exe utility can be used to create a resource file out of strings.txt. Typing resgen strings.txt will create the file strings.resources. The resulting resource file can be added to an assembly either as an external file or embedded into the DLL or EXE. Resgen also supports the creation of XML-based .resX resource files. One easy way to build an XML file is by using ResGen itself: resgen strings.txt strings.resX This command creates the XML resource file strings.resX. We will look at how to work with XML resource files when we look at localization later in this chapter. The resgen utility does not support adding pictures. With the .NET Framework SDK samples, you will get a ResXGen sample with the tutorials. With ResXGen it is possible to add pictures to a .resX file. Adding pictures can also be done programmatically by using the ResourceWriter class, as you will see next. ResourceWriter Instead of using the resgen utility to build resource files, a simple program can be written. ResourceWriter is a class in the System.Resources namespace that also supports pictures and any other object that is serializable. In the following code example, we will create a ResourceWriter object, rw, using a constructor with the filename Demo.resources. After creating an instance, you can add a number of resources of up to 2GB in total size using the AddResource() method of the ResourceWriter class. The first argument of AddResource() specifies the name of the resource and the second argument specifies the value. A picture resource can be added using an instance of the Image class. To use the Image class, you have to reference the assembly System.Drawing. Also add the using directive to open the namespace System.Drawing. Create an Image object by opening the file logo.gif. You will have to copy the picture to the directory of the executable, or specify the full path to the picture in the method argument of Image.ToFile(). The using statement specifies that the image resource should automatically be disposed at the end of the using block. Additional simple string resources are added to the ResourceWriter object. The Close() method of the ResourceWriter class automatically calls ResourceWriter.Generate() to finally write the resources to the file Demo.resources. using System; using System.Resources; using System.Drawing; class Class1 { static void Main() { ResourceWriter rw = new ResourceWriter(“Demo.resources”); 523 Localization 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 523 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com using (Image image = Image.FromFile(“logo.gif”)) { rw.AddResource(“WroxLogo”, image); rw.AddResource(“Title”, “Professional C#”); rw.AddResource(“Chapter”, “Localization”); rw.AddResource(“Author”, “Christian Nagel”); rw.AddResource(“Publisher”, “Wrox Press”); rw.Close(); } } } Starting this small program creates the resource file Demo.resources. The resources will now be used in a Windows application. Using Resource Files You can add resource files to assemblies with the assembly generation tool al.exe, using the /embed option, or the C# compiler csc.exe using the /resource option, or directly with Visual Studio .NET. To see how resource files can be used with Visual Studio .NET, create a C# Windows application and name it ResourceDemo. Use the context menu of the Solution Explorer (Add➪Add Existing Item) to add the previously created resource file Demo.resources to this project. By default, BuildAction of this resource is set to Embedded Resource so that this resource is embedded into the output assembly (see Figure 17-9). Figure 17-9 After building the project, you can check the generated assembly with ildasm to see the attribute .mre- source in the manifest (see Figure 17-10). .mresource declares the name for the resource in the assem- bly. If .mresource is declared public (as in our example), the resource is exported from the assembly and can be used from classes in other assemblies. .mresource private means that the resource is not exported and only available within the assembly. 524 Chapter 17 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 524 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 17-10 When adding resources to the assembly using Visual Studio .NET, the resource is always public as shown in Figure 17-10. If the assembly generation tool is used to create assemblies, we can use command line options to differentiate between adding public and private resources. The option /embed:demo.resources,Y adds the resource as public, while /embed:demo.resources,N adds the resource as private. In our Windows application, we add some text boxes and a picture by dropping Windows Forms ele- ments from the Toolbox to the designer. The values from the resources will be displayed in these Windows Forms elements. Change the Text and Name properties of the text boxes and the labels to the values that you can see in the following code. The name property of the PictureBox control is changed to logo. Figure 17-11 shows the final form in the Forms Designer. The PictureBox control is shown as a rectangle without grid in the upper left-hand corner. To access the embedded resource, use the ResourceManager class from the System.Resources names- pace. You can pass the assembly that has the resources as an argument to the constructor of the Resource Manager class. In this example the resources are embedded in the executing assembly, so pass the result of Assembly.GetExecutingAssembly() as the second argument. The first argument is the root name of the resources. The root name consists of the namespace, with the name of the resource file but without the resources extension. As you have seen earlier, ildasm shows the name. All you have to do is remove the file extension resources from the name shown. You can also get the name programmatically using the GetManifestResourceNames() method of the System.Reflection.Assembly class. If the assembly was generated using Visual Studio .NET, you can change the visibil- ity of the resources later. Use ilasm and select FileÍDump to open the assembly and generate an MSIL source file. You can change the MSIL code with a text editor. Using the text editor, you can change .mresource public to .mresource private. Using the tool ilasm, you can then regenerate the assembly with the MSIL source code: ilasm /exe ResourceDemo.il. 525 Localization 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 525 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 17-11 using System.Reflection; using System.Resources; // public class Form1 : System.Windows.Forms.Form { // private System.Resources.ResourceManager rm; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); Assembly assembly = Assembly.GetExecutingAssembly(); rm = new ResourceManager(“ResourceDemo.Demo”, assembly); Using the ResourceManager instance rm you can get all the resources by specifying the key to the meth- ods GetObject() and GetString(): logo.Image = (Image)rm.GetObject(“WroxLogo”); textTitle.Text = rm.GetString(“Title”); textChapter.Text = rm.GetString(“Chapter”); textAuthor.Text = rm.GetString(“Author”); textPublisher.Text = rm.GetString(“Publisher”); } When you run the code, you can see the string and picture resources (see Figure 17-12). 526 Chapter 17 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 526 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 17-12 Now we will move on to look at localization and the use of resource files with localization. The System.Resources Namespace Before we move on to the next example, we conclude this section with a review of the classes contained in the System.Resources namespace that deal with resources: ❑ The ResourceManager class can be used to get resources for the current culture from assemblies or resource files. Using the ResourceManager, you can also get a ResourceSet for a particular culture. ❑ A ResourceSet represents the resources for a particular culture. When a ResourceSet instance is created it enumerates over a class, implementing the interface IResourceReader, and stores all resources in a Hashtable. ❑ The interface IResourceReader is used from the ResourceSet to enumerate resources. The class ResourceReader implements this interface. ❑ The class ResourceWriter is used to create a resource file. ResourceWriter implements the interface IResourceWriter. ❑ ResXResourceSet, ResXResourceReader, and ResXResourceWriter are similar to ResourceSet, ResourceReader, and ResourceWriter; however, they are used to create a XML-based resource file .resX instead of a binary file. You can use ResXFileRef to make a link to a resource instead of embedding it inside an XML file. Localization Example Using Visual Studio .NET For this section, we create a simple Windows application to show you how to use Visual Studio .NET for localization. This application will not use complex Windows Forms and does not have any real inner 527 Localization 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 527 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com functionality, because the key feature we want to demonstrate here is localization. In the automatically generated source code change the namespace to Wrox.ProCSharp.Localization, and the class name to BookOfTheDayForm. The namespace is not only changed in the source file BookOfTheDayForm.cs, but also in the project settings, so that all generated resource files will get this namespace, too. You can change the namespace for all new items that are created by selecting Common Properties of Project➪Properties. Windows Forms applications will be covered more detailed in the Chapters 19 through 21. To show some issues with localization, this program has a picture, some text, a date, and a number. The picture shows a flag that is also localized. Figure 17-13 shows this form of the application as seen in the Windows Forms Designer. Figure 17-13 The following table lists the values for the Name and Text properties of the Windows Forms elements. Name Text labelBookOfTheDay Book of the day labelItemsSold Books sold textDate Date textTitle Professional C# textItemsSold 30000 pictureFlag In addition to this form, you might want a message box that displays a welcome message; this message might change depending on the current time of day. This example will demonstrate that the localization for dynamically created dialogs must be done differently. In the method WelcomeMessage(), display a message box using MessageBox.Show(). Call the method WelcomeMessage() in the constructor of the form class BookOfTheDayForm, before the call to InitializeComponent(). 528 Chapter 17 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 528 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Here is the code for the method WelcomeMessage(): public void WelcomeMessage() { DateTime now = DateTime.Now; string message; if (now.Hour <= 12) { message = “Good Morning”; } else if (now.Hour <= 19) { message = “Good Afternoon”; } else { message = “Good Evening”; } MessageBox.Show(message + “\nThis is a localization sample”); } The number and date in the form should be set by using formatting options. Add a new method SetDateAndNumber() to set the values with the format option. In a real application, these values could be received from a Web Service or a database, but in this example we are just concentrating on localiza- tion. The date is formatted using the D option (to display the long date name). The number is displayed using the picture number format string ###,###,### where # represents a digit and “,” is the group separator: public void SetDateAndNumber() { DateTime today = DateTime.Today; textDate.Text = today.ToString(“D”); int itemsSold = 327444; textItemsSold.Text = itemsSold.ToString(“###,###,###”); } In the constructor of the BookOfTheDayForm class both the WelcomeMessage() and SetDateAnd Number() methods are called. public BookOfTheDayForm() { WelcomeMessage(); // // Required for Windows Form Designer support // InitializeComponent(); SetDateAndNumber(); } 529 Localization 20 557599 Ch17.qxd 4/29/04 11:38 AM Page 529 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... Culture=neutral, PublicKeyToken=b77a5c561934e089”> Inherit 256 , 20 2 ... name=”textTitle.Text”> Professional C# Left True... from the C# code: 53 1 Chapter 17 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 24, 152 . the assembly with the MSIL source code: ilasm /exe ResourceDemo.il. 52 5 Localization 20 55 759 9 Ch17.qxd 4/29/04 11:38 AM Page 52 5 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure. com- mand-line options fr-fr and the de-de. Figure 17-16 Figure 17-17 53 5 Localization 20 55 759 9 Ch17.qxd 4/29/04 11:38 AM Page 53 5 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com There. satellite assemblies. 53 3 Localization 20 55 759 9 Ch17.qxd 4/29/04 11:38 AM Page 53 3 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 17- 15 Changing the Culture