Chapter 37. Localizing Programs

Many programmers write applications that are used only in their countries. It's easy enough to find plenty of customers for a small application without looking for long-distance customers.

However, the world has grown smaller in the past few decades, and it's common for software to spread far beyond its country of origin. Customers can download your software over the web and pay for it using online payment systems in a matter of minutes. Web applications that run in a browser are even more likely to be used by people all over the world.

With such a potentially enormous market, it makes sense in some cases to make programs accessible to people in different countries, particularly since Visual Basic and Visual Studio make it relatively easy.

In this lesson, you learn how to make a program accessible to customers in other countries with different cultures. You learn how to make multiple interfaces for a program so users can work in their own languages. You also learn how to work with values such as currency and dates that have different formats in different locales.

Warning

Localization is a huge topic so there isn't room to cover everything there is to know about it here. In particular, you should always get a native of a particular locale to help in localizing your application whenever possible. Unless you are extremely well-versed in a locale's language, customs, and idioms, it's very easy to make mistakes.

Note that I am not fluent in all of the locales that this lesson uses. I used the Babel Fish automatic translation tool at babelfish.yahoo.com to make the simple translations shown here, but these are for demonstration purposes. You can use Babel Fish or a similar tool for practice and for this lesson's exercises, but you should get human help before releasing a program to users.

UNDERSTANDING LOCALIZATION

A computer's locale is a setting that defines the user's language, country, and cultural settings, which determine such things as how dates and monetary values are formatted.

For example, the FormatValues example program shown in Figure 37-1 (and available in this lesson's code download) displays the same values in American, British, German, and French locales.

FIGURE 37-1

Figure 37.1. FIGURE 37-1

If you look closely at Figure 37-1, you can see that the same values produce very different results in the different locales. For example, the currency value 1234.56 is displayed variously as follows:

  • $1,234.56

  • £1,234.56

  • 1.234,56€

  • 1 234,56€

Not only do these results use different currency symbols, but they even use different decimal and thousands separators.

Note

Globalization is the process of building an application that can be used by users from different cultures.

Localization is the process of customizing a globalized application for a specific culture.

Localizing an application involves two main steps: building a localized user interface and processing locale-specific values.

BUILDING LOCALIZED INTERFACES

At first this may seem like a daunting task. How do you build completely separate interfaces for multiple locales? Fortunately this is one thing that Visual Basic and Visual Studio do really well.

To build a globalized program, start by creating the form as usual. Add controls and set their properties as you would like them to appear by default.

After you've defined the program's default appearance, you can localize it for a particular locale. First set its Localizable property to True. Then select a new locale from the drop-down list provided by the form's Language property. Now modify the form to handle the new locale. You can change control properties such as the text they display. You can also move controls around and change their size, which is particularly important because the same text may take up a different amount of room in different languages.

At run time, the program automatically checks the computer's locale settings and picks the language that is closest. Note that many languages have several sublocales. For example, English includes the varieties used in India, Ireland, New Zealand, and more than a dozen other locales.

There's also a locale listed simply as "English." If the user's computer is set up for one of the English locales that the program doesn't support explicitly, the program falls back to the generic English locale. If the program can't support that locale either, it uses the default locale that you used when you initially created the form.

FIGURE 37-2

Figure 37.2. FIGURE 37-2

The LocalizedWeekdays example program (available in this lesson's code download) is localized for English (the form's default) and German. Figure 37-2 shows the form's English interface and Figure 37-3 shows its German interface.

FIGURE 37-3

Figure 37.3. FIGURE 37-3

Having the program check the computer's locale automatically at run time is convenient for the user but it makes testing different locales tricky.

One way to force the program to pick a particular locale so you can test it is to select the locale in code. You must do this before the form is initialized because after that point the form's text and other properties are already filled in and setting the locale won't reload the form.

To add code to select a locale before the controls are loaded, you need to give the form a new constructor. If you type Public Sub New() and press [Enter], Visual Studio creates the following default constructor for a form:

Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

End Sub

Now you can add code to this constructor before the call to InitializeComponent. The following code block shows all the code used by the LocalizedWeekdays program:

Public Class Form1
    Public Sub New()
        ' English.
        'My.Application.ChangeCulture("en-US")
        'My.Application.ChangeUICulture("en-US")
' German.
        My.Application.ChangeCulture("de-DE")
        My.Application.ChangeUICulture("de-DE")

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

    End Sub
End Class

The code uses the My.Application.ChangeCulture method to change the culture the program uses for string manipulation and formatting when processing dates, currency, numbers, and other values in the code. It then uses My.Application.ChangeUICulture to change the culture the program uses to retrieve localized resources to build the form's user interface elements.

Note

For a list of more than 100 culture values that you can use in code, such as en-US and de-DE, see msdn.microsoft.com/library/ee825488(CS.20).aspx.

The code contains statements that set the program's locale to English or German. Comment out the one that you don't want to use for a given test.

After you finish testing a form's localized version, be sure to remove the code that selects the culture so the program can use the system's settings. Otherwise, you might end up with some very confused users.

Note

One trick some developers use is to give all labels and other controls nonsensical text such as Pig Latin initially. Then when you run the program it's obvious if you fail to localize a control.

Of course then you also need to localize the program for every locale that you want to support including your home locale, and if someone uses the program in an unexpected locale, they will see Pig Latin.

PROCESSING LOCALE-SPECIFIC VALUES

Within a Visual Basic program, variables are stored in American English formats. To avoid confusion, Microsoft decided to pick one locale for code values and stick with it. For example, if you're a German programmer your code still says For Each customer As Person in Customers and not Für Jeden Kunde Als Person In Kunden (or whatever it would work out to be).

When you move data in and out of the program, however, you need to be aware of the computer's locale. For example, suppose the program uses the following code to display an order's due date:

txtDueDate.Text = dueDate.ToString("MM/dd/yy")

If the date is October 31, 2011, this produces the result "10/31/11," which makes sense in the United States but should be "31/10/11" in France and "31.10.11" in Germany.

The problem is that the program uses a custom date format that is hard-coded to use an American-style date format. To produce a format appropriate for the user's system, you should use predefined date, time, and other formats whenever possible. The following code uses the standard short date format:

dueDateTextBox.Text = dueDate.ToString("d")

This produces "10/31/2011" on an American system and "31/10/2011" on a French system.

You can run into the same problem if you assume the user will enter values in a particular format. For example, suppose you want to get the whole number part of the value 1,234.56 entered by the user. If you assume the decimal separator is a period and just use whatever comes before it as the integer part, then you'll get the answer 1 when a German user enters "1.234,56"; and the program will crash when a French user enters the value "1 234.56."

To avoid this problem, use locale-aware functions such as the numeric classes' Parse methods to read values entered by the user. In this example, a good solution is to use Single.Parse to read the value and then truncate the numeric result as shown in the following code, rather than try to truncate the value while it's still in its string form:

Dim value As Integer = Int(Single.Parse(txtValue.Text))

For a list of standard numeric formats, see msdn.microsoft.com/library/dwhawy9k(VS.100).aspx.

For a list of standard date and time formats, see msdn.microsoft.com/library/az4se3k1(VS.100).aspx.

For more information on parsing strings, see msdn.microsoft.com/library/b4w53z0y(VS.100).aspx.

Note

Previous lessons have shown how to use Parse methods to parse currency values. For example, the following statement parses a currency value entered by the user:

value = Decimal.Parse(txtValue.Text, NumberStyles.Any);

This isn't completely foolproof. If the user has a German system but types a value in a French format, the program will fail (use TryParse or Try Catch to prevent a crash), but it seems reasonable to ask a German user to enter German values.

The LocalizedParsing example program shown in Figure 37-4 (and available in this lesson's code download) parses currency values displayed in labels in different languages, doubles the parsed decimal values, and displays the results. For each language, it selects the appropriate culture so it can parse and display the correct formats.

FIGURE 37-4

Figure 37.4. FIGURE 37-4

TRY IT

In this Try It, you write the program shown in Figures 37-5 and 37-6, which lets you select foreground and background colors in American English and Mexican Spanish.

FIGURE 37-5

Figure 37.5. FIGURE 37-5

FIGURE 37-6

Figure 37.6. FIGURE 37-6

Note

You can download the code and resources for this Try It from the book's web page at www.wrox.com or www.vb-helper.com/24hourvb.html. You can find them in the Lesson37 folder of the download.

Lesson Requirements

In this lesson:

  • Build the default interface in English.

  • Add code to handle the RadioButtons' Click events.

  • Localize the application for Mexican Spanish.

  • Add code to test the form for either locale.

Hints

  • There's no need to build a separate event handler for each RadioButton. Use one event handler for all the foreground buttons, and one event handler for all the background buttons.

  • These event handlers must then figure out which button was clicked, but they cannot use the buttons' text because that will vary according to which locale is selected. They could use the buttons' names because they don't change, but it's even easier to store the corresponding colors' names in their Tag properties and then use the Color class's FromName method to get the appropriate Color.

Step-by-Step

  • Build the default interface in English.

    1. Build a form that looks like the one shown in Figure 37-5.

    2. Store the color names (red, green, blue, and so forth) in the radio buttons' Tag properties.

  • Add code to handle the RadioButtons' Click events.

    1. Write an event handler similar to the following. The code converts the sender object into a RadioButton and uses its Tag property to get the appropriate color. It then applies that color to the form and the two GroupBoxes. (The RadioButtons inherit the colors from the form, but the GroupBoxes do not.)

      ' Set the foreground color.
      Private Sub Foreground_Click(ByVal sender As Object,
       ByVal e As EventArgs)
          ' Get the sender as a RadioButton.
          Dim rad As RadioButton = DirectCast(sender, RadioButton)
      
          ' Use the color.
          Dim clr As Color = Color.FromName(rad.Tag.ToString())
          Me.ForeColor = clr
          fgGroupBox.ForeColor = clr
          bgGroupBox.ForeColor = clr
      End Sub
    2. Connect the foreground RadioButtons to this event handler.

    3. Repeat these steps for the background RadioButtons.

  • Localize the application for Mexican Spanish.

    1. Set the form's Localizable property to True. Click the Language property, click the drop-down arrow to the right, and select "Spanish (Mexico)."

    2. Change the form's and controls' Text properties so they have the values shown in Figure 37-6.

  • Add code to test the form for either locale.

    1. Use code similar to the following in the form's constructor:

      ' Select a locale for testing.
      Public Sub New()
          ' English.
          'My.Application.ChangeCulture("en-US")
          'My.Application.ChangeUICulture("en-US")
      ' Spanish.
          My.Application.ChangeCulture("es-MX")
          My.Application.ChangeUICulture("es-MX")
      
          ' This call is required by the designer.
          InitializeComponent()
      
          ' Add any initialization after the InitializeComponent() call.
      
      End Sub

Note

Please select Lesson 37 on the DVD to view the video that accompanies this lesson.

EXERCISES

  1. Copy this lesson's Try It and add support for Italian (it-IT), as shown in Figure 37-7. Don't forget to add code to test it.

  2. When a program reads data from a file, it must use the correct locale. Download the files Dutch.txt, German.txt, and English.txt from the book's web site and make a program that can read them. The program should let the user select a file, check the filename to see which locale it should use, and select the correct locale. It should read and parse the values into appropriate data types and then display the values again in a DataGridView control.

    Hint: Use the locale name nl-NL for Dutch.

    Hint: The values within a line in the file are separated by tabs, so use File.ReadAllLines to get the lines, and Split to break each line into fields.

    The following text shows the values in the file Dutch.txt:

    Potlood    J 0,10       12    J 1,20
    Blocnote   J 1,10       10    J 11,00
    Laptop     J 1.239,99    1    J 1.239,99
  3. Copy the program you built for Exercise 2 and modify it so it calculates the total values instead of reading them from the files. Edit the text files to change the quantity values and remove the total values.

FIGURE 37-7

Figure 37.7. FIGURE 37-7

Note

You can find solutions to this lesson's exercises in the Lesson37 folder inside the download available on the book's web site at www.wrox.com or www.vb-helper.com/24hourvb.html.

FIGURE 37-7
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset