Localization in WP7

I just wrote a blog on how I localized a WPF application in a nice way. You can read that post here: Localization in WPF

What about Windows Phone , how to do localization for Windows Phone? Microsoft has some great articles about localization for Windows Phone. You can read them here: Globalization and Localization for Windows Phone. They give you some good best practices and also one way of doing localization, although I would like to do localization in a similar way as I did for WPF, and lucky me you can do that! :)

Let’s go through step-by-step how I did it.

Create a simple project
First of all create a simple Windows Phone Silverlight application, File->New->Project -> “Windows Phone application”.
Create Resources
I usually have all resources in a separate folder in my projects, so next we right-click the project and add a new folder called Resources.
Right-click the newly created Resources folder and a Resource file, I named mine AppResources.resx. This resource file will be the default language for your application, I have en-US as default.
Now let’s add entries in the Resource file for application title and main page title translations.

When naming the resources I try to follow the following naming convention. Each resource name is named “ViewName_id”. As example we have MainPage_Title, but I also use Application_id for resources that I use throughout the application, like Application_Title. Just make sure you don’t use Application_id in places where you reuse an “Application wide” resource string when you actually should have used a “View wide” resource string since this may lead to unwanted effects if the “Application wide” resource translation is changed.

Note: To be able to access the resources from Xaml you have to change the Access Modifier to public on the Resource file, see image above.

Add more languages
Let’s translate to Swedish and Spanish. The easiest way is to copy-paste the default resource file and just change the name of the file. By doing it this way you have all the resource entries already in the resource file and you just have to change the translation. Since I want to use Swedish and Spanish, I copy-paste the default resource twice and change the name of them to:
AppResources.sv-SE.resx
AppResources.es-ES.resx
I have used transle.google.com to translate the Spanish resource file, so perhaps the translation is totally wrong :)

The concept of globalization is very important to understand, so if that is new to you then you should read more at MSDN, Creating Globally Aware Applications and Localizing Silverlight-based Applications.

Create Base ViewModel
I really like the concept of MVVM design pattern and would like to use it for my Windows Phone application as well. In my previous post about WPF localization I used the ViewModel to access the Resources so that my XAML data bindings looks good. I accomplish the same in my Windows Phone application by creating a ViewModel base class that all ViewModels in my application use. The base class also has a property called Resources to accesses the application resources, AppResources.

Source Code for my ViewModelBase class

    public class ViewModelBase
    {
        private static AppResources resources = new AppResources();
        public AppResources Resources { get { return resources; } }
    }

View DataContext
Let’s set the ViewModelBase as DataContext for the View, you should probably create a new ViewModel that inherits the base class, but for simplicity in this example I just use the base class directly as DataContext.

Add namespace reference and set ViewModelBase as DataContext

<phone:PhoneApplicationPage
    x:Class="LocalizedApp.MainPage"
    . . .
    xmlns:this="clr-namespace:LocalizedApp"
    . . .
    >
    <phone:PhoneApplicationPage.DataContext>
        <this:ViewModelBase />
    </phone:PhoneApplicationPage.DataContext>

Update View to use Resources
Update the MainPage view to use the string resources instead. Since we have access to the Resources property through the DataContext we simply change the XAML to the following

        <TextBlock Text="{Binding Resources.Application_Title}" . . . />
        <TextBlock Text="{Binding Resources.MainPage_Title}" . . . />

Add buttons to page so that we can change language in runtime

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <StackPanel>
            <Button Content="Change to sv-SE" Click="SEButton_Click" />
            <Button Content="Change to es-ES" Click="ESButton_Click" />
            <Button Content="Change to Default" Click="DefaultButton_Click" />
        </StackPanel>
    </Grid>

Add event handlers
To be able to change the language in runtime and have the change reflect in the UI we need to extend the ViewModelBase class to implement INotifyPropertyChanged interface and call PropertyChanged when the language is changed. I also extend the base class with a convenient method to change language.

The new full implementation of ViewModelBase:

    public class ViewModelBase : INotifyPropertyChanged
    {
        private static AppResources _resources = new AppResources();
        public AppResources Resources { get { return _resources; } }

        public void ChangeLanguage(string language)
        {
            AppResources.Culture = new System.Globalization.CultureInfo(language);
            OnPropertyChanged("Resources");
        }

        #region INotifyPropertyChanged Members

        PropertyChangedEventHandler propertyChanged;
        public virtual event PropertyChangedEventHandler PropertyChanged
        {
            add { propertyChanged += value; }
            remove { propertyChanged -= value; }
        }

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.propertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }

Button Eventhandlers

        public ViewModelBase ViewModel { get { return this.DataContext as ViewModelBase; } }

        private void SEButton_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.ChangeLanguage("sv-SE");
        }

        private void ESButton_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.ChangeLanguage("es-ES");
        }

        private void DefaultButton_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.ChangeLanguage(System.Threading.Thread.CurrentThread.CurrentCulture.Name);
        }

If I run the Windows Phone application now I get the following screen:

But when I click the buttons to change language nothing happens. How come? Well this is the part that I think is a little bit awkward and not so good. You actually have to change the .csproj file and extend it to support more than the default language. What you have to do is to open the .csproj file in, for example, Notepad and add all supported cultures separated by a ‘;’ in the SupportedCultures tag.

 <SupportedCultures>sv-SE;es-ES</SupportedCultures>

Done! So now when I run the application I can change the language in runtime by clicking the buttons on the main page, sweet! :)

Your application will perhaps not give the user the possibility to change language in runtime in the same way as this example, but following this approach you can easily change the language in a settings page and have the current selected language stored in isolated storage and properly loaded when you start the application.

Good luck with your Windows Phone localization! Hopefully this blog-post has given you another approach on how it can be done.

