Have a question? ask www.kenlet.com
Home  |  FAQ  |  About  |  Contact  |  View Source   
 
SEARCH:
 
BROWSE:
    My Hood
Edit My Info
View Events
Read Tutorials
Training Modules
View Presentations
Download Tools
Scan News
Get Jobs
Message Forums
School Forums
Member Directory
   
CONTRIBUTE:
    Sign me up!
Post an Event
Submit Tutorials
Upload Tools
Link News
Post Jobs
   
   
Home >  Tutorials >  C# >  String Localization in C#
Add to MyHood
   String Localization in C#   [ printer friendly ]
Stats
  Rating: 4.56 out of 5 by 16 users
  Submitted: 02/01/02
Peter Huene ()

 
Localization is an important part of global software distribution. Localizing software opens up new markets around the world. We will demonstrate in this tutorial how to use localized strings in a simple C# WinForm application.

Localization Overview
Localization is the process of converting software user interfaces to a user’s local culture. For the most part, localization involves converting text strings into the language of the local culture, but it can also involve time, date, and number formats, for example.

In this tutorial, we will build a simple WinForm application that takes a user’s full name as input, and displays a greeting message box to the user. The application will support three separate languages, and easily allow for future languages with its framework.

Our application will go from this:
How boring, its in English! :(

To this:
Oooh la la, its in French!

With just a simple radio button check.

Please note: I am not multi-lingual in the human language sense of the term. Therefore, I have used the fish to translate from English into the other two languages. There will probably be some semantically incorrect translations, so please forgive me.

Step 1: Create a New WinForm Application
Go ahead and create a new C# Windows Application under New | Project. Call this project "LocalizationSample". You should now have the IDE form editor open with a blank form. Rename "Form1.cs" to "LocalizationSampleForm.cs". We are going to replace the form code with the form code I used for this application in the next step.

Step 2: Replace Blank Form Code With Code Specified
Replace the code in LocalizationSample.cs with the following code:
using System;
using System.ComponentModel;
using System.Collections;
using System.Windows.Forms;
using System.Resources;
using System.Globalization;
using System.Threading;

namespace LocalizationSample
{
    public class LocalizationSampleForm : Form
    {
        private TextBox          textFirstName;
        private TextBox          textLastName;
        private Label            labelFirstName;
        private Label            labelLastName;
        private Label            labelChoose;
        private Button           buttonGreetMe;
        private RadioButton      radioEnglish;
        private RadioButton      radioFrench;
        private RadioButton      radioSpanish;

        // Required variable for the designer
        private Container components = null;

        public LocalizationSampleForm()
        {
            // Initialize the components
            InitializeComponent();
        }

        // Clean up
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.textFirstName = new System.Windows.Forms.TextBox();
            this.labelLastName = new System.Windows.Forms.Label();
            this.labelFirstName = new System.Windows.Forms.Label();
            this.buttonGreetMe = new System.Windows.Forms.Button();
            this.radioFrench = new System.Windows.Forms.RadioButton();
            this.labelChoose = new System.Windows.Forms.Label();
            this.textLastName = new System.Windows.Forms.TextBox();
            this.radioEnglish = new System.Windows.Forms.RadioButton();
            this.radioSpanish = new System.Windows.Forms.RadioButton();
            this.SuspendLayout();
            
            // 
            // labelLastName
            // 
            this.labelLastName.Location = new System.Drawing.Point(20, 58);
            this.labelLastName.Name = "labelLastName";
            this.labelLastName.Size = new System.Drawing.Size(165, 16);
            // 
            // labelFirstName
            // 
            this.labelFirstName.Location = new System.Drawing.Point(20, 26);
            this.labelFirstName.Name = "labelFirstName";
            this.labelFirstName.Size = new System.Drawing.Size(165, 16);
            // 
            // textFirstName
            // 
            this.textFirstName.Location = new System.Drawing.Point(176, 22);
            this.textFirstName.Name = "textFirstName";
            this.textFirstName.Size = new System.Drawing.Size(209, 20);
            this.textFirstName.TabIndex = 1;
            this.textFirstName.Text = "";
            // 
            // textLastName
            // 
            this.textLastName.Location = new System.Drawing.Point(176, 56);
            this.textLastName.Name = "textLastName";
            this.textLastName.Size = new System.Drawing.Size(209, 20);
            this.textLastName.TabIndex = 2;
            this.textLastName.Text = "";
            // 
            // buttonGreetMe
            // 
            this.buttonGreetMe.Location = new System.Drawing.Point(83, 92);
            this.buttonGreetMe.Name = "buttonGreetMe";
            this.buttonGreetMe.Size = new System.Drawing.Size(234, 23);
            this.buttonGreetMe.TabIndex = 3;
            this.buttonGreetMe.Click += new System.EventHandler(this.buttonGreetMe_Click);
            // 
            // labelChoose
            // 
            this.labelChoose.Location = new System.Drawing.Point(26, 132);
            this.labelChoose.Name = "labelChoose";
            this.labelChoose.Size = new System.Drawing.Size(122, 14);
            // 
            // radioEnglish
            // 
            this.radioEnglish.Checked = true;
            this.radioEnglish.Location = new System.Drawing.Point(151, 129);
            this.radioEnglish.Name = "radioEnglish";
            this.radioEnglish.Size = new System.Drawing.Size(70, 24);
            this.radioEnglish.TabIndex = 4;
            this.radioEnglish.TabStop = true;
            this.radioEnglish.CheckedChanged += new System.EventHandler(this.radioEnglish_CheckedChanged);
            // 
            // radioFrench
            // 
            this.radioFrench.Location = new System.Drawing.Point(231, 129);
            this.radioFrench.Name = "radioFrench";
            this.radioFrench.Size = new System.Drawing.Size(70, 24);
            this.radioFrench.TabIndex = 5;
            this.radioFrench.CheckedChanged += new System.EventHandler(this.radioFrench_CheckedChanged);
            // 
            // radioSpanish
            // 
            this.radioSpanish.Location = new System.Drawing.Point(311, 129);
            this.radioSpanish.Name = "radioSpanish";
            this.radioSpanish.Size = new System.Drawing.Size(75, 24);
            this.radioSpanish.TabIndex = 6;
            this.radioSpanish.CheckedChanged += new System.EventHandler(this.radioSpanish_CheckedChanged);
            // 
            // LocalizationSampleForm
            // 
            this.AcceptButton = this.buttonGreetMe;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(414, 177);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.radioSpanish,
                                                                          this.labelChoose,
                                                                          this.radioFrench,
                                                                          this.radioEnglish,
                                                                          this.buttonGreetMe,
                                                                          this.textLastName,
                                                                          this.textFirstName,
                                                                          this.labelLastName,
                                                                          this.labelFirstName});
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.Name = "LocalizationSampleForm";
            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.ResumeLayout(false);

        }
        #endregion

        [STAThread]
        static void Main() 
        {
            // Create a new application with the given form
            Application.Run(new LocalizationSampleForm());
        }

        private void radioEnglish_CheckedChanged(object sender, System.EventArgs e)
        {
            if (radioEnglish.Checked)
            {
                // User selected English!
            }
        }

        private void radioFrench_CheckedChanged(object sender, System.EventArgs e)
        {
            if (radioFrench.Checked)
            {
                // User selected French!
            }
        }

        private void radioSpanish_CheckedChanged(object sender, System.EventArgs e)
        {
            if (radioSpanish.Checked)
            {
                // User selected Spanish!
            }
        }

        private void buttonGreetMe_Click(object sender, System.EventArgs e)
        {
            // User clicked the greet me button!
        }        
    }
}


Step 3: Adding Localized Resource Files
Now that we have the basic form for our application, we can now add localized resource files to our project. From the menu select File | Add New Item. Under "Local Project Items" select "Resources" then "Assembly Resource File" and type in "LocalizationSample.resx".

The file that was just added is going to be the neutral culture resource file (in the case of this sample, plain english). This file will be compiled into a .resource file and embedded in our executable.

Now that we have our neutral culture resource file, lets type in some values:
Value: Name:
Type your first name here: labelFirstName
Type your last name here: labelLastName
Choose a language: labelChoose
Greet me! buttonGreetMe
English radioEnglish
French radioFrench
Spanish radioSpanish
Please specify a first name. textFirstNameMB
Please specify a last name. textLastNameMB
Hello, {0} {1}, nice to meet you! greetingMessage
Localization Sample - By Peter Huene formTitle

Please Note:There are no spaces between the brackets and the numbers in "greetingMessage". Also, feel free to put your name in the formTitle.

Once you are done entering in the name-value pairs, it is time to add the localized versions of this file. Add a new Assembly Resource file, but this time use the name "LocalizationSample.fr-FR.resx". Note the "fr-FR" in the file name. This is the culture identifier for French (in France).

Now, add the following name-value pairs to this file:
Value: Name:
Tapez votre prénom ici: labelFirstName
Tapez votre dernier nom ici: labelLastName
Choisissez un langage: labelChoose
Saluez-moi! buttonGreetMe
Anglais radioEnglish
Français radioFrench
Espagnols radioSpanish
Veuillez indiquer un prénom. textFirstNameMB
Veuillez indiquer un dernier nom. textLastNameMB
Bonjour, {0} {1}, gentil de vous rencontrer! greetingMessage
Échantillon De Localisation - Par Peter Huene formTitle

