Windows Support Number

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Friday, 23 March 2012

Building a multilingual MVVM app

Posted on 07:08 by Unknown
Last week I built a sample multilingual app in WPF using MVVM for a proof of concept. This was the first time I've built a desktop app which supported different languages at runtime. Previously I've worked on multilingual websites and desktop apps but not ones that support changing the language of the UI dynamically via a UI control like a menu item.

The app was pretty simple, a single input field representing a number where the value has to be within a fixed range (-100 to 100). If the input failed the validation an error message would be displayed.

What I came up with is shown below, it supports three cultures - English, French & German. The culture (language) is selected by either the menu or the F1 - F3 keys. How I achieved this is what follows.
What I wanted to achieve was the model & view model being agnostic to any concern about the currently selected culture (language). The view model used for the English version should be the same for the French or German versions.

The model we'll be binding via the view model is shown below, as you can see no knowledge of the currently selected UI language.
The view model is shown below, this will be bound to the view via an implementation of the view model Locator pattern.
The view model like the model also has no knowledge of the currently selected UI language. What should also be noted is the lack of validation in the view model. Normally if one was developing an app for a single culture you could use the IDataErrorInfo interface in the System.ComponentModel to return the required validation message. This could have been done in this example, but I ddidn't want the view model to know anything about the current culture, if I had used it I would then have to worked out the current culture and then selected the correctly translated message. I see the concern of translating the validation message a responsibility of the view not the view model.

I did the validation via a custom validation rule - by implementing my own validation rule this allowed me to code up the required field input rules - a number where the value has to be within a fixed range (-100 to 100).
This is where the concerns of the UI culture start to come into play, the last two lines of the above validation rule take care of loading the correct culture invalid input message. How exactly this is done is described later. This is then used declarative in the view XAML, thus pushing the input validation to the correct area of concern, the view:
The  colours used for displaying the validation message are controlled by the style applied to the TextBox control, it defines when and how the validation tool-tip fades in & out.

What you can see from the XAML is a converter applied to the binding, this will only be called if the input validation executes successfully. The converter is also affected by the current UI culture, as you can see it is passed to each method. This means the double.Parse will correctly handle what ever number separators are defined for the culture:
That covers all the other parts required for multiple culture support, but the question still remains:

How exactly are the different cultural string being render by the view?

This is where it started to get complex for the simple reason the documentation on how to do this is confusing, I couldn't find a coherent strategy on MSDN. Googling for 'multilingual support WPF' does list MSDN as the first result, after reading through this I just started to get a headache...

I was looking for a way to declaratively define which strings need to support multiple cultures, it also need to separate the cultures into different files. I knew I was going to need to work with resource files (*.resx). The Google search above provided a lot of links pointing to solutions available on codeproject.com, I counted at least 5 different ways on the first page.

I decided to go with first in the list - 'WPF Localization Using RESX Files'. This solution provided both a declarative (XAML) and imperative (code-behind) methods, in fact it turned out to be so simple I can't believe you can't get this package on NuGet.

I recommend reading the article for the full details on how to add support to your app. First off I modified  the XAML by adding the a declaration at the top of the page:
Then I updated all string values that need to support multiple cultures:
The ResxExtension.DefaultResxName property in the window declaration defines where to find the required resx file. As you can see from the screen shot below there are also separate RESX files for the French & German resources:
The English & German resource properties window from visual studio are shown below:
Each RESX file needs to define the Custom Tool & Custom Tool Namespace via the properties window in visual studio. This is so the RESX file is compiled and available in C# code - that's how we access the resource in the last 2 lines in the custom validator earlier:
RESX file properties in visual studio:
The only thing left now is how to change the culture at runtime. I did this via a menu, but in theory this could be done any suitable UI control. All I did was declare a menu items in the XAML and then wire in the click events to the code-behind of the view:
Declared in the XAML:
As you can see the Header properties are bound to the resource manager and the click events are handled in the code behind. The code behind is initialised as follows;
We add an event handler for when the culture changes so we can update the menu items:
We also added the key bindings F1 - F3 to allow a keyboard drive approach. As you can see the English is represented by F1 and the command is routed through to the HandleEnglish method, this is an overload of the method wired in via the XAML for the English menu click. This is where the real magic happens the resource manager is updated with the new culture and instantaneously everything declared with a Resx binding in the XAML automatically updates:
Bring this all together gives me the ability to do any multilingual support in the view of my MVVM implementation.

I've put the implementation up on skydrive:

Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Posted in C#, Development, Multilingual, WPF Cultures | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Unit testing Rx methods Timeout & Retry with moq
    Earlier this week I was trying to unit test an asynchronous service (Foo) which used another asynchronous service (Bar) internally and ran i...
  • StructureMap: ILifecycle
    The other day I wanted to control the scope of a service inside a web based app with semantics which didn't fit either 'HttpContextS...
  • Implementing a busy indicator using a visual overlay in MVVM
    This is a technique we use at work to lock the UI whilst some long running process is happening - preventing the user clicking on stuff whil...
  • Be careful of the culture when using Bing Maps REST API
    When developing the Bing Maps Wrapper service for the WP7Contrib we weren't aware of the importance of the instance of the CultureInfo ...
  • No GetEntryAssembly in Silverlight!
    Ran into a problem today, wanting to get the assembly that started the an application. Now this isn't a tricky problem just had to bend ...
  • Can I make a value object from an entity?
    I've built a rich domain model for a private app I'm working on, it feels right, it got the correct mix of business functionality an...
  • Considerations when building a caching mechanism for WP7Contrib.
    For anyone wanting to build a cache for an application, there are several guidelines(may be rules) you want to beware of and more than likel...
  • WP7Contrib: Bing Maps REST Services Wrapper - Deep Dive
    Following on from Rich's post introducing the Bing Maps Service in the WP7Contrib I'm going to explain in more detail how we built ...
  • Using CompositeDisposable in base classes
    To help make an object eligible for collection by the GC (garbage collector) one would implement the IDisposable interface. Executing the di...
  • Tricky continuous testing and self hosting WebAPI issue...
    When using WebAPI inside a test fixture make sure you shutdown the HttpSelfHostServer instance correctly or your tests will more than likely...

