Saturday, November 30, 2013

How to use portable class libraries together with the Multilingual App Toolkit

Microsoft came up with two really nice features for Visual Studio:
  1. The Multilingual App Toolkit (MAT): The Visual Studio extension helps you to manage a simple localization process and even lets you pre-translate automatically with Bing translation Services. It´s built for Windows Phone and Windows Store Projects. Here you can read some more about how to get started.
  2. Portable Class Libraries (PCL): This feature Comes as a Project type for Visual Studio and lets you create assemblies that can be shared across .NET platforms. Therefore you can only use a common set of API calls. Here you can find some more about PCLs and the supported APIs
Lately I wanted to port a Windows Phone 7 App to Windows Phone 8, but still be able to keep a WP7 app with minimal redundancy to the WP8 app. Also I wanted a foundation to create a Windows Store app. So I decided to put most of the code into a portable class library. The app was localized into four languages and the translation process was based on the MAT. One major issue was that it is not possible to use the Multilingual App Toolkit inside a Portable Class Library project. In the end I found a solution that worked for me:
  1. A Windows Phone Project with just the resource files and Multilingual App Toolkit enabled (1). I use it to manage my localization. 
  2. A Portable Class Library project that includes all the .resx files as a link (2). It has all the platform Independent code in it that uses the resources (e.g. Models and Dataaccess, Viewmodels, Helpers) 
  3. Seperate Projects for Windows Phone 7 and Windows Phone 8 that just have the platform dependent code in it (3) (e.g. views, platform dependent helpers). Any other .Net project could use the code (e.g. WPF, Silverlight, Windows Store)


Here is what you have to do in detail to get it to work:

  1. Create a new project that you can use for localization MAT (1) :
    • the project could be any project type that supports the Multilingual App Toolkit (e.g. Windows Phone 8). 
    • You need to enable Multilingual App Toolkit ("Tools" -> "enable Multilingual App Toolkit")
    • Add your translation languages (rightclick on project -> "add translation languages...")
    • Build the project, so that MAT populates the .resx files)
    • Delete the generated designer file for you default language resources (e.g. "AppResources.resx"). Also remove the "custom tool"/"single file generator" in the file properties.
  2. Create a new PCL project (2).
    • By default, a PCL project will have "en" set as the neutral language inside the AssemlyInfo.cs file. So go therre and delete this line: [assembly: NeutralResourcesLanguage("en")]
    • Add the .resx files as linked files (rightclick on project -> "Add" -> "existing item" -> "Add as link")
    • Add the supported cultures to you project: 
      • rightclick on project -> "Unload Project"
      • rightclick on project -> "Edit"
      • Add the SupportedCultures xml element inside the first PropertyGroup element. It contains a list of supported cultures for the assembly: <SupportedCultures>de;fr;it</SupportedCultures>
    • Sadly I did not get the Pesudo Language "qps-ploc" to work from the PCL. I ould be glad to hear an explanation, why PCL does not Support the Pseudo Language?
  3. Create a new Windows Phone 8 project (3) and reference the PCL project. Do the same for a Windows Phone 7 or other .Net project

I created an example solution that follows this approach:
PCLplusMAT.zip (~500kb)
The example app shows how you bind to the PCL
resources and how to call localized helper methods

There are two ways of how to use the resources

Localized-Portable-Classes:

You can have portable helper classes with MAT-managed localization or even put your localized Viewmodels into the PCL. This is actually the main purpose and also what I do.

This is how a localized portable helper class could look like:
public static class HumanCalculator
{
    public static String TellMeTheSumOf(int numberA, int numberB)
    {
        return String.Format(AppResources.SumAnswerText, numberA, numberB, numberA + numberB);
    }
}

Exposed Resource Dictionary:

Use the resource dictionary inside the PCL throughout your .Net applications and bind to localized strings in Xaml. You could also accomplish this by linking to another set of resource files, but if you want to keep everything in one place, and as everything is set up allread, this is an easy way to use your resources from several peoject types:

The PCL could expose the following class:
public class LocalizedStrings
{
    private static readonly AppResources _localizedResources = new AppResources();

    /// <summary>
    /// Provides access to string resources.
    /// </summary>
    public AppResources LocalizedResources{get { return _localizedResources; }}
}

Then in your Plattform specific Project declare an instance of ot as a resorce inside App.xaml:
<Application.Resources>
    <portableLocalizedLibrary:LocalizedStrings x:Key="LocalizedStrings"/>
</Application.Resources>

And bind to your localized strings inside your page.xaml:
<TextBlock Text="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" />

If you add a new string just add it to AppResources.resx. It will show up instantly inside the designer just you are used to. In order to translate a string, you have to rebuild the MAT project (1) and head open the multilingual editor.

Hope this helps some of you. I´m open to any suggenstions or better ways to accomplish MAT+PCL.