views:

2961

answers:

4

Can you recomend me a good way to implement a Multilanguage system for a WPF app?

The method i'm using right now involves xml, classes and a xaml extension. Works fine in most of cases, but when I have to deal with dynamic labels or dynamic text in general it require some extra effort. I would like to let the programmer working only in the main problem and forgot the lang issues.

Thanks.

+3  A: 

Step 1) Place all string fragments in a separate stringtable resource file. example: stringResources.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">

<!-- String resource that can be localized -->
<system:String x:Key="All_Vehicles">All Vehicles</system:String>

</ResourceDictionary>

step 2: make copies for each language and add them (translated) to the merged dictionaries. example App.xaml

<Application x:Class="WpfStringTables.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="StringResources.de-DE.xaml" />
<ResourceDictionary Source="StringResources.nl-NL.xaml" />
<ResourceDictionary Source="StringResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

The last resource file with strings will be used to replace text parts in code.

step 3a: Use the text parts from the string table example Window1.xaml

<Window x:Class="WpfStringTables.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Button Margin="51,82,108,129" Name="button1" Content="{StaticResource All_Vehicles}"/>
</Grid>
</Window>

step 3b: load the resource from code

void Page_Load()
{
  string str = FindResource("All_Vehicles").ToString();
}

step 4: switch to new culture at start of application Codesnippet from App.xaml.cs

public static void SelectCulture( string culture )    
{      
  // List all our resources      
  List<ResourceDictionary> dictionaryList = new List<ResourceDictionary>();      
  foreach ( ResourceDictionary dictionary in   Application.Current.Resources.MergedDictionaries )      
  {        
    dictionaryList.Add( dictionary );      
  }      
  // We want our specific culture      
  string requestedCulture = string.Format( "StringResources.{0}.xaml", culture );
  ResourceDictionary resourceDictionary = dictionaryList.FirstOrDefault( d => d.Source.OriginalString == requestedCulture );      
  if ( resourceDictionary == null )      
  {        
    // If not found, we select our default language        
    //        
    requestedCulture = "StringResources.xaml";
    resourceDictionary = dictionaryList.FirstOrDefault( d => d.Source.OriginalString == requestedCulture );
  }      

  // If we have the requested resource, remove it from the list and place at the end.\      
  // Then this language will be our string table to use.      
  if ( resourceDictionary != null )      
  {        
    Application.Current.Resources.MergedDictionaries.Remove( resourceDictionary );
    Application.Current.Resources.MergedDictionaries.Add( resourceDictionary );      
  }      
  // Inform the threads of the new culture      
  Thread.CurrentThread.CurrentCulture =   CultureInfo.CreateSpecificCulture( culture );
  Thread.CurrentThread.CurrentUICulture = new CultureInfo( culture );    
}
Andre van Heerwaarde
+1  A: 

Josh Smith wrote an in-depth tutorial about his preferred method for this: Creating an Internationalized Wizard in WPF.

It might point you towards a big redesign (it's a MVVM solution), but using MVVM seems worth it for other reasons as well.

Wilka
+1  A: 

I am using WPF Localization Extension. It is a realy easy way to localize any type of DependencyProperties on DependencyObjects.

  • is in a real stabel state
  • supports binding-like write style like "Text = {LocText ResAssembly:ResFile:ResKey}"
  • works with the .resx-fallback mechanism (e.g. en-us -> en -> independent culture)
  • supports culture forcing (e.g. "this has to be english all the time")
  • works with normal dependency properties
  • works with control templates
  • can be used in xaml (really :P) without any aditional namespace
  • can be used in code behind to bind localized values to dynamic generated controls
  • implements INotifyPropertyChanged for advanced use
  • supports formating e.g. "this is the '{0}' value"
  • supports prefix and suffix values (currently with LocText extension)
  • is in use in productive systems (like my public relation product)
  • switching of the language to runtime affects NO timeslice
  • can be used with any resource file (.resx) accross all assemblies (also the dynamic loaded one at runtime)
  • dont need any initializing process (like "call xyz to register a special localize dictionary")
  • is available at designtime (MS Expression Blend, MS VisualStudio 2008 (Normal and SP1)
  • change of the choosen language is possible at designtime
  • can localize any type of data type, as long a converter (TypeConverter) for it exists (extend LocalizeExtension)
  • has build in support for Text, upper Text, lower Text, Images, Brushes, Double and Thickness
  • dont affects any memory leaks
  • leaves the UID property untouched
  • offers a "SpecificCulture" to use as IFormatProvider (e.g. (123.20).ToString(LocalizeDictionary.SpecificCulture) = "123.20" or "123,20")
  • offers some functionality to check and get resource values in code behind
  • dont alter the culture on Thread.CurrentCulture or Thread.CurrentUICulture (can be changed easily)
M. Jahedbozorgan
A: 

Here:

http://simplesample.site90.com/wpf_multiidioma.php

you will find a simple approach using XML and a Dictionary Class. That easy.

Rafa