Categories

  • .Net
  • .Net 4.5
  • Abstractions
  • Advertising
  • Agile
  • Agile Courage
  • AOP
  • Async
  • automated testing
  • Azure
  • Azure IIS RESTful development
  • BDD
  • Bing Maps
  • Bounded Context
  • C#
  • C# 5.0
  • Caching
  • Chocolatey
  • CLoud
  • CodePlex
  • Coding
  • Coding Building CI Testing
  • Coding C#
  • coding C# IoC StructureMap
  • Coding Functional-Programming
  • Coding REST Knowledge
  • Coding Services
  • Coding TDD Refactoring Agile
  • Command
  • continuous testing
  • coupling
  • CultureInfo
  • DAL
  • databases
  • DDD
  • DDD Coaching
  • DDD Domain Events Auditing nHibernate
  • DDD Entities Value Objects
  • Debugging
  • Design Patterns
  • Design Patterns Databases Auditing
  • Developement
  • Development
  • Development Coding
  • Development Process
  • Development unit testing
  • Development VS 2011
  • Diagnostics
  • Disposable
  • Exceptions
  • FINDaPAD
  • FindaPad Property Rental Windows Phone 7 Mobile Devices
  • Fun Coding Duct-Tape
  • Hotfixes
  • integration testing
  • IoC
  • jasmine
  • javascript
  • Jobs Development
  • LINQ
  • marketplace
  • Mobile Devices
  • Mocking
  • MSDN Coding
  • MSpec
  • Multilingual
  • MVC
  • MVVM
  • nCrunch
  • nHbiernate Repository Pattern Criteria
  • nHibernate Auditing Design Fluent
  • nHibnerate Entities Events Listeners
  • node.js
  • nodes.js
  • Nokia
  • NoSQL RavenDB Azure Development
  • Observations
  • OO
  • ORM
  • Performance
  • Portable Class Library
  • Portable Library
  • PostSharp
  • Process
  • Rants
  • RavenDB IIS 7.5 Development
  • Reactive
  • Reactive Extension
  • Reactive Extensions
  • ReadOnlyCollections
  • Resharper
  • REST Distributed-Systems
  • REST HTTP
  • rest web
  • RESTful
  • Rx
  • Serialization
  • Silverlight
  • Silverlight Installation
  • Task
  • TDD
  • TDD IoC DI
  • TDD Mocking
  • TDD Team Observation
  • Telerik
  • testing
  • threading
  • TPL
  • UI
  • Undo-Redo
  • unit testing
  • ViewModels
  • VS 2012
  • wcf
  • web api
  • Web Services
  • web services mobile devices data
  • WebAPI
  • Windows
  • Windows 8
  • windows phone
  • Windows Phone 7
  • WP7
  • WP7 Bing Maps Development Network HTTP
  • WP7 Bing Maps Development UK Crime
  • WP7 Bing Maps Development UK Crime Clustering
  • WP7 Bing Maps Development UK Polygons Clustering Performance
  • WP7 cryptography bouncy castle
  • WP7 Cultures C#
  • WP7 feedback development app store
  • WP7 Javascript web browser
  • WP7 MSBuild
  • WP7 ORM Databases performance
  • WP7 Serialisation
  • WP7 SilverlightSerializer C#
  • WP7 sqlite performance development
  • WP7 WP7Contrib Bing Maps Development
  • WP7 WP7Contrib Bing Maps Polygon Development
  • WP7 WP7Contrib CodePlex
  • WP7 WP7Contrib CodePlex Bing Maps Development
  • WP7 WP7Contrib CodePlex ObservableCollection
  • WP7 WP7Contrib ILMerge .Net
  • WP7 WP7Contrib Phone Maps
  • WP7 WP7Contrib SilverlightSerializer C#
  • WP7Contrib
  • WP7Contrib Bing Maps WP7
  • WP7Contrib WP7 Geo-Location development C#
  • WP7Contrib WP7 HTTP Compression
  • WP7Contrib WP7 Url Development Rx
  • WP7Dev
  • WPF
  • WPF Cultures
  • WuApi
  • XAML

Blog Archive

  • ►  2013 (16)
    • ►  November (5)
    • ►  September (3)
    • ►  August (1)
    • ►  July (1)
    • ►  June (3)
    • ►  May (2)
    • ►  January (1)
  • ▼  2012 (44)
    • ►  November (2)
    • ►  October (8)
    • ►  September (5)
    • ►  August (2)
    • ►  July (4)
    • ►  June (3)
    • ►  May (1)
    • ►  April (2)
    • ▼  March (13)
      • faking data in WP7 and other .Net platforms
      • Coupling and cohesion
      • Integrating jasmine into Visual Studio 2010/2011 beta
      • Playing around with jasmine
      • Building a multilingual MVVM app
      • Getting NLog working with Azure is as easy as 1, 2...
      • Showing a message box from a ViewModel in MVVM
      • Removing the 'Invalid Credentials... ' message fro...
      • Azure - RoleEnvironmentException in OnStart
      • Azure - what a disappointing developer experience...
      • "Configuration system failed to initialize" when u...
      • How fast is CallerInfoAttributes for INotifyProper...
      • Affects of caching on UI service layer
    • ►  February (4)
  • ►  2011 (52)
    • ►  December (3)
    • ►  November (5)
    • ►  October (7)
    • ►  September (7)
    • ►  August (11)
    • ►  July (4)
    • ►  May (2)
    • ►  April (1)
    • ►  March (5)
    • ►  February (3)
    • ►  January (4)
  • ►  2010 (1)
    • ►  August (1)
  • ►  2009 (32)
    • ►  December (3)
    • ►  November (7)
    • ►  October (6)
    • ►  September (11)
    • ►  April (1)
    • ►  March (4)
Powered by Blogger.

About Me

Unknown
View my complete profile