Internationalizing and Localizing .NET Desktop Applications

Introduction

This blog will provide examples of internationalization and localization across two .NET platforms - Windows Forms and WPF. The approaches are similar although the syntax is slightly different. A similar approach can be used in ASP.NET. Things get much different in HTML5 and JavaScript, where 3rd party libraries are often used.

Overview of the Project

The project, which we'll create in both Windows Forms and WPF, is a very simple UI with a label and a dropdown. Using just these elements, we can demonstrate the following aspects of internationalization:

  1. Strings in an external file
  2. Modification of UI layout
  3. An alternative to checking for string equality

Windows Forms Example

  1. In Visual Studio, create a new Windows Forms project.

  2. From the Common Controls section of the toolbox, add a Label and a ComboBox. Name them lblQuestion and cmbColor.
  3. Set the Text property of the Label to "What is your favorite color?". Instead of laying out the UI horizontally, we can do it vertically. This will allow more space for the translation of the question, as the spacing was tight in English, and other languages could have a longer string, which would truncate.


  4. Instead of adding strings directly to the Items property in the designer, add a few colors to the ComboBox through the code behind. This is done so that there can be a Value property associated with each item, instead of only Text.

    cmbColor.DisplayMember = "Text";
    cmbColor.ValueMember = "Value";
    
    var colors = new[] {
       new { Text = "Red", Value = "red" },
       new { Text = "Blue", Value = "blue" },
       new { Text = "Yellow", Value = "yellow" },
       new { Text = "Green", Value = "green" },
       new { Text = "Pink", Value = "pink" }
    };
    
    cmbColor.DataSource = colors;
    
  5. Add code to the SelectedValueChanged event to check if the user selected the green dropdown item. Note that this uses "SelectedValue", not "SelectedText", which is why we had to set the items in code to include a value that won't change based on locale.

    private void cmbColor_SelectedValueChanged(object sender, EventArgs e)
    {
      if ((string)cmbColor.SelectedValue == "green")
      {
          MessageBox.Show("Green is my favorite color too!");
      }
    }
    
  6. Now that we have everything set up, let's externalize the UI string resources. This can be done either before or after the initial design, as Visual Studio handles it for you either way.

    1. Set the Localizable property of the Form to true. This will setup the form resource file for you.
    2. In the Solution Explorer, open the Form1.resx file. You can see that the question has been added here.
    3. You can copy this file, rename the copy according to your target locale's culture code, and add it to the project. I'm using Japanese (ja) as an example.
    4. In the target locale's file, you can remove any entries beginning with ">>", as these don't need to be duplicated. You can also remove any entries under "Other", as well as any images, icons, files, etc. that you don't plan to change. Then you can translate the question.
  7. This won't work for anything in the code behind, because the Form1.resx file is autogenerated by the designer. If you add something to the .resx file that doesn't exist in the designer, then change the designer, it will remove what you added. Instead, for the code behind, let's add a separate resource file to the project.

    1. Add the key and value for the message in the code behind. Add the colors in here too.
    2. Copy, rename, and add the file to the project.
    3. Translate the entries from the code behind.
    4. Replace the hardcoded strings from the code behind with references to this resource file. You may have to rebuild to see the intellisense.

      private void cmbColor_SelectedValueChanged(object sender, EventArgs e)
      {
         if ((string)cmbColor.SelectedValue == "green")
        {
            MessageBox.Show(Strings.favoriteColorMatch);
         }
      }
      
      var colors = new[] {
        new { Text = Strings.colorRed, Value = "red" },
        new { Text = Strings.colorBlue, Value = "blue" },
        new { Text = Strings.colorYellow, Value = "yellow" },
        new { Text = Strings.colorGreen, Value = "green" },
        new { Text = Strings.colorPink, Value = "pink" }
      };
      
  8. Build and run the project.

  9. You can test out your other locale by using the following code in the constructor, before InitializeComponent:

    System.Threading.Thread.CurrentThread.CurrentUICulture = 
            new System.Globalization.CultureInfo("ja"); 

    WPF Example

    1. In Visual Studio, create a new WPF project.
    2. From the Common WPF Controls section of the toolbox, add a Label and a ComboBox to the section of the XAML file. Name them lblQuestion and cmbColor. Set the Content property of the Label to "What is your favorite color?". You can arrange them vertically in a stack panel, which will allow more space for localized text.

      
       
         
         
       
      
      
    3. Add items to the ComboBox using the designer. Set the Content for the text, and the Tag for the value. The resulting XAML will look like this:

       
           
           
           
           
           
       
      
    4. Add code to the DropDownClosed event to see if the user selected the green dropdown item. Note that we will check the Tag property, not the Content property, to avoid internationalization issues.

       private void cmbColor_DropDownClosed(object sender, EventArgs e)
       {
           ComboBoxItem cbi = (ComboBoxItem)cmbColor.SelectedItem;
           if (cbi.Tag.ToString() == "green")
           {
               MessageBox.Show(Properties.Resources.favoriteColorMatch);
           }
       }
      
    5. Now that we have everything set up, let's externalize the UI string resources.

      1. Open the Resources.resx file that comes with the project.
      2. Add the keys and values for the question, message in the code behind, and colors.
      3. Copy, rename, and add the file to the project.
      4. Translate the entries from the code behind.
      5. Replace the hardcoded strings from the XAML file and the code behind with references to this resource file. First, add a namespace declaration to the XAML file.
        xmlns:resx="clr-namespace:WPFI18N.Properties" 
        Make sure you have set the resource file's access modifier to Public.

        Then you can use bindings to the file in XAML.
        
        
          
          
          
          
          
        
        
        In the code behind:
        MessageBox.Show(Properties.Resources.favoriteColorMatch); 
    6. Build and run the project.

    You can test out your other locale by using the following code in the constructor, before InitializeComponent:

    System.Threading.Thread.CurrentThread.CurrentUICulture = 
                   new System.Globalization.CultureInfo("ja"); 

    Conclusion

    In these two examples, we demonstrated how to take text, layout, and comparison into consideration when designing a desktop application.

    For testing, you can also change the CurrentCulture which will affect things like dates and number formatting. This doesn't apply in our simple example, but would impact a more complete application.

    Note that even in another language, the message only shows up if the green item is selected. This is why we didn't compare the text of the selected item - so that we don't have to worry about it not working.

    By planning for internationalization early, we saved ourselves from having to change the layout of the UI or change the comparison logic later in the development cycle.


Comments  (4 )

Elizabeth busse
on Sun, Jan 29 2017 4:13 AM

why we had to set the items in code

[Infragistics] Elizabeth Albert
on Mon, Jan 30 2017 11:05 AM

In Windows Forms, I set the items in code so that I could associate a value with each item in addition to the displayed text.  This value is used for checking which item was selected, so that we don't have compare the displayed text.  I recommend this because then you don't have to use a string resource in the comparison.

It is possible to change the language of the form in the designer and set your localized Items on the ComboBox that way.  If you use this approach, you only have the displayed text set, with no associated value.  As such, you have to compare the displayed text in your SelectedValueChanged event.  Either way will work.  I used the value approach because I've seen string comparisons in the code behind overlooked during internationalization.  Works in the application's default language and doesn't work in any other!

lucy cyrus
on Tue, Feb 14 2017 1:19 AM

knowledgable post!! thanx for sharing!!!

Xmod Games
on Mon, Mar 6 2017 5:58 AM

Thanks for sharing such post. We can optimize this now.

Add a Comment

Please Login or Register to add a comment.