{"id":4330,"date":"2016-10-22T21:39:53","date_gmt":"2016-10-22T21:39:53","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=4330"},"modified":"2016-10-23T08:00:32","modified_gmt":"2016-10-23T08:00:32","slug":"localizing-a-wpf-application-using-dynamic-resources","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/localizing-a-wpf-application-using-dynamic-resources\/","title":{"rendered":"Localizing a WPF application using dynamic resources"},"content":{"rendered":"<p>There are several options for localizating a WPF application. We can use resx files, locbaml to create resource DLL&#8217;s for us, or why not just use the same technique used in theme&#8217;s, i.e. DynamicResource and ResourceDictionary&#8217;s.<\/p>\n<p>In this post I&#8217;m going to look at the DynamicResource and ResourceDictionary approach to localization. Although this technique can obviously be used with images etc., we&#8217;ll concentrate on dealing with strings, which usually are the main area of localization.<\/p>\n<p><strong>Let&#8217;s start with some code<\/strong><\/p>\n<p>Create a simple WPF application which will use the standard DynamicResource to set text on controls. We will create a &#8220;default&#8221; set of string resources to allow us to develop our initial application with and we will create two satellite assemblies which will contain the same string resources for en-GB and en-US resources.<\/p>\n<ul>\n<li>Create a WPF Application<\/strong>\n<li>Create a class library named Resources_en-GB and another class library named Resources_en-US<\/li>\n<li>Add the references PresnetationCore, PresentationFramework, WindowsBase and System.Xaml to these class libraries<\/li>\n<li>Change the class library output folders for Debug and Release to match those for the WPF application so the DLL&#8217;s will be built to the same folder as the application<\/li>\n<\/ul>\n<p>Now in the WPF application, add a ResourceDictionary, mine&#8217;s named Strings.xaml and this will act as our default\/design-time dictionary, here&#8217;s mine<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;ResourceDictionary xmlns=&quot;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation&quot;\r\n                    xmlns:x=&quot;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml&quot;\r\n                    xmlns:system=&quot;clr-namespace:System;assembly=mscorlib&quot;&gt;\r\n\r\n    &lt;system:String x:Key=&quot;Header&quot;&gt;TBC&lt;\/system:String&gt;\r\n    \r\n&lt;\/ResourceDictionary&gt;\r\n<\/pre>\n<p>and my MainWindow.xaml looks like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;Window x:Class=&quot;WpfLocalizable.MainWindow&quot;\r\n        xmlns=&quot;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation&quot;\r\n        xmlns:x=&quot;http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml&quot;\r\n        xmlns:d=&quot;http:\/\/schemas.microsoft.com\/expression\/blend\/2008&quot;\r\n        xmlns:mc=&quot;http:\/\/schemas.openxmlformats.org\/markup-compatibility\/2006&quot;\r\n        xmlns:local=&quot;clr-namespace:WpfLocalizable&quot;\r\n        mc:Ignorable=&quot;d&quot;\r\n        Title=&quot;MainWindow&quot; Height=&quot;350&quot; Width=&quot;525&quot;&gt;\r\n    &lt;StackPanel&gt;\r\n        &lt;TextBlock Text=&quot;{DynamicResource Header}&quot; FontSize=&quot;24&quot;\/&gt;\r\n        &lt;StackPanel Orientation=&quot;Horizontal&quot; VerticalAlignment=&quot;Bottom&quot;&gt;\r\n            &lt;Button Content=&quot;US&quot; Width=&quot;100&quot; Margin=&quot;10&quot; \/&gt;\r\n            &lt;Button Content=&quot;GB&quot; Width=&quot;100&quot; Margin=&quot;10&quot; \/&gt;\r\n        &lt;\/StackPanel&gt;\r\n    &lt;\/StackPanel&gt;\r\n&lt;\/Window&gt;\r\n<\/pre>\n<p>I didn&#8217;t say this was going to be exciting, did I?<\/p>\n<p>Now if you run the application as it currently stands, you&#8217;ll see the string TBC &#8211; our design-time string.<\/p>\n<p>Next, copy the Strings.xaml file from the application to both the Resources_en-GB and Resources_en-US and change the string text to represent your GB and US strings for header &#8211; I used the word Colour in GB and Color in US &#8211; just to demonstrate the common language differences.<\/p>\n<p>Now if you build and run the application, you&#8217;ll see the default header text still, so we now need to make the application set the resources at start-up and allow us to easily switch them. So change the buttons in MainWindow.xaml to these<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;Button Content=&quot;US&quot; Width=&quot;100&quot; Margin=&quot;10&quot; Click=&quot;US_OnClick&quot;\/&gt;\r\n&lt;Button Content=&quot;GB&quot; Width=&quot;100&quot; Margin=&quot;10&quot; Click=&quot;GB_OnClick&quot;\/&gt;\r\n<\/pre>\n<p>We&#8217;re going to simply use code behind for changing the resource in this demo. So in MainWindow.xaml.cs add the following code <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void LoadStringResource(string locale)\r\n{\r\n   var resources = new ResourceDictionary();\r\n\r\n   resources.Source = new Uri(&quot;pack:\/\/application:,,,\/Resources_&quot; + locale + &quot;;component\/Strings.xaml&quot;, UriKind.Absolute);\r\n\r\n   var current = Application.Current.Resources.MergedDictionaries.FirstOrDefault(\r\n                    m =&gt; m.Source.OriginalString.EndsWith(&quot;Strings.xaml&quot;));\r\n\r\n\r\n   if (current != null)\r\n   {\r\n      Application.Current.Resources.MergedDictionaries.Remove(current);\r\n   }\r\n\r\n   Application.Current.Resources.MergedDictionaries.Add(resources);\r\n}\r\n\r\nprivate void US_OnClick(object sender, RoutedEventArgs e)\r\n{\r\n   LoadStringResource(&quot;en-US&quot;);\r\n}\r\n\r\nprivate void GB_OnClick(object sender, RoutedEventArgs e)\r\n{\r\n   LoadStringResource(&quot;en-GB&quot;);\r\n}\r\n<\/pre>\n<p>and finally in the constructor let&#8217;s default to en-GB, so simply add this line after the InitializeComponent<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nLoadStringResource(&quot;en-GB&quot;);\r\n<\/pre>\n<p>Now run the application, be default you should see en-GB strings and then press the US button to see the en-US version etc.<\/p>\n<p><strong>Finishing touches<\/strong><\/p>\n<p>In some situations we might want to switch the languages strings used via an option (very useful when debugging but also in you&#8217;re natural language is not the same as the default on your machine). In most cases, we&#8217;re likely to want to switch the language at start-up to match the machines&#8217;s culture\/language.<\/p>\n<p>Using ResourceDictionary might look a little more complex than CSV files, but should be easy for your translators to use and being, ultimately, XML &#8211; we could ofcourse write a simple application to allow the translators to view strings etc. in a tabular format. <\/p>\n<p>We can deploy as many or as few localized resources as we need on a machine.<\/p>\n<p><strong>References<\/strong><\/p>\n<p>Checkout this a useful document <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ms788718(v=vs.110).aspx\" target=\"_blank\">WPF Globalization and Localization Overview<\/a> from Microsoft. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are several options for localizating a WPF application. We can use resx files, locbaml to create resource DLL&#8217;s for us, or why not just use the same technique used in theme&#8217;s, i.e. DynamicResource and ResourceDictionary&#8217;s. In this post I&#8217;m going to look at the DynamicResource and ResourceDictionary approach to localization. Although this technique can [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[137,138,13],"tags":[],"class_list":["post-4330","post","type-post","status-publish","format-standard","hentry","category-i18n","category-localizing","category-wpf"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=4330"}],"version-history":[{"count":13,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4330\/revisions"}],"predecessor-version":[{"id":4366,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4330\/revisions\/4366"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=4330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=4330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=4330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}