Click here to Skip to main content
Click here to Skip to main content
Technical Blog

How To: Make XAML Content Globalizable When Using Value Converters

, 9 Jul 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
There are a many articles on MSDN (and all over the Internet) about globalization and localization of Silverlight applications in general and specifically Windows Phone 7 applications but I haven’t found any that uses a value converter.

(This content was written based on Silverlight for Windows Phone, but might be valid for generic Silverlight.)StatCounter

There are a many articles on MSDN (and all over the Internet) about globalization and localization of Silverlight applications in general and specifically Windows Phone 7 applications but I haven’t found any that uses a value converter.

If you read the documentation for the IValueConverter interface, you can see that both in the Convert and ConvertBack methods have a culture parameter of type CultureInfo.

And why would we need the culture for the conversion? Imagine the application is a shop that shows prices in more than one currency. Or the application is a currency converter.

The culture parameter is used as the culture of the conversion. Any place inside the Convert or ConvertBack methods where a CultureInfo or IFormatProvider instance is need, the culture parameter should be used:

public class MoneyValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            return string.Format(culture, "{0:C}", value);
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

The value of the culture parameter is determined in the following order:

  1. The converter looks for the ConverterCulture property on the Binding object.
  2. If the ConverterCulture value is null, the value of the Language property is used.

The first case is very straightforward:

<TextBlock Text="{Binding Euros, Converter={StaticResource MoneyValueConverter}, ConverterCulture=pt-PT}" />
<TextBlock Text="{Binding Dollars, Converter={StaticResource MoneyValueConverter}, ConverterCulture=en-US}" />

But that should only be used when the culture of the conversion differs form the application culture or has an explicit value. The second case is the most frequently used and that’s where things get complicated. The value of the Language property of an element, if not explicitly set, is inherited from its container. In the case of Windows Phone 7, up to the phone application frame. And it’s never null.

I was expecting that the value of the Language property of the phone application frame would reflect the value of the current culture but, as far as I can tell, it’s always en-US.

So, if, unless explicitly set, the language is always en-US. How to specify which culture to use inside the value converter methods? The current culture could be used, but how to know if the language has been changed or the culture has been explicitly specified?

The solution is setting the language on the phone application frame and always to be able to use the culture parameter inside the converter methods:

this.RootFrame = new PhoneApplicationFrame
{
    Language = XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.Name)
};

The correct way to get the XML language would be to use the IetfLanguageTag property of the current culture, but that property is not available on Silverlight.

As far as I could find, you won’t get into trouble unless you’re dealing with Chinese cultures. But if you’re like me, you’ll probably be publishing your applications worldwide.

It’s not an hard problem to solve, though. A couple of extension method can solve it:

public static class CultureInfoExtensions
{
    public static XmlLanguage GetXmlLanguage(this CultureInfo culture)
    {
        return XmlLanguage.GetLanguage(culture.GetIetfLanguageTag());
    }

    public static string GetIetfLanguageTag(this CultureInfo culture)
    {
        switch (culture.Name)
        {
            case "zh-CHT":
                return "zh-Hant";
            case "zh-CHS":
                return "zh-Hans";
            default:
                return culture.Name;
        }
    }
}

And now the language of the root phone application frame can be properly initialized:

// Avoid double-initialization
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
    Debug.WriteLine("{0} >> InitializePhoneApplication", DateTime.Now.Ticks);

    if (this.phoneApplicationInitialized)
    {
        return;
    }

    // Create the frame but don't set it as RootVisual yet; this allows the splash
    // screen to remain active until the application is ready to render.
    this.RootFrame = new RadPhoneApplicationFrame
        {
            Language = CultureInfo.CurrentUICulture.GetXmlLanguage()
        };

    this.RootFrame.Navigated += CompleteInitializePhoneApplication;

    // Handle navigation failures
    this.RootFrame.NavigationFailed += RootFrame_NavigationFailed;

    // Ensure we don't initialize again
    this.phoneApplicationInitialized = true;
}

Resources:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Paulo Morgado
Software Developer (Senior) Paulo Morgado
Portugal Portugal

Comments and Discussions

 
GeneralFormatting PinmemberTim Corey9-Jul-12 10:44 
GeneralRe: Formatting PinmemberPaulo Morgado9-Jul-12 12:01 
AnswerRe: Formatting PinmemberTim Corey9-Jul-12 14:24 
GeneralRe: Formatting PinmemberPaulo Morgado9-Jul-12 14:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141220.1 | Last Updated 9 Jul 2012
Article Copyright 2012 by Paulo Morgado
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid