Localization #3: Re-using localized resources on multi-platforms Apps

In the first two parts of this tutorial, you learned how to create a localized Windows Phone App.One of the strengths of the Windows platform is the ability to create multi-platform Apps that target both the Windows Phone and the Windows 8 (Windows Store Apps) platforms through the use of Portable Class Libraries. Using this approach, it is possible to prevent redundant code parts by implementing large parts of the code within a Portable Class Library which can then be referenced by both App projects. Wouldn’t it be nice if we could add all the localized content to such a Portable Class Library and reference it from there, instead of defining all the necessary resource files twice – once for the Windows Phone App (*.resx resource files) and once for the Windows Store App (*.resw resource files)?

In fact, this is really easy: Just move all the resource files as well as the LocalizedStrings helper class into an appropriate namespace within the Portable Class Library, and you’re almost done! The file name, structure and location of the resource files is the same as in usual Windows Phone projects, each resource files’ name ends with the 2-character language code or the 5-character culture code, followed by the “*.resx” file extension. You don’t need to take into account the special Windows Store App setup (usually, Windows Store Apps make use of *.resw resource files and the language/culture code is included in the containing folder instead of the file name), because the Portable Class library will take care of the conversion from the given *.resx files to *.resw. files.

The only aspect that is a bit tricky is the way of accessing localized resources from within the Windows Phone / Windows Store projects that reference the Portable Class Library. To access any AppResource.resx file from within C#/VB code, you can still directly call the AppResource class – but first you must ensure that each resource file’s Access Modifier is set to “Public”. If it is set to “No code generation”, no AppResources class is generated at all. If set to “Internal”, the AppResources class including all the contained properties (one for each localized string value) will generated, but it will be marked as internal – in contrast to a standalone Windows Phone App, the generated AppResources class will be located within the Portable Class Library (which in fact will be compiled as a separate assembly) and will therefore not be accessible from the App projects. Only if the Access Provider is set to “Public”, the App projects are allowed to access the AppResources class located in the Portable Class Library.

Public access modifier in resource file

The second topic is the question of how to access localized resources from within XAML code. If you do not need to change the current language from within the App as discussed in the artice Localization #2: Instant language switching, you can simply add a reference to LocalizedStrings in the App.xaml’s Resources section and call it from all pages as static reference. If a settings page that allows instant language switching is desired, it gets a bit tricky: The code for changing the language will typically be located within some Viewmodel, which is usually contained in the Portable Class Library. The problem is: From there, you don’t have access to the LocalizedStrings instance that is stored inside the App’s resources, because at compile time the Portable Class Library does not know about the Apps it will be included in – without having access to the current LocalizedStrings instance, however, you are not able to call the RefreshLanguage method that is required to notify the page that its content has changed!

The first solution that comes into your mind might be a Singleton class: Instead of keeping the instance of LocalizedStrings inside the App class, implement it as a Singleton such that its current instance can be accessed from everywhere!

public class LocalizedStrings : INotifyPropertyChanged
{
	// Singleton implementation
	private static readonly LocalizedStrings _instance = new LocalizedStrings();
	public static LocalizedStrings Instance
	{
		get { return _instance; }
	}
	private LocalizedStrings() { }
	
	// Reference to AppResources
	private static AppResources _localizedResources = new AppResources();
	public AppResources LocalizedResources { get { return _localizedResources; } }
	
	// Update language code:
	public event PropertyChangedEventHandler PropertyChanged;
	public void RefreshLanguage()
	{
		if (PropertyChanged != null)
		  PropertyChanged(this, new PropertyChangedEventArgs("LocalizedResources"));
	}
}

In theory, such a Singleton instance can be referenced in each page, whenever a localized string value is requested, as static property:

<TextBlock Text="{Binding Source={x:Static LocalizedStrings.Instance}, Path=AppResources.String1} " />

Unfortunately, this won’t work in Windows Phone and Windows Store projects since the x:Static Markup Extension is only available in WPF, but not in Silverlight and therefore not on these two platforms. The typical solution is to implement an additional provider class that wraps around the Singleton. Let’s call this LocalizedStringsProvider:

public class LocalizedStringsProvider
	public LocalizedStrings Strings
	{
		get
		{
			return LocalizedStrings.Instance;
		}
	}
} 

The LocalizedStringsProvider contains only one property: The one and only instance of the original LocalizedStrings class! This workaround allows our XAML pages to access the LocalizedStrings instance and all of its public members, first of all the AppResources property that again provides access to all the individual string resources!

Let’s see how to include this into your XAML code! In App.xaml, simply add a reference to the new LocalizedStringsProvider helper class as static resource:

<Application.Resources>
    <helpers:LocalizedStringsProvider x:Key="LocalizedStrings"/>
</Application.Resources>

(Of course, you need to replace the helpers: namespace from this example with the actual namespace that represents the LocalizedStringsProvider class’ exact location within the Portable Class Library, depending on your project setup.)

To include a certain localized string value in any XAML page, you can now make use of this static resource:

<TextBlock Text="{Binding Source={StaticResource LocalizedStrings}, Path=Strings.AppResources.String1}" />

To change the language and refresh the current page’s content, you can access the LocalizedStrings as follows:

Thread.CurrentThread.CurrentUICulture = new CultureInfo(LANGUAGE_CODE);
LocalizedStrings.Instance.RefreshLanguage();

Of course, the use of Singleton classes has some disadvantages and is regularly criticized – I’d like to propose an alternative approach for solving the problem of limited access from Portable Class Libraries to App resources, which of course also does not come free of drawbacks. Be sure to check out the final part of this sequence of tutorials Localization #4: Getting rid of Singletons localized multi-platform Apps and decide which solution better suits your requirements!