The StaticResource
markup extension works very well for what you are trying to accomplish. You can include almost anything using a StaticResource, even when a DynamicResource doesn't work:
<Window ...>
<Window.Resources>
<Span x:Key="Whatever">
<Bold>Hello</Bold> there<LineBreak/>
A green circle:
<InlineUIContainer>
<Ellipse Width="10" Height="10" Fill="Green" />
</InlineUIContainer>
</Inline>
</Window.Resources>
...
<TextBlock>
<StaticResource ResourceKey="Whatever" />
</TextBlock>
Now localizing this is easy:
- Move the
Span
resource into a separate ResourceDictionary
and merge into your Application's resource dictionary.
- During application startup and before any windows are created, use code to get the current culture and add an additional language-specific
ResourceDictionary
to application.Resources.MergedDictionaries
. The satellite dictionary can be loaded using WPF's built-in localization mechanism.
As long as the dictionares are merged into the application dictionary in the correct order, any named resource that is found in the localized dictioary will take precendence over the one in the main dictionary, for example your Spanish localization dll could have a xaml file containing this:
<ResourceDictionary>
<Span x:Key="Whatever">
El círculo rojo
<InlineUIContainer>
<Ellipse Width="10" Height="10" Fill="Red" />
</InlineUIContainer>
dice <Bold>hola!</Bold>
</Span>
</ResourceDictionary>
Note that the message is similar, but for Spanish the circle is red and the layout of the text is different.
You can take this much further with ControlTemplates if you want to. Using ControlTemplates will allow you to do such things as have buttons laid out in a different order depending on the locale. For example if your generic dictionary contains:
<ResourceDictionary>
<ControlTempate x:Key="Something" TargetType="ContentControl">
<StackPanel>
<TextBlock Text="In English we want the text above the button" />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</ResourceDictionary>
You can add this to your window or user control:
<ContentControl Template="{StaticResource Something}">
<Button Command="Save">Save File</Button>
</ContentControl>
And then you change the layout for another language, for example:
<ResourceDictionary>
<ControlTempate x:Key="Something" TargetType="ContentControl">
<DockPanel>
<ContentPresenter DockPanel.Dock="Left" />
<TextBlock Text="En español en el botón a la izquierda del texto" />
<!-- In spanish the button is to the left of the text -->
</DockPanel>
</ControlTemplate>
</ResourceDictionary>
Note: If you only use localization in DependencyProperties (eg no InlineCollections, etc) you can get away with using {DynamicResource}
which allows the locale to change at any time with an instant update of the UI. To do this with my first example, instead of including a <Span>
in the ResourceDictionary
and including it inside a TextBlock, you can put the TextBlock in a ControlTemplate inside the ResourceDictionary.
This is only the beginning of the flexibility of localization with WPF. You can go much further.