You are on page 1of 13

Color profile: Generic CMYK printer profile

Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Resources and
Localization
CHAPTER

7
In this chapter, you will
• Implement localizability for the user interface
• Convert existing encodings
• Implement right-to-left and left-to-right mirroring
• Prepare culture-specific formatting

Localization is rapidly becoming a central part of application development, not only for
building applications that can be used in different languages, but that also accurately
mirror the local culture of the client. Localization becomes paramount when you think
of web sites that will potentially be used by clients from all the corners of the world.

Localization is the process of writing software that is able to sense the user’s locale
and change its behavior based on that information. The user can change his or her locale by
making changes to the Regional Settings in the control panel.
The term culture refers to a combination of parameters and methods that allow a pro-
gram to adjust to the geographical location of the user. For example, the program can
correctly display the currency of a region and print it in the proper location (for exam-
ple, $42.00 for the United States and Canada; 42,00 kr for Sweden). The culture also
contains information on how to display dates and numbers.
One part of localization is the use of strings in the language of the region. In this
chapter you will learn how to use strings from many different cultures to write as generic
a program as possible. This will allow you the freedom to define the strings and re-
sources used in a program in a central store that can be maintained for multiple lan-
guages and locales.
All applications contain resources that can be centralized for better management,
such as the string literals used for labels and button controls. The .NET Framework
draws on the ancestry of Windows to provide resources for strings, images, icons, and
custom resources.

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:22 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


2

String Resources
String resources are language-specific strings that are made available to a program so
that the resource manager can find the properly localized string to use when the applica-
tion is executed on the user’s computer. Using string resources enables you to write code
that has no string literals in it—the literals are defined in either text files or XML-format-
ted resource files.
We will start with our old friend, the Hello World program, and localize it.

Using System;
class Hello
{
public static void Main()
{
Console.WriteLine("Welcome to the Hello Program");
Console.WriteLine("\n\nHello World!");
Console.WriteLine("\n\nSee you Later");
}
}

This program will always display the same thing, irrespective of where in the world it
is executed. To make the program display in German, we would have to create a new ver-
sion for Germany, and yet another version for any other language that might be needed.
This is an almost impossible situation to manage.
The way to start on the road towards localization is to move the strings out from the
program and store them in a separate file. In our example, the file will be named
strings.txt, and it is located in the same directory as the source file for the program.
It has this content:

txtGreeting = Welcome to the Hello Program


txtBye = See you soon.
txtHello = Hello World!

This text file is not directly usable by itself—it needs to be compiled, and the tool that
is used to compile resource files is the resgen utility. To create a resource file from the
strings.txt file that can be embedded in an assembly, use the following command:

resgen strings.txt

The result is a new file named strings.resources that can be used in our program.
We also need to make some changes to our program to be able to use the new re-
source file. First we need to add some namespaces to support localization:

using System.Globalization;
using System.Resources;

System.Globalization adds the support for culture-related information, while


System.Resources adds the support for resources, and most importantly, the Re-
source Manager.

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:22 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


3
Once we have the namespaces added, we can proceed to get a reference to the Re-
source Manager. The Resource Manager is a rather heavy resource for the application, so
you should take care to only create one. The common technique is to create the Re-
source Manager as a static member of the class—the code looks like this:

static ResourceManager rm = new ResourceManager("strings",


Assembly.GetExecutingAssembly());

PART II
EXAM TIP The name of the resource in the ResourceManager
constructor is case-sensitive: “string” is different from “String”.

Now we are ready to use the strings in the string resource file. We do that by using the
GetString() method of the Resource Manager:

Console.WriteLine(rm.GetString("txtHello"));

The final program will be as follows. The CultureInfo object is used to retrieve the
current culture with this statement:

CultureInfo ci = Thread.CurrentThread.CurrentCulture;

The current thread of our program uses the culture of the operating system for the UI
(user interface) culture, the current culture is what the user has configured in the Re-
gional Settings. To make the current thread’s UI culture the same as the current culture,
we use this statement:

Thread.CurrentThread.CurrentUICulture = gh.ci;

We also changed the name of the class to GlobalHello to indicate the global nature of
the program, and the file is now called HelloGlobalWorld.cs. Here’s the revised
program:

using System;
using System.Globalization;
using System.Resources;
using System.Reflection;
using System.Threading;
class GlobalHello {
// create the resource manager once only, it is resource heavy
static ResourceManager rm = new ResourceManager("strings",
Assembly.GetExecutingAssembly());
// create a culture information object
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
public static void Main()
{
GlobalHello gh = new GlobalHello();
// ensure the current thread is using the culture
Thread.CurrentThread.CurrentUICulture = gh.ci;
// Display a welcome
Console.WriteLine(rm.GetString("txtGreeting"));
Console.Write("\n\n");
// say hello world

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


4
Console.WriteLine(rm.GetString("txtHello"));
Console.Write("\n\n");
// say bye
Console.WriteLine(rm.GetString("txtBye"));
}
}

To compile the program use the csc compiler with the /res: switch to indicate the
default (fallback) resource to use:

csc /res:strings.resources HelloGlobalWorld.cs

When you run the program, it will display the following:

C:\gc\global\demo>HelloGlobalWorld
Welcome to the Hello Program

Hello World!

See you soon.

If you go in now and change your Regional Setting in the control panel to French, and
you run the program again, there will not be any change to the output—there are no
French resources defined for the program yet. That’s what we need to do next.
To define language-specific resources, you will need to create a subdirectory under
the directory where the executable is located. For the French language, you use the
two-letter code from the RFC 1766 hierarchy to name the directory for French as fr;
other language codes are en for English, de for German, sv for Swedish, and so on. The
electronic documentation that comes along with Visual Studio .NET contains a com-
plete listing of the codes.
Once the directory is created, you need to create a language-specific string resource file
in the new directory. The following is an example of a language-specific string resource:

txtGreeting = Bienvenue bonjour au programme


txtBye = Voyez-vous plus tard.
txtHello = Bonjour Monde!

In order to make the resource available, you must compile it into a resource file (as
we did earlier for the English version) and then create a satellite assembly (for a refresher
on assemblies, see Chapter 6). It is important to remember that the naming of the file is
critical, and it is case-sensitive. The resource file we used as the fallback was called
strings.txt, so we will call the French version strings.fr.txt. When we com-
pile it using the resgen utility, the resulting resource will be called strings.fr
.resources.
To create the satellite assembly, you need to use the assembly-building utility, al,
as follows:

al /t:lib /culture:fr /embed:strings.fr.resources


/out:HelloGlobalWorld.resources.dll

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


5
Remember that the commands are case-sensitive; the output file must have the same
name as the program (HelloGlobalWorld) and must end with resources.dll.
The result is that there is an assembly in the fr directory. Now use the Regional Set-
tings applet in the control panel to change your region to “French (France)” as in Figure 7-1,
and run the program. The result is as follows:

C:\gc\global\demo>HelloGlobalWorld
Bienvenue bonjour au programme

PART II
Bonjour Monde!

Voyez-vous plus tard.

The language has changed to the language of the client’s Regional Settings.

Localized Formatting
Once the strings are localized, we need to look at the formatting of data such as cur-
rency, numbers, and the date and time. The localization of these items is done through
the boxing (conversion to objects) of the data.
As an example, the following code segment will create an int variable that is then
printed using the boxing of the int to an Int32, on which we can call the ToString

Figure 7-1
The Regional
Options
dialog box

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


6
method (for a refresher in boxing and unboxing see Chapter 2). The formatting string
passed to the method specifies how the data is to be formatted:

int i = 420000000;
Console.WriteLine(" " + i.ToString("N"));

The resulting display depends on the client’s locale, as shown in the following examples:

420 000 000,00 // French


420.000.000,00 // German
420,000,000.00 // English

The boxing technique is an elegant way of ensuring that the client’s locale is honored.
The same technique can be used with other data types, like double and long. The spe-
cial treatment of currency formatting takes the currency sign and position (pre or post)
into consideration, as well as the representation of the decimal and thousands separa-
tor. The following code segment will display the double 42.00 as currency using the cli-
ent’s locale:

double d = 42.00;
Console.WriteLine(" " + d.ToString("C"));

The resulting output will be as follows:

$42.00 // English (United States)


42,00 kr // Swedish (Sweden)
L. 42 // Italian (Italy)
42.00 DM // German (Germany)

EXAM TIP The boxing operation, and the use of the ToString() method
makes the localization of numeric dates seamless.

Date and time values can be treated in the same fashion, and by taking advantage of
the formatting, we can display the date and time in a format familiar to the user. The fol-
lowing code does just that—the key again is to use the ToString() method to perform
the localized action:

DateTime dt = DateTime.Now;
Console.WriteLine(" " + dt.ToString("F"));

The following program is the final version of the HelloGlobalWorld program that is
localized to work with any culture:

using System;
using System.Globalization;
using System.Resources;
using System.Reflection;
using System.Threading;
class GlobalHello {
// create the resource manager once only, it is resource heavy
static ResourceManager rm = new ResourceManager("strings",

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


7
Assembly.GetExecutingAssembly());
// create a culture information object
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
public static void Main()
{
GlobalHello gh = new GlobalHello();
// ensure the current thread is using the culture
Thread.CurrentThread.CurrentUICulture = gh.ci;
// Display a welcome
Console.WriteLine(rm.GetString("txtGreeting"));

PART II
Console.Write("\n\n");
// say hello world
Console.WriteLine(rm.GetString("txtHello"));
Console.Write("\n\n");
// print out some numbers using the culture
// assign the value 420000000 to a variable and display it
int i = 420000000;
Console.Write("{0} " + rm.GetString("txtNumber"), i);
Console.WriteLine(" " + i.ToString("N"));
// print out 42.00 of the default currency for the culture
double d = 42.00;
Console.Write("{0} " + rm.GetString("txtCurrency"), d);
Console.WriteLine(" " + d.ToString("C"));
// print out todays date and week day using the culture
DateTime dt = DateTime.Now;
Console.Write(rm.GetString("txtDate"));
Console.WriteLine(" " + dt.ToString("F"));
// say bye
Console.WriteLine(rm.GetString("txtBye"));
}
}

The string resource that is used would look like this:

txtGreeting = Welcome to the Hello Program


txtBye = See you soon.
txtHello = Hello World!
txtNumber = written in localized format is:
txtCurrency = written using the localized currency:
txtDate = Today is:

Running this program with the regional setting for English would produce this output:

C:\gc\global\demo>HelloGlobalWorld
Welcome to the Hello Program

Hello World!

420000000 written in localized format is: 420,000,000.00


42 written using the localized currency: $42.00
Today is: Tuesday, March 26, 2002 7:53:31 PM

See you soon.

All the strings in this program are localized. There are no string literals used in the code,
nor are the numeric values displayed without using the formatting of the ToString()
method.

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


8

Implementing Right-to-Left
Mirroring and Encoding
For locales that use a right-to-left script direction, you will have to implement the proper
interface for direction, which is done by setting the RightToLeft property to
RightToLeft.Yes for all the controls and forms in the application. The controls on a
form all inherit the RightToLeft property of the form. In Figure 7-2 you can see the
property set to Yes, and that the form’s caption has moved to the right side of the win-
dow bar.
When working with ASP.NET pages, you must also work with RightToLeft script
direction as well as allow the UTF-8 encoding (Unicode characters encoded using UCS
Transformation Format, 8-bit form) to be used to send Unicode characters to the client.

Figure 7-2 Setting the RightToLeft property

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


9
There are two UTF encodings available: UTF-7, which encodes 2-byte wide Unicode
characters in 7-bit characters for the original US-ASCII e-mail systems, and UTF-8,
which encodes Unicode characters as two 8-bit characters for transmission over the net-
work. ASP.NET uses Unicode internally, and by including the following directive at the
top of the ASP.NET page, UTF-8 will be returned to the client:

<%@Page Language="C#" ResponseEncoding="UTF-8"%>

PART II
To set the script direction, the element that needs the direction specified must have
the dir attribute set to rtl, as in the following Hebrew text inserted in the div element:

Best Practices
Localization is a State of Mind; it has to be designed into the application from the begin-
ning. There are some things that must be done to successfully implement a localized ap-
plication, and the following list highlights the most important rules:

• Never use string literals in the code.


• Never set static string values to any interface elements in a form.
• Always build the default (fallback) string resource first, and then add additional
locales as needed.
• Always set the string values for the form and controls from the string resource.
• When adding locales, store them in subdirectories that are named after the locale.

The resources can be stored in satellite assemblies, as we have seen in this chapter,
or they can be added to a strongly-named assembly that is added to the GAC. The
naming of the resources is very important. The Resource Manager uses the names to

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


10
find the requested locale: the format is <name>.<locale>.txt for the strings,
<name>.<locale>.resources for the resource, and finally <application>.re-
sources.dll for the assembly. The Resource Manager is very unforgiving when it
comes to errors in the resources. Any error will be ignored, and the Resource Manager
will use the fallback (default) without any indication of the error having occurred.

Summary
In this chapter you were introduced to the world of localization, and you used string re-
sources to turn our Hello World program into something that works all over the world.
You were also introduced to the RightToLeft script direction, as well as the encoding
needed to send 16-bit Unicode characters over the 8-bit Internet by using the UTF-8
encoding.
The need for localization will only grow as we continue towards a more integrated
world where software, and especially the Internet, will be global products working in
the culture of the client.
The next step in preparing for the C# exams is to look at how our code can be used to
generate its own documentation in XML format.

Test Questions
1. What is the code for the German language?
A. ge
B. gb
C. de
D. dk
2. What namespace contains the ResourceManager class?
A. System.Localization
B. System.Resources
C. System.Globalization
D. System.Threading
3. What is the process called that converts a primitive to a class?
A. Primary
B. Boxing
C. Conversion
D. Encoding
4. Which of the following code segments will correctly display the string resource
txtHello? (All objects are correctly created.)

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


11
A. Console.Write(rm.ToString("txtHello");
B. Console.WriteLine(rm.Strings("txtHello");
C. Console.Write(txtHello.ToString("s"));
D. Console.Write(rm.GetString("txtHello"));
5. What does the following command do?
csc /res:strings.resources HelloGlobalWorld.cs

PART II
A. Builds only the HelloGlobalWorld program.
B. Builds the HelloGlobalWorld and links the fallback resource.
C. Creates an assembly for the HelloGlobalWorld program.
D. Creates a name resolution report for the HelloGlobalWorld program.
6. When localizing a web application, you find that you need to encode Unicode
characters that are sent to the client. What attribute would you set?
A. ResponseEncoding="UTF-8"
B. Encoding="UTF-8"
C. ResponseCode="UTF-8"
D. EncodedResponse="UTF-8"
7. What happens when the Resource Manager fails to find the localized resource
for a locale?
A. It uses the closest locale.
B. It throws an exception.
C. Nothing, the resource will be blank.
D. It uses the fallback resource.
8. What namespace contains the CultureInfo class?
A. System.Localization
B. System.Resources
C. System.Globalization
D. System.Threading
9. Do you have to produce all the locale-specific assemblies before deploying the
application?
A. Yes, the assemblies must be present for the final compile of the application.
B. Yes, the fallback manifest must be built from all the satellite assemblies.
C. Yes, the .NET Framework must update the registry with all the information
at deployment.
D. No, the satellite assemblies can be deployed at will after initial deployment.

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


12
10. In the following code segment, what is the significance of the "Strings" literal?
static ResourceManager rm = new ResourceManager("Strings",
Assembly.GetExecutingAssembly());
A. Arbitrary name for the assembly.
B. The base name of the resource to be loaded.
C. The base name of the assembly to be loaded.
D. Alias for the Resource Manager.
11. Where in the object model is the information relating to the date format stored
for a specific locale?
A. ResourceManager
B. CultureInfo
C. LocalFormat
D. Reflection
12. Your application is called AccountingOne.exe. What must the name of the
French string resource be?
A. AccountingOne.resources.dll
B. strings.resources
C. strings.fr.resources.dll
D. strings.fr.resources
13. What does the attribute dir="rtf" stand for?
A. The direction of RTF files.
B. The encoding of RTF files.
C. The direction for the display of characters.
D. A directory listing of all RTF files.
14. Your application is called AccountingOne.exe. What must the name of the
satellite assemblies be?
A. Accountingone.resources.dll
B. accounting.Resources.dll
C. AccountingOne.resources.dll
D. Accounting.resources.dll

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 7

Chapter 7: Resources and Localization


13
Test Answers
1. C.
2. B.
3. B.
4. D.

PART II
5. B.
6. A.
7. D.
8. C.
9. D.
10. B.
11. B.
12. D.
13. C.
14. C.

P:\010Comp\All-in-1\443-6\ch07.vp
Monday, August 26, 2002 12:11:24 PM

You might also like