|
Going international with Locale - II
The C# Column - Yashawant Kanetkar
In
the last episode we had designed the greeting form and added code
to change the culture. Let us now add localisation support to it.
After we are done with developing
the form, select the Localized property of the greetform to True.
This property specifies whether localised code is to be generated
for this form. We must now specify the languages that our application
would support. For this, select the Language property. Click the
down arrow. It would display a list of cultures. Select ‘French
(France)’ then select ‘Italian (Italy)’ and ‘German (Germany)’ one
after another. As soon as we select a language, say, French (France),
two resource files ‘greetform.fr.resx’ and ‘greetform.fr-FR.resx’
get added to our project. In these files we need to add French equivalents
for the resources. Add the data as shown in the following table
in the ‘greetform.fr-FR.resx’ file. We will see the purpose of the
‘greetform.fr.resx’ file later.
|
Lname.
|
Text Nom: |
| bgreet. |
Text Saluer |
| bclose. |
Text Fermer |
The following table shows the data to be added
to German and Italian resource files.
| German |
|
| Lname. |
Text Name: |
| Bgreet.Text |
Begrüßen |
| Bclose.Text |
Enden |
| Italian |
|
| Lname.Text |
Nome: |
| Bgreet.Text |
Salutare |
|
Bclose.Text
|
Argomentare |
Now you can run the program.
Select a language and display the greetform. The greetform in Italian
is shown in the following figure.

But there is a problem in
this output. Although resources are appearing in Italian, the greeting
message is still in English. This is because, when we localise resources,
an entry is made in their properties to extract the proper resource
from the appropriate resource file. Since welcome messages are string
literals, their properties are not changed. We have to do this job
ourselves. We also need to make a few changes in the program. Add
the following translations in the resource files for German, French
and Italian.
| French |
|
| GoodMorning |
Bonjour |
| GoodAfternoon |
Bonsoir |
| GoodEvening |
Bonaprèsmidi |
| German |
|
| GoodMorning |
Guten Morgen |
| GoodAfternoon |
Guten Tag |
| GoodEvening |
Guten Abend |
| Italian |
|
| GoodMorning |
Boungiorno |
| GoodAfternoon |
Bounpomeriggio |
| GoodEvening |
Buonasera |
We must also provide default
culture settings for English. For this, we can modify the main resource
file i.e. ‘greetform.resx’. In this file we must add three resource
strings and their English equivalents that happen to be the same.
Change the bgreet_Click(
) handler as given below:
private void bgreet_Click (object sender, System.EventArgs e)
{
ResourceManager r = new ResourceManager("locale_greet.greetform",
Assembly.GetExecutingAssembly());
String s;
DateTime t = DateTime.Now;
if(t.Hour <= 12)
s = r.GetString ("GoodMorning");
else
{
if ( t.Hour <= 19 )
s=r.GetString("GoodAfternoon");
else
s=r.GetString("GoodEvening");
}
s += " " + tname.Text;
lgreet.Text = s;
}
The ResourceManager class
provides methods to work with culture specific resources at run-time.
The ‘locale_greet.greetform’ is the root name of the resources (if
resource file name is "MyResource.en-US.resources" then
the root name is "MyResource") that we want to access
from the current assembly. We have specified a fully qualified name
of the resource file. We have used the ResourceManager.GetString(
) method to extract the value of the resource passed to it as parameter.
Use the System.Resources and the System.Reflection namespace for
the ResourceManager and Assembly classes respectively.
Now run the program again
and confirm that the greetings are displayed in the chosen language.
Behind the scenes
Let’s see what happens behind
the scenes when we localise the form, select the language and compile
the program.
When we set the Localizable
property to true, information about all the resource strings, properties,
embedded pictures, etc, gets stored in the root resource file i.e.
‘greetform.resx’. The following statement gets added to the InitializeComponent(
) method.
ResourceManager resources = new ResourceManager
( typeof ( greetform
) ) ;
The type greetform provided
to the constructor is used to gather all information like assembly
name, root name of resource, etc, for finding the resources. Instead
of assigning values directly to the properties, methods like GetString(
), GetObject( ) are used to retrieve the strings and pictures from
the resource file. Before retrieving the values, the CurrentUICulture
property is checked for the current culture.
On compilation, for every
localised resource, a separate assembly called ‘satellite assembly’
gets created in the folder named after the culture name. We can
find this folder in the ‘bin\ Debug’ folder. The satellite assembly
contains a manifest describing the localised resource. Since resources
are shipped as separate assemblies and not as part of the main assembly,
we can easily replace or update resources corresponding to a specific
culture without replacing the application’s main assembly.
We know that on selecting
the language two resource files get created. One is for specific
culture (greetform.fr-FR.resx) and another for neutral culture (greetform.fr.resx).
To understand the purpose of creating two files, we must first understand
the path in which localised resources are searched.
The localised resources
are searched for in a hierarchical manner. At the top of the hierarchy
is the resources for default culture i.e. English ("en").
Below that are the resources for any neutral culture. Below those
are the resources for any specific cultures. Suppose a user requests
for the resources localised in French (France). The CLR would first
search in the global assembly cache (GAC) for the assembly matching
requested culture ("fr-FR"). If not found, it searches
in the folder of the currently executing assembly for the ‘fr-FR’
folder. If not found it searches the GAC again for the fallback
culture contained in the parent assembly ("fr’). If the parent
assembly is not found, run-time searches all potential levels of
parent assemblies. On failing that, it then uses the resources for
default culture. If we don’t provide the neutral cultures, a problem
may arise in some cases. For example, it may so happen that a machine
contains culture of "fr-CA" and our program loads the
culture "fr-FR". If "fr-FR" is not found, then
run-time would directly load the English culture instead of French
culture that we could provide in neutral "fr" assembly.
 |
Yashavant Kanetkar, one of the first
Express Computer columnists, is an established software expert,
speaker and author with several best-sellers to his credit,
including titles like “Let Us C” and the “Fundas” series. Contact
him at kanet@nagpur.dot.net.in |
|