The application I'm trying to localize is a WinForms application that has a few hosted WPF user controls (WPF user controls hosted in an ElementHost WinForms control).
I use resx files to localize the WinForms, which VS2008 manages quite well.
The problem starts when I try to use the LocBaml method to localize the WPF parts.
Here's what happens:
When I build the solution, Visual Studio automatically generates satellite assemblies for me but only for the WinForms resources in the resx files.
Then, when I use the LocBaml command-line tool, it generates satellite assemblies for me but only for the WPF resources in the xaml files.
I haven't figured out how to merge the two resulting DLLs (WPF & WinForms) into a single satellite assembly.
Blech...The WPF team sure seemed to leave something to be desired with their localization solution. Well, for what it's worth, here's what I've been doing (to be fair, I've actually borrowed this idea from Jecho Jekov on CodeProject):
First, you'll need to create (or borrow) a Localization MarkupExtension class. Jecho calls his LocExtension, I called mine i18nExtension for no reason other than I felt it was a little more descriptive than Loc. What this markup extension will do is lookup a given resource key in your resource file. This is a really simple and easy class to code up if you want all of your resources located in the Properties/Resources.resx file.
What you end up with is something like this in your xaml:
<UserControl ... >
...
<TextBox Text="{i18n HelloWorld}"/>
...
</UserControl>
If you want to have separate resx files for each UserControl/Window as the WinForms designer allows you to do, you'll have to get a little more creative in your MarkupExtension so that it can figure out its context.
Ultimately, you end up with one satellite assembly per culture, which is what it seems your after. The one caveat that comes to mind is that I'm not sure how this deals with on-the-fly culture/language changes. At the very least, the Window/Control will need to be reloaded.
In order to get the method dustyburwell posted working in WinForms-embedded WPF user controls, you need to set the culture to the usercontrol after the InitializeComponent() call at the WinForms form constructor and then update the values.
- Declare WinForms Form.
- Add ElementHost (elementHost1).
- Add your WPF UserControl in the elementHost1 (userControl1).
- Open Form's code. Write the following code:
public Form1()
{
InitializeComponent();
WpfLocalization.LocalizationScope.SetCulture(userControl1, System.Threading.Thread.CurrentThread.CurrentCulture);
WpfLocalization.LocalizationScope.SetUICulture(userControl1, System.Threading.Thread.CurrentThread.CurrentCulture);
WpfLocalization.LocalizationManager.UpdateValues();
}
Whenever the CurrentCulture changed, this 3 lines must be called for each WinForms-embedded WPF user control.
How to merge multiple sets of resources into a single satellite assembly
The correct method is to use AL.exe (the assembly linker tool) to embed both the windows form .resources file and the .resources generated by LocBaml into a single satellite assembly (replacing the original build by default containing only the WinForms resources).
The steps to build a hybrid app would be:
- Build your solution (generating WinForms-only .resource file and satellite dll).
- Generate your XAML .resource file using the locBaml tool
- Use AL.exe to link both sets of .resource files into a new hybrid satellite dll and replace the original from step 1. Rebuilding the project will need steps 2 and 3 repeated to re-merge the xaml resources, so you probably want to automate this by adding it as a build step or target.
Example Usage:
Al.exe /out:MyApp.resources.dll /culture:es-ES /embed:MyApp.Form1.es-ES.resources /embed:MyAppWpf.g.es-ES.resources
More information (Localizing a Hybrid Application) http://msdn.microsoft.com/en-us/library/ms754231.aspx