Once you are done entering in those name-value pairs, it is time to add the Spanish localized version. Add a new Assembly Resource file, but this time use the name "LocalizationSample.es-ES.resx". You guessed correctly, "es-ES" is the culture identifier for Spanish (in Spain).

Now, add the following name-value pairs to this file:
Value: Name:
Pulse su nombre aquí: labelFirstName
Pulse su nombre pasado aquí: labelLastName
Elija un lenguaje: labelChoose
¡Salúdeme! buttonGreetMe
Ingles radioEnglish
Frances radioFrench
Español radioSpanish
Especifique por favor un nombre. textFirstNameMB
Especifique por favor un nombre pasado. textLastNameMB
¡Hola, {0} {1}, agradable satisfacerle! greetingMessage
Muestra De la Localización - Por Peter Huene formTitle

It is interesting to note that when you compile your application and check your bin\Debug or \bin\Release directory that there are now two sub-directories, namely "fr-FR" and "es-ES". These sub-directories contain what are called satellite resource assemblies. These assemblies contain no executable code, just the localized string resources.

Step 4: Adding the ResourceManager and CultureInfo objects
Under your private control variable definitions, add the following:
private ResourceManager     m_ResourceManager = new ResourceManager("LocalizationSample.LocalizationSample", 
                                    System.Reflection.Assembly.GetExecutingAssembly());
private CultureInfo         m_EnglishCulture = new CultureInfo("en-US");
private CultureInfo         m_FrenchCulture = new CultureInfo("fr-FR");
private CultureInfo         m_SpanishCulture = new CultureInfo("es-ES");

The constructor to the ResourceManager object takes a string that is the root name of the resource to manage, and looks in the specified assembly object (in our case, the executing assembly). Note that the root name of the resource is not "LocalizationSample" but "LocalizationSample.LocalizationSample". The reason for this is that the IDE appends the default namespace to the .resource file when it is compiled (you can verify this in your obj\Debug or obj\Release directories). The default namespace can be changed in the Project properties.

The CultureInfo objects represent information about a culture. These objects will be used to change the current user interface culture.

Step 5: Updating the UI
Lets add the following method to our form class:
private void UpdateUI()
{
    labelFirstName.Text = m_ResourceManager.GetString("labelFirstName");
    labelLastName.Text = m_ResourceManager.GetString("labelLastName");
    labelChoose.Text = m_ResourceManager.GetString("labelChoose");
    buttonGreetMe.Text = m_ResourceManager.GetString("buttonGreetMe");
    radioEnglish.Text = m_ResourceManager.GetString("radioEnglish");
    radioFrench.Text = m_ResourceManager.GetString("radioFrench");
    radioSpanish.Text = m_ResourceManager.GetString("radioSpanish");
    this.Text = m_ResourceManager.GetString("formTitle");
}


and also add the following line after InitializeComponent() in the form constructor:
UpdateUI();


If you compile and run now, you will see that English now appears where there used to be a blank user interface.

Step 6: Responding to a Change in Language
Add the following code to the if statement in the radioEnglish_CheckedChanged method:
Thread.CurrentThread.CurrentUICulture = m_EnglishCulture;
UpdateUI();


Now do the same for both radioFrench_CheckedChanged and radioSpanish_CheckedChange but instead use their appropriate cultures.

When we set the current thread's current UI culture and call UpdateUI(), the resource manager's GetString method uses the current UI culture to localize the string. It does this transparently, and pulls the resources out of satellite resource assemblies if needed.

