In WPF la localizzazione è ‘ufficialmente’ compito di LocBaml, tool che personalmente preferisco evitare per una lunga serie di motivi, non ultima il fatto che la non è applicabile a Silverlight.
Per localizzare le applicazioni basate sul pattern Model-View-ViewModel la soluzione che utilizzo è la seguente.
Aggiungo al mio progetto i vari files .resX che contengono i vari testi localizzati:
Successivamente da ViewModelBase:
1: public class ViewModelBase : INotifyPropertyChanged
2: {
3: public event PropertyChangedEventHandler PropertyChanged;
4:
5: protected void OnPropertyChanged(string propertyName)
6: {
7: if (PropertyChanged != null)
8: {
9: PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
10: }
11: }
12: }
Eredito un generico LocalizableViewModel che rappresenta il ViewModel base per tutte quelle View che devono essere localizzate:
1: public abstract class LocalizableViewModel:ViewModelBase
2: {
3: private static Strings resources = new Strings();
4:
5: public LocalizableViewModel():base() { }
6:
7: protected void SetCulture(string userCulture)
8: {
9: if (Thread.CurrentThread.CurrentUICulture.Name != userCulture)
10: {
11: Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(userCulture);
12: this.OnPropertyChanged("LocalizedText");
13: }
14: }
15:
16: public Strings LocalizedText
17: {
18: get
19: {
20: return resources;
21: }
22: }
23: }
A questo punto un generico ViewModel non deve far altro che ereditare da LocalizableViewModel:
1: public class ShellViewModel:LocalizableViewModel
2: {
3: private List<string> availableCultures = new List<string>() { "it-IT", "en-US", "fr-FR" };
4: private string selectedCulture;
5:
6: public ShellViewModel():base(){}
7:
8: public List<string> AvailableCultures
9: {
10: get { return this.availableCultures; }
11: }
12:
13: public string SelectedCulture
14: {
15: get
16: {
17: return this.selectedCulture;
18: }
19:
20: set
21: {
22: if (value != this.selectedCulture)
23: {
24: this.selectedCulture = value;
25: this.SetCulture(value);
26: this.OnPropertyChanged("SelectedCulture");
27: }
28: }
29: }
30: }
Ora associamo il ViewModel alla view utilizzando la modalità che preferiamo:
1: <Window
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:local="clr-namespace:D08_LocalizationOnMVVM"
5: xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="D08_LocalizationOnMVVM.Window1"
6: Title="Window1" Height="300" Width="300" mc:Ignorable="d">
7: <Window.DataContext>
8: <local:ShellViewModel />
9: </Window.DataContext>
10: <Grid>
11: <TextBlock Height="20"
12: Margin="92,0,84,182"
13: x:Name="textBlock1"
14: VerticalAlignment="Bottom"
15: Text="{Binding LocalizedText.WelcomeText, Mode=OneWay}"
16: FontSize="18" />
17: <Button Margin="82,117,75,122"
18: x:Name="button1"
19: Content="{Binding LocalizedText.ButtonContent, Mode=OneWay}" />
20: <ComboBox x:Name="CultureComboBox"
21: ItemsSource="{Binding AvailableCultures}"
22: Height="25"
23: SelectedItem="{Binding SelectedCulture, Mode=TwoWay}"
24: SelectedIndex="0"
25: Margin="82,0,75,75"
26: VerticalAlignment="Bottom">
27: </ComboBox>
28: </Grid>
29: </Window>
Ottenendo una View che può così cambiare la propria lingua in tempo reale:
Il procedimento funziona sia con WPF che Silverlight, in quest’ultimo caso bisogna solo ricordarsi di editare il file di progetto e inserire manualmente le culture supportate nel tag <SupportedCultures>