Localizing Xamarin.Forms apps when using a shared project


Localizing Xamarin.Forms apps when using a shared project

This winter we built a cross platform app for Langham Preaching using Xamarin Forms. Forms allowed us to be quite productive and we pushed out a long backlog of stories simultaneously on both Android and iOS platforms. This was possible partly because we could share more than 90% of our code between the two platforms by using two shared projects:

Langham.Model – all the data entities and persistence with unit tests covering the business logic.
Langham – all the UI and presentation

Langham targets this app for use by it’s members who live in 22 different countries world wide. Most of those users would not be preparing their sermons in English and so it was no surprise to see a localization story in the product backlog.

The official guide to do this is Localizing Xamarin.Forms Apps with RESX Resource Files. However, near the top of the guide we find this warning:

Shared Projects are not recommended
The remainder of this document relates to projects using the Xamarin.Forms PCL template.

We didn’t want to change our shared projects into portable class libraries, because we never need to share this code with any other solutions and we don’t need the risk of picking a PCL profile that will later prove to be limiting. Also .NET Standard did not look quite ready for primetime. So, we had to roll our own localization mechanism.

Merging namespaces

It made most sense to embed the language resource files in the shared UI project. The difficulty with this was, that we had to flatten the namespace so the .Net resource manager could resolve the assembly reference. Our UI project had many sub namespaces like Langham.Sermons, Langham.Clubs, Langham.Content etc. We did not need to touch these. But we did have to flatten Langham.iOS and Langham.Droid to be just one namespace with Langham. Since more than 90% of our code was in the shared projects it was just renaming one or two classes and changing the namespace declaration on less than a dozen files and we were good to go.

Locale service

We start off our localization with a simple interface which exposes just enough functionality to serve our business layer and unit tests:

The real work is done in an abstract class in the UI project where we have this:

Google and Apple have their own conventions of naming locales and these are standardised to the Microsoft way by platform-specific implementations of the two abstract methods. The CultureInfo value is cached because it is called a lot and expensive to calculate.

Take a look at this article’s gist for details of the two platform specific abstractions for iOS and Android.

Now all that is left to do is to register the service with our service container in the bootup code. For example in our AppDelegate.cs file for the iOS project we use TinyIoC like this:

Usage in code

To use the mechanism to get a local translation of a literal string, we can do something like this in our c# view models:

Usage in layouts

But most of our literal strings were in XAML files, so to localize those we use this XAML markup extension.

Now we can do this:

Just remember to reference your local namespace in the XAML root tag:

Resource file properties

The current Xamarin build system can not generate the Resource.Designer.cs file for us, but since we don’t use it, just set all your .resx files to the following properties:
resource file properties

Jannie Theunissen
No Comments

Post A Comment