Advertisements
    • m.savazzi
    • January 25th, 2012

    How this can work when I have to use DataContext for the data to be shown in the page ?

    I cannot have 2 data context

  1. Hi m.savazzi.

    Yes you are absolutely right, you cannot have two data context on a single element. But you can have regular object oriented programing with inheritance for your view model classes.

    So this approach above is expecting you to have a base View Model class implementation that each of your view model is inheriting.

    Example:
    You have a customer view with corresponding customer VM that is called CustomerViewModel (and inherits ViewModelBase).

    public class CustomerViewModel : ViewModelBase { … }

    Then the data you want to bind in the view should be in the CustomerViewModel, but again since CustomerViewModel inherits ViewModelBase you will also be able to bind against the string resources property in the view.

    So you only have one data context, the CustomerViewModel.

    Hope that clarifies it a bit for you.

    /Michael

    • m.savazzi
    • January 25th, 2012

    Ok, you are right :)

    The problem I have is that I’m using MVVM Light so the ViewModelBase class is locked.

    Can I create an intermediate class for globalization?

    Like

    public class CustomerViewModel : ViemModelBaseLocal { … }

    public class ViemModelBaseLocal: ViewModelBase { … }

    If yes the only things I have to add in ViemModelBaseLocal are the Strings?

    Can you help a little? I’m not that good in inheritance :)

  2. Yes exactly. You should create your own extended base class (I have also done the exact same when using MVVM light)

    I had the following:
    public class ViewModelBaseExtended : ViewModelBase { ..}

    and in my ViewModelBaseExtended I place all the application specific properties/data that I want in each of my view models.

    Then inherit my local/extended version of the view model base class like you suggested above.

    public class CustomerViewModel : ViewModelBaseExtended { …}

    • m.savazzi
    • January 25th, 2012

    I’m lazy :)

    any chance you share your public class ViewModelBaseExtended : ViewModelBase

    with the language resources etc?!?

    You also use the Extended model to store application wide settings?

    • m.savazzi
    • January 25th, 2012

    I have an additional question: have you found a nice solution to solve the light/dark style dynamically?

    • m.savazzi
    • January 25th, 2012

    I’m trying to implement it… I’m not interested in changing dynamically the language, is just for me to have the same language of the phone.

    I do not understand how to do that :(

    I’ve created the resource file but how I choose the right one?
    and how I substitute the text in the XAML with binding?

  3. Here are some code for you: :)

    public class ExtendedViewModelBase : GalaSoft.MvvmLight.ViewModelBase
    {
    public ExtendedViewModelBase()
    {
    Messenger.Default.Register(this, delegate(LanguageChanged lang) { RaisePropertyChanged(“UIResources”); });
    }
    #region Localization
    public UIResources UIResources { get { return LocalizationHelper.UIResources; } }
    #endregion
    }

    public static class LocalizationHelper
    {
    #region Localization
    public static UIResources resources = new UIResources();
    public static UIResources UIResources { get { return resources; } }

    public static void ChangeLanguage(string language)
    {
    // Make sure we have value
    if (string.IsNullOrEmpty(language)) return;

    try
    {
    UIResources.Culture = new System.Globalization.CultureInfo(language);
    Messenger.Default.Send(null);
    IsolatedStorageSettings.ApplicationSettings[“SelectedLanguage”] = language;
    }
    catch { }
    }
    #endregion
    }

    In the LocalizationHelper I’m creating an instance of the UIResources class which is my .resx file for strings that is located in the same project and called. UIResources.resx
    I also have another resource file for Swedish language called UIResources.se-SV.resx

    One thing to remember is to make the Access Modifier Public. You do this by double-clicking the resource file and in the resource editor select Public in the drop-down.

    /Michael

    • m.savazzi
    • January 26th, 2012

    great!

    will give it a try… very soon!

    • m.savazzi
    • January 26th, 2012

    ok…
    got errors on
    LanguageChanged lang

    and also the two Messenger.Default lines give me an error…

    you use the messenger to force an update of the ViewModel, correct?

    using latest MVVM Light messenger class require 2 paramenters not just one.

    Also in your code you have to unregister messenger explicitly on unload or it will do a mess (Laurent wrote…)

  4. Ok, although I guess you can figure it out from now on. :)

    Regarding the whole Messenger things, you can delete that since you are not localizing the app (if I understood correctly) and yes I use that to notify the UI that resources are changed.

    • m.savazzi
    • January 26th, 2012

    hehe

    only one thing I’ve not understood how to do:
    How can I load the correct resource = to the local settings of the phone?

    I’m confused on that

  5. The following code is telling you what resource file to access in the property

    public static UIResources resources = new UIResources();
    public static UIResources UIResources { get { return resources; } }

    The resource file called UIResources.resx is what I use in this example.

    • m.savazzi
    • January 31st, 2012

    I’ve found an issue: how you can localize the AppBar button text?

    using binding deos not work…

  6. To localize the AppBar you have to build it by hand, you cannot build it in XAML. In your code behind:

    private void BuildApplicationBar()
    {
    this.ApplicationBar = new ApplicationBar();

    ApplicationBarIconButton newButton = new ApplicationBarIconButton(new Uri(“/Images/appbar.new.png”, UriKind.Relative));
    newButton.Text = AppResources.MainMenu_New;
    newButton.Click += ((s, e) =>
    {
    // Do stuff
    });
    ApplicationBar.Buttons.Add(newButton);

    // Add additional buttons
    // To add a menu item, create a new ApplicationBarMenuItem and add it to ApplicationBar.MenuItems.Add
    }

  7. Also, take a look at MSDN for best practices regarding localization in Windows Phone. http://msdn.microsoft.com/en-us/library/ff637520%28v=vs.92%29.aspx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: