Click here to Skip to main content
Click here to Skip to main content

Globalization of Windows Applications in 20 Minutes Using C#

By , 1 Sep 2006
 

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:

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:

// 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, and SetUIChnages 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:

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:

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

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:

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 like ResourceManager.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


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestiongoodmemberHua Yujun31-Mar-13 20:58 
very good
I like programing

GeneralBest Solutionmemberaktaken15-Jan-13 2:41 
I have not seen till now such a best solution,when ever i was searching i was getting code for aspx page but not for windows,this article has solved my issue i will be trying it in vs2010 framework 4,thank you
GeneralMy vote of 4memberMember 932989810-Oct-12 22:21 
Great article. I'm currently facing a similar problem. I don't see how you can use the VS designer with this approach though.
QuestionProblem with length of word when changing the languagemembersky39131-Dec-11 23:31 
Hi, thanks for sharing
I've used your approach and I have problem with length of word
Let's say I have label with text "Jumlah Anak" in Indonesia and next to label is textbox,
when I translate to English, it is "Number of Dependant"
This cause the label will be closed by textbox
How to handle it?
 
Thanks.
Willi
AnswerRe: Problem with length of word when changing the languagememberrajesh-lal2-Dec-11 1:50 
i think that can be easily fixed by changing the size of the UI element.

Omit Needless Words - Strunk, William, Jr.


Have fun Learning Silverlight 4

QuestionMy vote for 5memberjoniwalker220-Oct-11 8:07 
very useful and very simple
 
Thanks
AnswerRe: My vote for 5memberrajesh-lal2-Dec-11 1:49 
thanks

Omit Needless Words - Strunk, William, Jr.


Have fun Learning Silverlight 4

GeneralGlobalizationmemberjaspreet1233-Mar-11 20:52 
Hi Rajesh,
 
The above code does not work in the debug mode and gives the below error:
 
Could not find any resources appropriate for the specified culture (or the neutral culture) on disk.
baseName: resource locationInfo: <null> fileName: resource.resources
 
But strangely it works in the Relase Mode.
 
Can you please explain...
GeneralRe: Globalizationmemberrajesh-lal3-Mar-11 21:59 
check if the resource files are present there which are in release folder

Omit Needless Words - Strunk, William, Jr.


Learn to Develop Web Widget

GeneralMy vote of 4memberdarth_toni21-Oct-10 1:36 
i like it
GeneralMy vote of 5memberRick Benadez8-Aug-10 10:47 
Very Useful
GeneralRe: My vote of 5memberrajesh-lal2-Dec-11 1:49 
thanks

Omit Needless Words - Strunk, William, Jr.


Have fun Learning Silverlight 4

GeneralMy vote of 3memberKommrad Homer27-Jul-10 1:58 
this is nice.nothing unique though. thanks for sharing
GeneralWeb ApplicationmemberGlen Harvy13-Dec-09 10:31 
Hi,
 
I have been using this most successfully for a few years with my forms application and now my users have demanded a web application version.
 
Has anyone been able to port this to an asp.net application. If so, could they please post the code necessary to achieve it.
 
PS: asp.net is not my forte and hence the need for some real-world example that I can learn from please.
 
TIA.
 
Glen Harvy

Questionchange languagememberanahita2230-Jul-09 5:46 
hi,how can i change my current form language to other language,?Rose | [Rose]
QuestionHow to use this method for controls, programmatically?memberAniket Salunkhe30-Jul-08 8:18 
Hi Quartz,
 
Thank you very much for the information you have provided in this article.
 
Can explain how to use same method, u have explained in your article, to set values of control's properties?
I was not able to use 'ComponentResourceManager', to set control values, using your method & resource ( generated from from resx file).
 

Best Regards,
Aniket A. Salunkhe
Generalhellomemberkhanbtech6-May-08 22:34 
nice article
it is possible to do this dynamically in runtime
i mean without enter predefined text
if possible means plz instruct me
khanbtech@gmail.com
Generalen-US woes [modified]memberGlen Harvy5-Apr-08 7:46 
First - thanks for this excellent introduction to localization & globalization.
 
