пятница, 10 августа 2012 г.

Localize a Windows Phone 7 Application


Here’s a quick guide to add content localization in your Silverlight-based Windows Phone 7 application plus a bonus dynamic way to do it (read the official documentation to get the fine prints).
First add a resource file (.resx) for each language you want to support. Here we have the default one (English) and the same filename for French  labels except the .fr suffix.
solution explorer
Don’t forget to choose “public” as the class visibility level (for the binding).
Resources settings
Unload your project and edit the csproj file to add your supported language:
CsProj
(Here the “fr” works for all regions below the “fr” culture: fr-FR, fr-CA etc.)
In the properties of your project add your default culture:
Default Language
Now add a class  (LabelsManager) to be the middle-man between the XAML and the resources files. We can’t use  directly the generated class because you need a class with a default constructor to be able to use it in the XAML.
1public class LabelsManager {
2     public Labels Labels { getset; }
3     public LabelsManager()
4     {
5        Labels = new Labels();
6     }
7}
Add an instance of the class as a resource in the application (App.xaml):
1<Application.Resources>
2     <Resources:LabelsManager x:Key="LabelsManager" />
3</Application.Resources>
Now you can bind the Text Property of your TextBlock controls to your resources (see the blog of Karl Shifflet for the code of the manager class):
1<TextBlock TextWrapping="Wrap" x:Name="PageTitle" Text="{Binding Source={StaticResource LabelsManager},Path=Labels.Title, Mode=OneTime}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
If you change the language of the emulator and restart it,you will see that the label gets the correct value :
en
params
fr
Now if you want a way to dynamically change the culture and therefore the UI you need a a little more sophisticated Manager class. First the OneTime binding can’t be used anymore since we want something dynamic. Second the manager class needs to implement the famousINotifyPropertyChanged interface. So here’s the code of the new class:
01public class LabelsManagerDynamic : INotifyPropertyChanged
02{
03    private Labels labels;
04 
05    public Labels Labels
06    {
07        get return labels; }          
08    }
09 
10    public LabelsManagerDynamic()
11    {
12        labels = new Labels();
13    }
14 
15    public void ResetResources()
16    {
17        OnPropertyChanged(() => Labels);
18    }
19 
20 
21    #region INotifyPropertyChanged region
22    (...)
23    #endregion
24}
In the Main class if we want to change the current culture we need to: change it in the current thread and somehow warn Silverlight that something changed with the PropertyChanged event:
01private void EnglishBt_Click(object sender, RoutedEventArgs e)
02{
03    Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
04    Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
05    ResetResources();
06}
07 
08private void ResetResources()
09{
10    ((LabelsManagerDynamic)App.Current.Resources["LabelsManagerDynamic"]).ResetResources();
11}
The chain of events goes like this : first execution (en) => click on the button => change UI Culture => call ResetResources method on the Manager class => Raised PropertyChanged event => Silverlight re-binds the property and calls the getter on the Labels property and gets the French version of the resources.
dynamic
I used this post from Tim Heuer for the dynamic version.
Here’s the source code of the project on GitHub.

Комментариев нет: