现在的位置: 首页 > 综合 > 正文

Globalization and Localization

2012年10月18日 ⁄ 综合 ⁄ 共 15467字 ⁄ 字号 评论关闭

Globalization of Windows Applications in 20 Minutes Using C#

By rajesh-lal | 1 Sep 2006
Describes the essential features required to enable multiple languages in a Windows application using resource files.
Is your email address OK? You are signed up for our newsletters but your email address has not been reconfirmed in a long time. To make this warning go away please click here to have a confirmation email sent so we can confirm your email address and continue sending you your newsletters. Alternatively, you can update your subscriptions.

Globalization of Windows Application in 20 Minutes

Prelude

There was once a time when multiple language support for a Windows application used to be a three to six months call, but with the advent of .NET, not anymore. Here is a 20 minutes crash course for globalization / localization of a Windows application. I think you'll find it as useful as I do.

Globalization, in simple terms, means enabling an application so that it works in different nationals, similar to how a global company operates in different countries. For a Windows application, globalization means it is intended for worldwide distribution. There are two aspects of globalization:

  • Internationalization: Enabling the application to be used without language or culture barriers, i.e., language and culture information comes from a resource rather than being hard coded in the application.
  • Localization: Translating and enabling the product for a specific locale. Based on a resource file, the application is translated into a language and culture.

Target

  • Modular design: Code Once Use Everywhere (COUE), this is the prime feature which is needed when you globalize an application. All anyone should do is convert any user interface output/message box /labels text etc., to something like frmMain.RM.GetString("10001"). No culture information or resource manager initialization need to be done again in forms or anywhere else.
  • Default language: Saving and retrieving the default language selected by the user in the Registry.
  • Features: How to take care of date/time, multiple forms, images etc.
  • Reusability: Minimum effort when you add a new form to the application.
  • Extensibility: Support for multiple languages like French, Spanish, and English, using resource files for each.

To hold your interest, here is how it looks:

Time starts now

The first thing we need will be three resource files for three languages English, French, and Spanish. I have used Google translate here[^] to accomplish this:

  1. English file name: resource.en-US.txt.
  2. Spanish file name: resource.es-ES.txt.
  3. French file name: resource.fr-FR.txt.

Using the Resource generator (Resgen) in the Visual Studio .NET 2003 Command Prompt, we will create three resource files which can be understood by the application, here is how:

We are done with the resource files which will be used by the application and will look something like this (below) with the extension .resources for each text file:

Put these three .resources files in a Resource folder in the executable path.

Functionality

First run

When the application runs for the first time, we check for the Registry entry language of the application in [HKEY_CURRENT_USER\SOFTWARE\CODE PROJECT\GLOBALIZATION SAMPLE], and returns "en-US" if there is no entry yet. This value is set for the string strCulture of the application.

GetStringRegistryValue in the RegistryAccess class helps us get this:

 Collapse
static public string GetStringRegistryValue(string key, string defaultValue)
{
    RegistryKey rkCompany;
    RegistryKey rkApplication;
    rkCompany = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, 
                false).OpenSubKey(COMPANY_NAME, false);
    if( rkCompany != null )
    {
        rkApplication = rkCompany.OpenSubKey(APPLICATION_NAME, true);
        if( rkApplication != null )
        {
            foreach(string sKey in rkApplication.GetValueNames())
            {
                if( sKey == key )
                {
                return (string)rkApplication.GetValue(sKey);
                }
            }
        }
    }
    return defaultValue;
}

Globalize application

Once we have the strCulture, we call the GlobalizeApp function:

 Collapse
// Resource path
private string strResourcesPath= Application.StartupPath + "/Resources";
// string to store current culture which is comon in all the forms
private string strCulture= "en-US";
//resourcemanager which retrivesthe strings
//from the resource files
private static ResourceManager rm;

private void GlobalizeApp()
{
    SetCulture();
    SetResource();
    SetUIChanges();
}
private void SetCulture()
{
    CultureInfo objCI = new CultureInfo(strCulture);
    Thread.CurrentThread.CurrentCulture = objCI;
    Thread.CurrentThread.CurrentUICulture = objCI;
    
}
private void SetResource()
{
    rm = ResourceManager.CreateFileBasedResourceManager
        ("resource", strResourcesPath, null);

}
private void SetUIChanges()
{
    ...
}

The GlobalizeApp function sets the culture information of the current thread, sets the Resource manager to the respective resource file, andSetUIChnages does all the user interface translations.

Modular design: Code Once Use Everywhere

This, as I said already, is an important feature because when an application expands or grows with time, you should be ready to change a new string with just one statement replacement. For this, I have created a public resource manager in frmMain:

 Collapse
public static ResourceManager RM
{ 
  get 
  { 
   return rm ; 
   } 
}

So, when the main form loads, you set the culture and the resource file information to the public resource manager. And, in the new added form or anywhere you add a message box or label, you can call the resource manager like this:

 Collapse
this.Text = frmMain.RM.GetString("0006");
label1.Text = frmMain.RM.GetString("0008");