Step 7: Implement the buttonGreetMe_Click Method
Add the following code to the buttonGreetMe_Click method of our form:
if (textFirstName.Text == "")
{
    MessageBox.Show(this, m_ResourceManager.GetString("textFirstNameMB"), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
    textFirstName.Focus();
    return;
}
else if (textLastName.Text == "")
{
    MessageBox.Show(this, m_ResourceManager.GetString("textLastNameMB"), this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
    textLastName.Focus();
    return;
}
string message = String.Format(m_ResourceManager.GetString("greetingMessage"), textFirstName.Text, textLastName.Text);
MessageBox.Show(this, message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);


The first if statement checks for an empty first name field, and prompts the user (with a localized prompt) to enter in a first name. Likewise for the else if clause. If both fields contain some text, then we get the localized greeting message from the resource manager and format it using the first and last name values from the text boxes. We then display the greeting in a message box.

Now we're practically done, but lets do one more step. If a satellite resource assembly for a given culture doesn't exist, lets disable the radio button.

Step 8: Disable Unsupported Language Radiobutton
To do this, we need to simply check with the resource manager to see if it can obtain the resource set. Add the following code to your forms constructor (somewhere after InitializeComponent()):
if (m_ResourceManager.GetResourceSet(m_FrenchCulture, true, false) == null)
{
    this.radioFrench.Enabled = false;
}
if (m_ResourceManager.GetResourceSet(m_SpanishCulture, true, false) == null)
{
    this.radioSpanish.Enabled = false;
}


That's it! Now if a user deletes the satellite resource assembly, the user won't be able to switch to that language.

Conclusion
By now you should understand the process of localization and how to localize string resources in C#.
Feel free to e-mail me with any Questions/Comments/Flames.

About The Author
I think my picture just about sums it up :).

Return to Browsing Tutorials

Email this Tutorial to a Friend

Rate this Content:  
low quality  1 2 3 4 5  high quality

Reader's Comments Post a Comment
 
very good tutorial. Makes localization in C# look easy!
-- Chris Kelly, February 02, 2002
 
I didn't realize is was so easy! I remember that localization was previous a pain, but knowing this now I can actually include localization into a contract project I'm working on. Thanks!
-- Heath Stewart, February 03, 2002
 
I found how to do it while working on my pet project that is a Python compiler for .NET. You specify a /culture:name compiler switch and the output gets localized for that culture, if possible. Simply by setting the UI culture to the one specified; doesn't get much easier than that :).
-- Peter Huene, February 03, 2002
 
Also, please post comments with your ratings please. This was my first tutorial and I am interested to see how I can improve for future tutorials. What did you not like, what went wrong, etc? I have more tutorials in the works, so feedback will make me a better tutor. Thanks, guys.
-- Peter Huene, February 03, 2002
 
I don't mean to be the only one posting to my own tutorial, but you can download the complete source here and soon you will be able to download the sample source from the tools section as well.
-- Peter Huene, February 03, 2002
 
Good tutorial. I think it's good how you outlined the steps of what someone has to do to accomplish the task. You may want to leave out the entire source code for the application that demonstrates the localization. Sometimes it's necessary, sometimes I think it's better to leave it out. But overall, it's informative. I learned something here.
-- Andrew Ma, February 03, 2002
 
Great, this is going to save me a lot of time!!
-- David McKenna, February 04, 2002
 
This is really cool, and yet so simple! Still, I'd like to see GUI's that were written and not made with VS.NET's GUI program.
-- Seth Peck, February 05, 2002
 
What?! You mean people use things other than VS.NET? (gasp) :)
-- Peter Huene, February 06, 2002
 
A helpful tutorial.
-- Brian Simoneau, February 19, 2002
 
Very easily understood tutorial. Good Job!
-- Luis Ortiz, February 19, 2002
 
I once had to implement localization for an application, but in C++. Those GetString() look awfully familiar. It is nice to see how beautifully it is done in C#. Good job!
-- Alvin Chardon, February 27, 2002
 
Very good tutorial!
-- Kuniaki Tran, March 03, 2002
 
I was stuck with a wierd error but ur sample helped me c my problem.
-- Gaurav Ahuja, March 07, 2002
 
Content aside, you did a wonderful job of formatting this thing. The tables and pictures are a great visual aid. The content itself was interesting and something i had tried myself before. YOu did a much better job :).
-- Lee B, October 03, 2002
 
Thank you for this helpful tutorial. I also want to learn how I can apply localisation to web projects.
-- Metin Albayrak, July 14, 2004
 
After some reflexion, I wrote this to make the translation easier; it applies the translation, if any available, to all Labels in a webform. May it helps...

foreach (System.Web.UI.Control ctrl in Controls) {
  if (ctrl.HasControls() == true) {
    foreach (System.Web.UI.Control ctrl2 in ctrl.Controls) {
      if (ctrl2.GetType().ToString().Equals("System.Web.UI.WebControls.Label")) {
        string lbl = m_ResourceManager.GetString(ctrl2.ID);
        if (lbl != null)
          ((System.Web.UI.WebControls.Label)ctrl2).Text = lbl;
      }
    }
  }
}

Shall you put this into a function called on form initialize, and change the name of "Form1" to match your needs, or even better make a recursive call (with little & easy modifications)
-- Mac Teddy, November 04, 2005
 
Copyright © 2001 DevHood® All Rights Reserved