Saturday, April 26, 2008

WPF Localization - RESX Option

About a year ago I was building a WPF project in .Net 3.0 and Visual Studio 2005. I wanted to revisit this subject and see what has changed in .Net 3.5 and Visual Studio 2008. I will make a few of these posts to try and cover all the different options (RESX option, LocBaml option, Resource Dictionary Option). In this blog I will focus on using a resx file to localize an application.

To show how the resx option is done I created a WPF form with three labels on it. The first label has is text set inline in XAML, the second has it text set via code behind from the resx file and the third has its text set via XAML accessing the resx file.

The first thing that needs to happen to setup a project for localization is a small change to the project file. To make this change you will need to open the project file in notepad (or some other generic editor). In the first PropertyGroup section you need to add the follow XML node <UICulture>en-US</UICulture>. So the project file node would look like this:




Adding this to the project file config will cause the IDE to create a resource.dll when you compile. Now we need to create our resx file. I like to create a Resources folder to keep my resx files in (You will have to create a resx file for each language you want to have). I created three labels in my XAML to show how this will work.

<Window x:Class="WpfLocalization.Window1"
    Title="Window1" Height="300" Width="300"    
        <Label Height="28" Margin="10,13,33,0" 
               Name="lblFromXAML" Content="Text from XAML" 
        <Label Height="28" Margin="10,43,33,0" Name="lblFromResource" 
        <Label Height="28" Margin="10,71,33,0" Name="lblXAMLResource" 
               Content="{x:Static properties:UIStrings.lblXAMLResource}"></Label>

The first label is just used to show that text in the XAML does not change when we change the culture. The second label will be changed in code using the following:

public Window1()
    //UIStrings.Culture = new System.Globalization.CultureInfo("de-DE");
    lblFromResource.Content = UIStrings.lblFromResourcesText;

Pretty simple code. You will notice the third label has a binding in the content to do this. In my opinion this is the best way to do this as all your UI display is isolated to the XAML. However, I realize that in an enterprise application you will probably need code to decided what text is displayed (this could be accomplished using a trigger in  your style but that discussion is for another time). In order to do this binding though you have to include the xmlns import to your resx file. You will note that I imported the clr-namespace of WpfLocalization.Resources which is the namespace of my resx file. I can then bind to the static resource of properties:UIStrings.lblXAMLResource which pulls the text for my lblXAMLResource label (I gave my resource string and my label the same name).  When I run the application here is what I get.image Now I can copy my current resx file of UIStrings.resx and make a new resx file called I can then edit the text in this new resx file for my German text. The next time I build the compiler will create a secondary resource.dll file for de_DE. If I un-comment the line of code that is commented out above (this code changes the culture form the default of US to de-DE which is Germany) and run the application again I get different text as the resx resource that is used is for my de-DE culture. image I have uploaded the source code for this example as well if you would like to see the entire solution.

You will notice that at the top of the resx editor you have the ability to select rather or not the values in the resx are internal or public. This is new to .Net 3.5 and Visual Studio 2008. In Visual Studio 2005 you could not make these values public. They were always private and there for not accessible to the XAML file via the binding method or accessible to other projects in your solution.


Seba said...

Your post is not 100% correct. The <UICulture>en-US</UICulture< property in the project file is not needed for the resx option. This will generate a localized sattelite assembly for the en-US culture but this file will only contain the baml localizations. The neutral language resources will be compiled in your main assembly (the classic .NET approach)

Nader Alkhatib said...

HariOm said...

This solutions is fine if you have resources public but it won't work with internal resources.

summ3r said...

Hello, Toad! :) If you're interested in a localization tool that can help manage the translation of RESX filex, check out the localization management platform