Translations

SetUIChanges describes how the translations are done:

  • Texts are directly translated from the resource file
  • Images have to be taken care for using multiple images
  • DateTime etc., which are Windows specific does not need to be translated at all (isn't that cool?)

The code-behind

 Collapse
private void SetUIChanges()
{
    if (String.Compare(strCulture,"en-US")==0)
    { 
        picTop.Image = picE.Image;
    }

    if (String.Compare(strCulture,"es-ES")==0)
    { 
        picTop.Image = picS.Image;
    }

    if (String.Compare(strCulture,"fr-FR")==0)
    { 
        picTop.Image = picF.Image;
    }
    label1.Text=rm.GetString("0001");
    label2.Text=rm.GetString("0002");
    label3.Text=rm.GetString("0003");
    btnSubmit.Text=rm.GetString("0004");
    btnCancel.Text=rm.GetString("0005");
    this.Text = rm.GetString("0000");
    lblselect.Text = rm.GetString("0009");

    lbltime.Text = DateTime.Now.ToLongDateString().ToString(); 
}

For images, I have used three hidden PictureBox controls as shown below:

Saving the default culture in the Registry

The code-behind:

 Collapse
static public void SetStringRegistryValue(string key, string stringValue)
{
    RegistryKey rkSoftware;
    RegistryKey rkCompany;
    RegistryKey rkApplication;

    rkSoftware = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, true);
    rkCompany = rkSoftware.CreateSubKey(COMPANY_NAME);
    if( rkCompany != null )
    {
        rkApplication = rkCompany.CreateSubKey(APPLICATION_NAME);
        if( rkApplication != null )
        {
            rkApplication.SetValue(key, stringValue);
        }
    }
}

Acknowledgement

My humble acknowledgement to my boss who gave me a 6 days deadline, for globalization of an application we have been working on for a year.

What's wrong with the .Resx approach

i got a number of emails asking why not use the .resx approach for each form. Well, here are a few of the reasons. I prefer a single resource file compared to multiple .resx files for each form for three simple reasons:

  1. Maintainability:
  2. Assuming you are taking the .resx files approach:

    Take a simple scenario. By mistake, you have a wrong translation for the "Submit" button, say for the German language. The original translation is "Einreichen", but you initially missed the last n and now, you have "Einreiche" instead of "Einreichen" for Submit buttons throughout your application.

    What you can do to resolve this:

    1. You have to go to each form and change the resource file of the form.
    2. Compile the EXE again, creating the German DLL, and redistribute the whole EXE with setup including the new DLL.

    On the other hand, if you use a single resource file as in this article, "Submit" buttons in all the forms translate into something likeResourceManager.GetString("101").

    If the translation is wrong, just-

    1. Update the initial German text file.
    2. Resgen it and create a resource file.
    3. Overwrite your existing resource file with the updated resource file.

    You are done. Redistribution needs just the lightweight resource file and your EXE will automatically update the Submit buttons everywhere.

  3. Extensibility:
  4. If you have to add another language, say Latino, with the .resx file approach, you have to go to each form and create a resx file for Latino, and compile and create a Latino DLL.

    With the Single Resource file approach, you just have to create another text file with the Latino translation as shown in the example above, Resgen it, and add a menu option for Latino, and you are done. You can have a Latino menu option even earlier, and add the resource file later; you won't even need to re-compile.

  5. Dynamic UI changes:
  6. With resource files, you can have a dropdown menu instead of the radio button in the example, and change the complete UI on the fly to whichever language you fancy. With the .resx and DLL approach, you have to start the application with that localized DLL.

    I think you might be able to dynamically change the UI, but it will be a much more complicated process.

    Another not that important reason is, the Resource file approach creates lightweight .Resources files whereas .resx creates a DLL for each language.

    If you want to go by the standard approach, you can definitely get better results, but will not be as fast as this approach.

And thanks

For coming so far. I hope this 20 minutes was worth it, and give me your comments/ suggestion to improve this.

In action (French)

Article history

  • August 20 2006: First published.
  • September 01 2006: Added comparison with .Resx approach.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

rajesh-lal


Software Developer (Senior)
Nokia Inc.
United States United States

Member

Senior Engineer at Nokia Inc. Mountain View

Author of the following books

1. Creating Vista Gadgets using HTML, CSS, & JavaScript (website). 
2. 
Beginning Smartphone Web Development (website)
3. 
Developing Web Widget with HTML, CSS, JSON and AJAX (website)

 

 

 

Globalization and localization demystified in ASP.NET 2.0

By Vivek Thakur | 30 Sep 2006
This article explains how to globalize an ASP.NET 2.0 website, step by step, with a practical example.
Is your email address OK? You are signed up for our newsletters but your email address has not been reconfirmed in a long time. To make this warning go away please click here to have a confirmation email sent so we can confirm your email address and continue sending you your newsletters. Alternatively, you can update your subscriptions.

Introduction

Globalization and localization are two important processes which every developer should be aware of while creating global products or applications. Though there are many articles which explain the subject well, I did not find a single resource which explains all important concepts regarding globalization/localization, practically and comprehensively. This article aims to provide practical step-by-step approach to globalizing a web application in ASP.NET 2.0.

Background Theory

Globalization is defined as the process of developing a program or an application so that it is usable across multiple cultures and regions, irrespective of the language and regional differences. For example, you have made a small inventory management program and you live in a region where English is the main language, assume England. Now, if you want to sell your program in a different country, let’s say Germany, then you need to make sure that your program displays and takes input in German language.

Localization is the process of creating content, input, and output data, in a region specific culture and language. Culture will decide date display settings (like, mm/dd/yyyy or dd/mm/yyyy), currency display formats etc. Now, the process by which we can make sure that our program will be localized is known as Internationalization or Globalization. In simpler terms, Globalization can be defined as the set of activities which will ensure that our program will run in regions with different languages and cultures.

So, globalization is related to intrinsic code changes to support such changes like using Resource files etc. Whereas, localization is the process of using a particular culture and regional info so that the program uses the local languages and culture. This means translating strings into a particular local language. This covers putting language specific strings in the resource files. Globalization starts in the main construction phase along with the code development. Localization generally comes later.

Globalizing an ASP.NET 2.0 Website

Let’s start with a simple example. For the purposes of explaining localization and keeping things simple, I have created a new website in ASP.NET and C#, called TestSite (source code of the example is included in this article). I have added a Master Page and a default page. This default page has a TextBoxand a Calendar control. The TextBox control has a double number which will represent currency, and we will see how the currency format varies as user selects different languages. The default page looks like this when I run the application:

Default.JPG

I have published the test web application, and you can see the functional version here.

Cultures and Locale

Now, before we move ahead, let me throw some light on cultures and locale.

Languages also depend upon the geographical location. For example, French is spoken in France as well as Canada (besides many other countries). But linguistically speaking, Canadian French is quite different from French spoken in France. Similarly, there are linguistic differences between US English and British English. Therefore, the language needs to be associated with the particular region where it is spoken, and this is done by using locale (language + location).

For example: fr is the code for French language. fr-FR means French language in France. So, fr specifies only the language whereas fr-FR is the locale. Similarly, fr-CA defines another locale implying French language and culture in Canada. If we use only fr, it implies a neutral culture (i.e., location neutral).

How do we define or change the current culture?

There are two properties of the CultureInfo class in the .NET FCL (Framework Class Library) which we can set using the overloaded constructor of the class, and then we can use the class to change the culture of the currently executing thread:

  • UICulture: gets/sets the user interface culture for the currently executing thread. This property helps the runtime to load the resource strings from a specific resource file (which we will see later). This property can take neutral cultures as well as locales. For example:
  •  Collapse
Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr”);

Or,

 Collapse
Thread.CurrentThread.CurrentUICulture = new CultureInfo(“fr-CA”);
  • Culture: gets/sets the region specific culture and formats of currency, dates etc. This needs language as well as location (locale).
  •  Collapse
    Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr-A”); //correct as 
        ///we have given locale 
    Thread.CurrentThread.CurrentCulture = new CultureInfo(“fr”); //wrong, will
                                                               // not work

    Sometimes we need a culture which does not belong to any language or locale, which is invariant of any region/language. For this, we have theCultureInfo.InvariantCulture property. It is used during the internal system processes which need to be culture independent, or to store data which does not need to be displayed directly to the end user.

    Both UICulture and Culture properties can be defined in the Web.Config file under the <GLOBALIZATION>property. They can also be specified at page level. But we don’t want to hard-code these values, and would like to set them dynamically instead. As seen above, we could also get/set these values from the code using the Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICultureproperties. So, we will use these properties in our application.

    Switching Locale

    Coming back to our application, we need a way to switch the locale. There are two approaches regarding this:

    1. Use the browser settings: In IE, the user can change the culture by going to Internet Options->General->Languages. For this to work, we need to set both the Culture and the UICulture to auto and enableClientBasedCulture = true as:
    2.  Collapse
      <GLOBALIZATION culture="auto" uiculture="auto" enableClientBasedCulture="”true”" />
    3. User specified settings: We can give an option for the user to specify and change the culture and the language at runtime. This is the recommended approach, as sometimes the browser itself may not have the user specific culture set (for example, a French tourist might be surfing net in India). Also, sometimes changing Language settings via the browser is blocked.

    Going by the second recommended approach, I have created a section on the top (inside a Panel control) in the Master Page where I have a drop-down with these language options which let the users choose a particular locale. For illustration purposes, I have the option of only four languages to choose from: Hindi, US English, British English, and French.

    For my application to be globalized, I want that whenever the user selects a locale from the language, the following should happen:

    1. All content should be localized: This means that all strings and text should be displayed in the chosen language and locale.
    2. Each control’s caption/content should also show text in local language.
    3. Date and currency formatting should occur according to the chosen locale.

    抱歉!评论已关闭.