I have a problem and I would like you to explain why this is so.
 
My project is written here in Australia where my computer is set to en-AU which in the case of datatime is the same as en-UK. The program as it currently stands seems to work well globally - well at least in Countries with en-UK and es-ES - I have had no reports that it doesn't anyhow.
 
I am now trying to create a Spanish version and have followed your example with two selectable options - en-US and es-ES. As far as the UI is concerned, everything works well except.....
 
Here's the problem:
 
If I set Thread.CurrentThread.CurrentCulture = objCI (as in your example), to en-US my dateTime related functions in use with my dataset are broken ie. select item where date = 6/4/2008 (meaning April 6th) are returning June 4th.
 
As I am only really concerned with the UI (I'm relying on .Net to handle the machines culture) why are you changing both culture settings?
 
Naturally I am concerned that the changes I'm making won't break my program so can you confirm that changing the UI culture only will also achieve the desired result.
 
Thanks.
 
Glen Harvy
modified on Saturday, April 5, 2008 6:43 PM

NewsYou may like to rethink on you single file approachmemberAngel inc.28-Dec-07 0:36 
Hi ,
I like your code and used to think the your way till I read this article
http://www.microsoft.com/globaldev/handson/dev/muiapp.mspx#ERC[^]
 
PS: With Tool like WinRes localization becomes a easy job(after full development).
Event if you use things like dynamic control, it has nothing to do with single file or multi-file resource assembly. You will have to handle it in your code.
 
Another important thing:
Consider you application supports 20 languages, using a single resource file approach, the entire resource assembly will be loaded in the memory if you only wish to work with one language.
 
Thanks
GeneralRe: You may like to rethink on you single file approach [modified]memberQuartz.28-Dec-07 5:01 
thats a great link thanks for sharing
 
i am aware of those two approaches, i think a good comparision between all the three approaches allows the user more flexibility and choice
 
Rajesh
 

Omit Needless Words - Strunk, William, Jr.

Like tricks, Vista? Daily Tricks Vista Gadget, Trick of Mind
modified on Saturday, April 5, 2008 10:34 PM

QuestionGlobalization - issues with chinese numeric conversionmemberAnima27-Dec-07 2:28 
Hi All,
 
I have a WPF application which supports globalization. But if user tries to enter Chinese numbers using IME pad in a numeric only textbox, the conversion logic to convert this entry to integer is failing.
 
Code I am using for conversion is:
 
private bool IsNumeric(char valueToCheck)
{
 
int result = new int();
return int.TryParse(valueToCheck.ToString(), System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture, out result);
}
 

 
I am checking if the entry is numeric or not, but this is returning false for chinese numbers Sigh | :sigh: .
 
I have set the culture of the application to Chinese by executing below lines:
 
string culture = "zh-CN";
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo(culture);
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo(culture);
 
Thanks in advance
Anima
JokeScreenshots BrokenmemberJames Murray11-Dec-07 11:20 
Ahh...I was "looking" at your article, and all of a sudden I lost "interest".
 
Alas....the screenshots are broken...must....have...screenshots...
GeneralRe: Screenshots BrokenmemberQuartz.26-Dec-07 7:56 
it was caused by codeproject upgrade it is fixed i think now
 

Omit Needless Words - Strunk, William, Jr.

Like tricks, Vista? Daily Tricks Vista Gadget, Trick of Mind

GeneralCopyright Symbol, Possibly Others!memberandyr200524-Sep-07 1:34 
Hi,
 
I have entered the © symbol to a string in my resource file, and built it. Now, when I call the string to the interface, it returns a small square.
 
Any help appreciated.
 
Thanks, Andrew.
GeneralRe: Copyright Symbol, Possibly Others!memberQuartz.24-Sep-07 4:57 
resource files allows all special kind of characters
look for where you are printing that in the interface
 

Omit Needless Words - Strunk, William, Jr.

Vista? Photoshop Preview Handler

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 1 Sep 2006
Article Copyright 2006 by Raj Lal
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid