Adding Globalization and Localization Support to Your Windows Phone Application

Introduction

The mobile market is global today. The latest version of Angry Birds is a favorite not only in the U. S. but across the globe. In this light, it is important for application developers to ensure that their application works in all possible markets where the app can be sold.

Windows Phone supports an app to work in more than one language through support for globalization and localization.

If the application is managed, there is already first-class support in .NET framework. The default Visual Studio templates for Windows Phone contain boiler-plate code for localization support.

Globalization Basics

A globalized app presents the user with information, which is adapted to user’s cultural environment. The date format, number format, currency format, etc. are presented in the user’s locale.

Building globalization support in a Windows Phone application is very simple. You need to use the CultureInfo class and set the Culture of the current thread to the user’s locale. Once the CultureInfo is set, the presentation formats of date, currency, numbers, etc. are automatically changed to the culture defaults.

As a best practice, the culture value should not be hardcoded. Instead, the CultureInfo object should be assigned to the CurrentCulture property of the current thread.

The following are some of the common formats used in globalization scenarios.

 

 

Format type

String formatter

Long Date

DateTimeObject.ToString(“D”)

Short Date

DateTimeObject.ToString(“d”)

Time

DateTimeObject.ToString(“T”)

Currency

Int64.ToString(“C”)

 

 

Localization Basics

Localization is the task of localizing the strings presenting in your application to local values, so that they appear meaningful for the user. This list will include localizing the app bar also.

As part of localization, developers will need to separate localizable resources from code by using language-specific resource files.

Hands-On

In our sample application, we will build an application that will allow the user to choose the locale and reflect the changes in some values.

New Project
New Project

Target Windows Phone OS Version
Target Windows Phone OS Version

Add the following controls to your mainpage.xaml: one radiobutton for en-US locale and another radiobutton for fr-FR locale, 4 textblocks and 4 textboxes – one each to hold long date format, short date format, time format, and currency format. Finally, add 2 textblocks for localized strings – one for “Hello” and other for “user”.

mainpage.xaml
mainpage.xaml

To start with, double-click AppResources.resx under the Resources folder and add content to match the following screen to it. Here, we are adding our strings as resources, which we will assign to various controls.

AppResources.resx
AppResources.resx

Next, we will add another resource file, called AppResources.fr-FR.resx and add the following contents.

AppResources.fr-FR.resx
AppResources.fr-FR.resx

This resource file contains the strings localized for fr-FR locale (French in France). Please be sure to add the string names exactly as you would have done for AppResources.resx. If the resource string does not match in AppResources.fr-FR.resx, the Windows Phone runtime will look up AppResources.resx to determine the value to be used.

Now, right-click on the Project and select Properties and then select fr-FR from the list of supported Cultures.

List of Supported Cultures
List of Supported Cultures

Now, we are ready to start binding the controls we put on MainPage.xaml to the resource strings in our resource files.

For the text value of each control we added, specify it as below:

Text="{Binding Path=LocalizedResources.StringFoo, Source={StaticResource LocalizedStrings}}"

In the snippet above, we have specified that the text value is a localized string of type static resource and the path to the resource is in LocalizedResource.StringFoo. If we have an entry in AppResources.resx as StringFoo, this snippet will fetch the value associated with that string.

You can specify the binding of the controls on the page as shown in the highlighted section below.

<phone:PhoneApplicationPage
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    x:Class="WindowsPhoneGlobLocDemo.MainPage"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
 
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!-- LOCALIZATION NOTE:
            To localize the displayed strings copy their values to appropriately named
            keys in the app's neutral language resource file (AppResources.resx) then
            replace the hard-coded text value between the attributes' quotation marks
            with the binding clause whose path points to that string name.
 
            For example:
 
                Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
 
            This binding points to the template's string resource named "ApplicationTitle".
 
            Adding supported languages in the Project Properties tab will create a
            new resx file per language that can carry the translated values of your
            UI strings. The binding in these examples will cause the value of the
            attributes to be drawn from the .resx file that matches the
            CurrentUICulture of the app at run time.
         -->
 
        <!--Uncomment to see an alignment grid to help ensure your controls are
            aligned on common boundaries.  The image has a top margin of -32px to
            account for the System Tray. Set this to 0 (or remove the margin altogether)
            if the System Tray is hidden.
 
            Before shipping remove this XAML and the image itself.-->
        <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" Grid.RowSpan="2" IsHitTestVisible="False" />-->
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <RadioButton x:Name="radioButtonenUS" Content="en-US" HorizontalAlignment="Left" Margin="106,32,0,0" VerticalAlignment="Top" />
            <RadioButton x:Name="radiobuttonfrFR" Content="fr-FR" HorizontalAlignment="Left" Margin="106,85,0,0" VerticalAlignment="Top" />
            <TextBox x:Name="textBoxLongDate" HorizontalAlignment="Left" Height="72" Margin="170,181,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="280" />
            <TextBox x:Name="textBoxShortDate" HorizontalAlignment="Left" Height="72" Margin="170,253,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="280"  />
            <TextBlock x:Name="textBlockHello" HorizontalAlignment="Left" Margin="22,483,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="148" Height="27" Text="{Binding Path=LocalizedResources.Salutation, Source={StaticResource LocalizedStrings}}"/>
            <TextBlock x:Name="textBlockUser" HorizontalAlignment="Left" Margin="183,483,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding Path=LocalizedResources.UserName, Source={StaticResource LocalizedStrings}}" />
            <TextBox x:Name="textBoxTime" HorizontalAlignment="Left" Height="72" Margin="170,313,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="280"  />
            <TextBox x:Name="textBoxCurrency" HorizontalAlignment="Left" Height="72" Margin="170,371,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="280" />
            <TextBlock x:Name="textBlockLongDate" HorizontalAlignment="Left" Margin="22,204,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding Path=LocalizedResources.TextLabelLongDate, Source={StaticResource LocalizedStrings}}"/>
            <TextBlock x:Name="textBlockShortDate" HorizontalAlignment="Left" Margin="22,278,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding Path=LocalizedResources.TextLabelShortDate, Source={StaticResource LocalizedStrings}}"/>
            <TextBlock x:Name="textBlockTime" HorizontalAlignment="Left" Margin="22,338,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.487,2.293" Text="{Binding Path=LocalizedResources.TextLabelTime, Source={StaticResource LocalizedStrings}}" />
            <TextBlock x:Name="textBlockCurrency" HorizontalAlignment="Left" Margin="22,396,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.487,2.293" Text="{Binding Path=LocalizedResources.TextLabelCurrency, Source={StaticResource LocalizedStrings}}"/>
        </Grid>
 
    </Grid>
 
</phone:PhoneApplicationPage>

Next, we will implement the code when the radio buttons are checked.

Before we do that, we will implement a helper method, which will set the culture of the current thread to a specified CultureInfo. Additionally, it will extract the resource string value from the resource files and use them to display the control labels. Also, it will format some value according to the user’s current culture (locale).

        private void ApplyCulture(CultureInfo cul)
        {
            Thread.CurrentThread.CurrentCulture = cul;
            Thread.CurrentThread.CurrentUICulture = cul;
            DateTime current = DateTime.Now;
            textBoxLongDate.Text = current.ToString("D");
            textBoxShortDate.Text = current.ToString("d");
            textBoxTime.Text = current.ToString("T");
            textBoxCurrency.Text = 100.ToString("C");
            textBlockLongDate.Text = AppResources.TextLabelLongDate;
            textBlockShortDate.Text = AppResources.TextLabelShortDate;
            textBlockTime.Text = AppResources.TextLabelTime;
            textBlockCurrency.Text = AppResources.TextLabelCurrency;
            textBlockUser.Text = AppResources.UserName;
            textBlockHello.Text = AppResources.Salutation;
        }
 

Now, in the checked event of our radiobuttons, we will call this helper method, passing in the value of the appropriate CultureInfo objects.

private void radioButtonenUS_Checked(object sender, RoutedEventArgs e)
        {
            ApplyCulture(new CultureInfo("en-US"));
        }
 
private void radiobuttonfrFR_Checked(object sender, RoutedEventArgs e)
        {
            ApplyCulture(new CultureInfo("fr-FR"));
            
        }

Testing the Application

Our application is now complete. Compile and execute it. If you are having trouble following along, you can download the sample snippet from here.

When you run the application for the first time, the default locale is en-US (for most of our readers). The application launch screen is below.

Application Launch Screen
Application Launch Screen

When I select a particular locale, the textboxes and the labels are changed according to my selected locale.

en-US Textboxes and Labels
en-US Textboxes and Labels

fr-FR Textboxes and Labels
fr-FR Textboxes and Labels

Summary

In this article, we built a Windows Phone 8 application that is globalized as well as localized. I hope you have found this information useful.

About the Author

Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com


Originally published on Developer.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds