Sorry to leave you in suspense like that. It’s been a busy few weeks completing a large Silverlight Prism/MVVM application.
We have an original solution to all the localisation challenges outlined below:
- You want the translated strings to be stored in a centralised location for easy of translation and maintenance.
- You only need one language at a time to be visible.
- You only want to download to the client the selected language.
- You probably would not want to change the current language while in the middle of a critical operation (like form entry).
- You want to make it easy for the developer to add new strings without worrying about maintaining a database.
- You want to make it easy for localisation testers to edit and view changes inside the running application.
Your first impression may be that the solution is overly complex, but trust me when I say you get a lot of ongoing value in return (and the individual components were not that hard to build).
Attached Properties to the Rescue!
Attached properties are a marvellous invention. They allow any object (that derives from DependencyObject) to store values that they have no knowledge of. The most common examples given are the Grid.Column and Grid.Row properties. They are stored in the children of a Grid, but only the Grid knows of them and what to do with them. The child objects have no idea they are carrying parasitic values around.
A little known detail you may be able to make use of is: that AttachedProperty Setxxx methods are called as XAML files are parsed, even if you don’t actually store the attached values! This gives you somewhere to hook code to do special things as the XAML is loaded.
The components of our solution are:
- Create a Loc class containing PageId and Key dependency properties (at a minimum). We also added MaxLength and Notes properties to optionally give translators more information (e.g. about restrictions on the translation length).
- Key Property: The secret is to put your lookup code in the static SetKey method you had to create, as this is called whenever a loc:Loc.Key property is found as your XAML files are parsed.
- Mark every page and user-control in your project with a PageId Attached Property. Give them all a unique meaningful name (probably the name of the assembly and XAML file).
- Mark every control that contains any text to be localised with a Key Attached Property, identifying the translation key.
- Create a server-side Localisation database with at least Phrase, Translation, Page and PagePhrases tables. For a more serious set-up you will probably want Cultures, Translators and TranslatorCultures tables as well.
- Create a RIA services project (e.g. called CompanyName.Localisation.Web and CompanyName.Localisation)
- Add an ADO.NET Entity Data Model and connect it to your localisation database tables.
- Create a RIA Services “Domain Service Class” giving you access to the localisation Entity Data Model.
- Create a LocalisationManager class to act as a single port of call for all your localisation needs.
- If you are producing a Prism app, you will also create an ILocalisationProvider interface (with methods to change the language and fetch translations based on key values).
- Optional: Create a XAML interface for viewing and editing translations from within your application (this is the only difficult step, as any good interface with lots of parts is hard work).
The reason for marking all pages and user-controls is that, normally, from inside a XAML page you have no idea of what page you are in. It is all just a visual tree of components. Having an attached PageId property means you can now do cool stuff like relate translation keys, to the controls they appear on, at runtime. This becomes especially useful when you add a user interface that allows language Translators to edit the language strings at runtime. This feature is worth the effort and will amaze your clients.
By using Attached Properties for the localisation of individual controls, you get the following benefits immediately:
- The original “Programmer English” strings are unchanged so are visible and human-readable as normal.
- The original string is available to use as the starting default value for your translations. You can even have the Key SetKey method send all keys and original text to the database (maybe in debug mode)! No need to add it manually.
- These Attached Properties can be found, at runtime, by a recursive search of the visual tree allowing instant replacement when the language changes.
By providing a single point of entry for localisation you can also use the same system to access translated strings programmatically. This is a requirement as there are also strings somewhere that are not simply authored into the XAML pages.
You now know all the secrets of how we got it to work. In part 3 we will show specific examples of the various components. In the meantime we are always available for consultation and development tasks, so drop us a line via our contact page.