Click here to Skip to main content
Click here to Skip to main content

WPF Localization Using RESX Files

By , 13 Feb 2013
 

Introduction

For developers used to the integrated, inbuilt localization support for Windows Forms applications, the Microsoft approach to localizing WPF applications using the somewhat primitive Locbaml tool can come as a shock. Some of the issues that have been identified with this approach are:

  • The localization process is not integrated into the standard Visual Studio build mechanism (as it is for Windows Forms applications).
  • There is no way to view or edit the localized XAML within the Visual Studio designer.
  • Locbaml uses CSV files and has issues when the translated text includes commas. The use of CSV files forces translators to work with two separate mechanisms since they still have to work with standard .NET RESX files for programmatically translated strings.
  • The Locbaml approach results in the complete binary XAML for the window being replicated in the satellite assemblies for each localized language. This results in much larger footprint for localized applications compared to the Windows Forms approach where only those resources that differ from the invariant culture are compiled into the satellite assemblies.
  • There is no way to dynamically change the language of the application at runtime without closing and recreating windows.

The issues with the Locbaml approach have resulted in the development of a multitude of different solutions for localizing WPF applications. The following are just some of the solutions proposed:

At the risk of adding to the confusion, this article outlines another approach which builds on the strengths of some of these earlier solutions.

Background

The article Simple WPF Localization provides an effective, simple solution for localizing text resources in WPF applications. It uses a WPF Extension to get the string resources from the standard project Properties.Resources RESX file. This article takes a similar approach, and defines a RESX extension that allows WPF properties to be pulled from embedded RESX resources. The solution outlined here differs in the following ways:

  • Resources can be localized using any embedded RESX file. This allows you to take a similar approach to Windows Forms localization and store the resources associated with each WPF window or control in a separate RESX file (typically named the same as the Window). This is important for projects with a large number of windows where it can become difficult to manage the large number of resources in a single file, particularly with multiple developers. It also means that your resource names only have to be unique within the window.
  • Any WPF property (not just strings) can be localized using the RESX Extension. You can use it to localize images, locations, sizes, and other layout properties. The built-in support for images makes defining icons for windows, menus, and toolbars much simpler, and is worth using even if you don't want to localize them.
  • The design time display culture can be selected dynamically using a notification icon in the system tray, allowing you to view and edit the localized windows in the Visual Studio designer. This is great for verifying the localized layout for a window without having to run the application.
  • The RESX extension allows you to define a default fallback value for properties that is used if the associated resource cannot be loaded. This is particularly important when localizing non-text properties where returning a null value may cause the page to fail to load.

Using the RESX Extension

Once you have downloaded the source code and built it, add a reference to the compiled assembly (Infralution.Localization.Wpf) to your project. If you are using the demo solution, then this is already done for you. You are now ready to use the ResxExtension in your own XAML.

Markup extensions allow you to define XAML property values that are evaluated by calling custom code defined by the Markup Extension. See the MSDN article Markup Extensions and XAML for more information. The ResxExtension derives from the base MarkupExtension class, and evaluates the property by retrieving the data from an embedded RESX resource. For instance, the following markup sets the Text property of a TextBlock to the "MyText" resource from the embedded RESX resource called MyApp.TestWindow:

<TextBlock Text="{Resx ResxName=MyApp.TestWindow, Key=MyText}"/>

If you haven't yet created the resource (and compiled your project), then this will be displayed in the WPF designer as #MyText, where the # highlights the fact that the resource has not yet been defined. The next step is to create the RESX file and define the resource. If the default namespace for your project is "MyApp", then you simply create a RESX file called "TestWindow.resx" and set its Build Action to "Embedded Resource". Add a string resource with the name "MyText" and recompile the project. If you now open the TestWindow XAML in the designer, you will see the string from the resource file displayed in the TextBlock.

To add a localization, simply copy the RESX file and rename it. For instance, to create a French localization, copy the RESX file to TestWindow.fr.resx and include it in your project as an embedded resource. Change the "MyText" resource to the French translation. When you recompile your project, Visual Studio will automatically create the French satellite assembly containing the French resources.

Setting the Default ResxName

Setting the ResxName property for each Resx element within a window leads to a lot of duplicated XAML. Patrick Duffy suggested a solution using attached properties which allows much concise XAML. This allows you to set the attached ResxExtension.DefaultResxName property at the top most element as shown below:

<Window ResxExtension.ResxName="WpfApp.MainWindow" Language="{UICulture}>" 

The ResxName property can now be omitted from the Resx elements. Furthermore, if we only need to specify the Key property (which is the default property), then we can omit the parameter name leading to a very concise declaration:

<TextBlock Text="{Resx MyText}"/>

Setting the DefaultResxName using the attached property works provided you are using the Resx element within a normal FrameworkElement property. It will not work however when the Resx element is used within another MarkupExtension. In this case, you will still need to set the ResxName explicitly.

Changing the Design Time Culture

Open TestWindow.xaml in the designer again. You should notice that a new WPF_Resx_Localization/CultureSelector.gif icon appears in your Windows desktop notification tray. This allows you to select the culture used at design time. Click on the icon and select "Other Cultures...". Select one of the French cultures from the dropdown list. The translations displayed in the designer will switch to those from the French RESX file.

Changing the Culture Dynamically at Runtime

The culture of your application can be changed dynamically at runtime simply by setting the CultureManager.UICulture property. This sets the CurrentThread.UICulture and automatically updates all active XAML that uses the ResxExtension.

Images and Icons

The ResxExtension doesn't just work for text. It also makes it easy to use icons and images from RESX files in your XAML markup. For instance, to define the icon for a window, simply add an icon resource to the RESX file named "Window.Icon", then define the markup as follows:

<Window Icon="{Resx Window.Icon}"/>

This is so much easier than the standard way of defining WPF window icons, that you will probably want to use this even if you don't want to localize the icons. You can use the same technique for setting the icons for menus and toolbars.

Localizing Other Property Types

The ResxExtension can be used to localize properties of any type. For instance, the Margin property of a TextBlock could be defined as follows:

<TextBlock 
  Margin="{Resx Key=MyMargin, DefaultValue='18,0,0,71'}"/>

In this case, note that we have defined a DefaultValue attribute. This is the value used if no resource can be found and loaded. If you don't provide a DefaultValue for non-text properties, then the XAML may fail to load in the designer if the resource has not been defined yet. The resource can be defined as a simple string resource (with value "18, 0, 0, 71"), or you can define it as a fully typed value in the RESX file, e.g.:

<data name="MyMargin" type="System.Windows.Thickness, PresentationFramework">
   <value>18, 0, 0, 71</value>
</data>

The latter is somewhat more work - but it does ensure that only valid values can be entered using the resource editor.

Formatting Bound Data

WPF provides the Binding element to bind a property to a data source. The Binding.StringFormat property allows you to supply a string used to format the data for display. For instance:

<Binding StringFormat="Selected Item: {0}" ElementName="_fileListBox" Path="SelectedItem"/>

To localize this, we would like to specify the StringFormat property using a Resx element. This works, provided you don't change the culture at runtime. If you change the culture then you will get an InvalidOperation exception with the message "Binding cannot be changed after it has been used". Unfortunately bindings weren't designed with dynamic updating of culture in mind. To overcome this, the ResxExtension can itself act like a binding. You simply set the binding properties (prefixed with "Binding") and the resource value is used as a format string. For instance, the binding above would become:

<Resx Key="MyFormatString" BindingElementName="_fileListBox" BindingPath="SelectedItem"/>

The ResxExtension also supports formatting data from multiple data sources (similar to a MultiBinding) by nesting Resx elements. For instance:

<Resx Key="MyMultiFormatString">
    <Resx BindingElementName="_fileListBox" BindingPath="Name"/>
    <Resx BindingElementName="_fileListBox" BindingPath="SelectedItem"/>
</Resx> 

In this case, you would define the MyMultiFormatString resource with placeholders for both data source arguments eg "Selected {0}: {1}".

UICulture Extension

The project also defines another markup extension - UICulture. This extension is used to set the Language property of a WPF window (or other elements) to the language matching the current CultureManager.UICulture. Like the RESX Extension, the UICulture extension automatically updates attached elements when the CultureManager.UICulture changes.

ResourceEnumConverter

For convenience, the project includes the ResourceEnumConverter class. This provides an easy mechanism for localizing the display text associated with enums. It is described in more detail in this article.

Hiding Window RESX Files in the Visual Studio Solution Explorer

One nice feature of Windows Forms localization is that the RESX files associated with a form or control are hidden by default. To see the RESX files, you click on the expand button next to the form or control. This means that as you add more languages, your Solution Explorer pane does not become too cluttered. You can also do this for the RESX files associated with a window XAML file by editing the Visual Studio project file and adding a DependentUpon XML node for the RESX file. E.g.:

<EmbeddedResource Include="TestWindow.resx">
  <DependentUpon>TestWindow.xaml</DependentUpon>
  <SubType>Designer</SubType>
</EmbeddedResource>

Implementation Notes

This section provides some notes on the internal implementation of the ResxExtension class. You don't need to read this to use the ResxExtension, but if you are interested in some of the design choices, then read on.

Object Lifetime Management

Object lifetime management is one of the main issues when designing a MarkupExtension that will dynamically update the XAML that uses it. The ResxExtension needs to maintain a reference to the target XAML elements that use it to enable the elements to be updated when the CultureManager.UICulture is changed. If this reference is a strong reference however, then the WPF elements that use the extension will never be garbage collected. To avoid this situation, the extension instead maintains a weak reference to the WPF target objects. This enables the target objects to be garbage collected. The only problem is that there is still a strong reference to the extension objects themselves (since we need to hold a collection of the extension objects in order to update them). This issue is overcome by periodically calling a cleanup function that removes extensions that no longer have active targets. The cleanup is triggered after a set number of extension objects have been created since the last cleanup. This lifetime management mechanism has been implemented in some base classes to enable it to be used for any MarkupExtension that requires this behaviour. The ManagedMarkupExtension provides the base class for the extension, and implements the weak reference to the WPF target objects. The MarkupExtensionManager class manages a collection of ManagedMarkupExtension objects, and implements the update and cleanup mechanism. The ResxExtension and UICultureExtension both derive from ManagedMarkupExtension, and use a static instance of the MarkupExtensionManager class to handle updating WPF targets when the CultureManager.UICulture is changed.

Data Binding Support

Overcoming the immutability of the standard Binding markup extension proved to be quite difficult and I tried quite a few approaches before finally settling on the current design which I think is quite elegant. The solution allows you to set binding properties directly on a Resx element. The ResxExtension just delegates these properties to an underlying Binding instance and sets the Binding.StringFormat to the resource value. When the culture is changed, the ResxExtension creates a new copy of the binding and updates the target to use the new binding.

Expression Blend Support

The ResxExtension will work inside Expression Blend and display the resources from the embedded invariant RESX file (provided that the project has been compiled). Unfortunately, Expression Blend will not load resources from satellite assemblies, and so changing the design time culture using the desktop tray icon has no effect when using Expression Blend.

Globalizer.NET Support

The ResxExtension was designed to support localizing WPF applications using Infralution's Globalizer.NET tool (although you certainly don't need Globalizer.NET to use the ResxExtension). The ResxExtension class includes a static GetResource event that allows Globalizer.NET (or any other localization tool) to hook into the resource translation mechanism and dynamically provide translations for resources. This enables Globalizer.NET to display translated previews of windows and controls that use the ResxExtension without having to first compile the satellite assemblies. Globalizer.NET also includes the ability to scan existing WPF projects for localizable properties and automatically convert them to use the ResxExtension.

History

  • 2009.04.08
    • Initial posting
  • 2009.04.20
    • Fixed bug in ResxExtension.ConvertValue
  • 2009.09.22
    • Fixed ResxExtension.GetDefaultValue to handle non-dependency types and added UpdateTarget methods
  • 2010.01.05
    • Fixed ManagedMarkupExtension.UpdateTarget to handle targets which don’t inherit from FrameworkElement
  • 2010.06.30
    • Fixed issue with using ResxExtension with PRISM
  • 2011.05.30
    • Fixed issue with using ResxExtension in templates
  • 2012.02.06
    • Added ResxExtension.ResxName attached property to allow setting the default ResxName for a window/control
    • Added binding properties to ResxExtension to allow you to format bound data using a resource string
    • Added support for binding to multiple data sources (similar to MultiBinding) by nesting ResxExtension elements
    • Changed ResourceEnumConverter to implement IValueConverter to allow derived classes to be used in XAML as binding converters
    • Added check for dynamic assemblies in HasEmbeddedResx to avoid exceptions being thrown internally
  • 2012.03.02
    • Changed name of attached property from ResxExtension.ResxName to ResxExtension.DefaultResxName. This fixes a runtime markup parsing exception in .NET 4 if you explicitly set the ResxName parameter for an extension (see discussion regarding this bug in comments).
  • 2012.03.22
    • Fixed exception when changing cultures if the the ResxExtension is used in a template
    • Fixed display of culture names at design time when using in .NET 4 projects (previously the culture code was displayed rather than the friendly name)
    • Add overridable GetResourceName method to ResourceEnumConverter class to allow derived classes to change the default resource naming

    2013.02.14

    • Fixed exception when using ResourceEnumConverter inside a multibinding ResxExtension with .NET 4 Framework

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Grant Frisken
Architect Infralution
Australia Australia
Member
I am currently the Software Architect at Infralution. Infralution develops .NET components and solutions including:
 
Globalizer - localization for .NET made easy. Let your translators instantly preview translations and even build the localized version of your application without giving away your source code.
 
Infralution Licensing System - simple, secure and affordable licensing for .NET apps and components
 
Virtual Tree - superfast, flexible, databound tree/list view

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberErrCode9 May '13 - 2:14 
I've been looking for a way to localize WPF like how you used to be able to with Winforms in Visual Studio. This is the closest thing I've found that allows me to use the .resx files from my Winforms dev.
QuestionToolTips?memberjschopf23 Apr '13 - 10:13 
I tried putting a tooltip on the Add button in the example code, but was unsuccessful. Any suggestions?
 
<ToolTipService.ToolTip>
    <!-- Didn't work: <TextBlock Text="{Resx _addButton.ToolTip}"/>-->
    <TextBlock Text="Add file"/>
</ToolTipService.ToolTip>

AnswerRe: ToolTips?memberGrant Frisken8 May '13 - 21:35 
Sorry I haven't replied earlier - but I didn't get an email from Code Project like I normally do for messages posted on the article. If you aren't defining the tooltip as a direct property on a framework element like:
 
<Button Content="{Resx _addButton.Content}" ToolTip="{Resx _addButton.ToolTip}" />
 
Then the DefaultResxName will not work because the TextBlock is actually not parented by the Window so you will have to explicitly set the ResxName property. For instance:
 
<ToolTipService.ToolTip>
    <TextBlock Text="{Resx ResxName=WpfApp.MainWindow, Key=_addButton.ToolTip}"/>
</ToolTipService.ToolTip>
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: ToolTips?memberjschopf9 May '13 - 2:36 
Easy enough. Thanks!
QuestionCurious COMException for Language menu (non-fatal) and also a 4.0 client profile question.memberMember 998491512 Apr '13 - 23:06 
COMException is thrown with your latest download (although if you click Continue twice the app still seems to work ok):
System.Runtime.InteropServices.COMException occurred
  Message=An event was unable to invoke any of the subscribers (Exception from HRESULT: 0x80040201)
  Source=mscorlib
  ErrorCode=-2147220991
  StackTrace:
       at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
       at MS.Internal.Automation.UiaCoreProviderApi.CheckError(Int32 hr)
  InnerException: 
 
Steps to produce:
- Run the WpfApp_CS app
- Open the Language menu (seems ok)
- Leave the menu by clicking elsewhere
- Try to open the Language menu again (used a mouse click in my test)
 
What's it trying to do here that causes the COMException? (any fix required?)
 
Question: After swapping the target to NET Framework 4.0 Client profile for the WpfApp_CS demo, the app seemingly builds, but won't actually start. Any ideas?
 
Note: using VS2010 here, so only performed a project upgrade - nothing else was changed after extraction unless specifically mentioned
AnswerRe: Curious COMException for Language menu (non-fatal) and also a 4.0 client profile question.memberGrant Frisken8 May '13 - 21:09 
Sorry I haven't replied earlier - but I didn't get an email from Code Project like I normally do for messages posted on the article. I've tried replicating your problems using Visual Studio 2010 and 2012 (Express) but have been unable to on Windows 7. Do you still have the problem? What operating system are you using?
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: COMException and .NET 4.0 client profile issues not in latest download. New DataGrid column header question.memberErrCode9 May '13 - 2:06 
Hi Grant,
 
Thanks for responding - even if it's delayed I really wanted to try out this code in my .NET 4 client profile project.
 
I've just download the latest source code and it seems like the issues I noticed with the exception and changing it to .NET 4 client profile aren't an issue anymore. I did notice that my previously downloaded zip file was slightly smaller (356KB) than the latest (371KB). So whatever it was, getting the latest version seems good for me to use now.
 
I do have a new question after playing around with this latest version in my project - Is there a way for localizing a DataGrid's column header? I attempted it with the following, but it doesn't seem to work:
 
<DataGrid ItemsSource="{Binding Path=Inputs}" SelectedItem="{Binding Path=SelectedInput}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="Vertical">
    <DataGrid.Columns>
        <DataGridTextColumn Header="{Resx VarHeader}" Binding="{Binding Path=VarId}" Width="50*" />
        <DataGridTextColumn Header="{Resx ItemHeader}" Binding="{Binding Path=InputItemName}" Width="200*" />

GeneralRe: COMException and .NET 4.0 client profile issues not in latest download. New DataGrid column header question.memberGrant Frisken9 May '13 - 12:37 
This question comes up so often that I probably need to change the article to deal with it explicitly. The DefaultResxName property (set on the window) only works for Framework Elements that belong to the window hierarchy. DataGridTextColumns are not Framework Elements and so you have to set the ResxName property rather than relying on the DefaultResxName eg
 
<DataGridTextColumn Header="{Resx ResxName=WpfApp.MainWindow, Key=VarHeader}" Binding="{Binding Path=VarId}" Width="50*" />
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: COMException and .NET 4.0 client profile issues not in latest download. New DataGrid column header question.memberErrCode9 May '13 - 18:31 
Wonderful. That fixed it. My WPF knowledge still pales in comparison to my WinForms background, so didn't realise that not everything is from the window hierarchy. Learn something new each day.
 
Thanks a lot for the help and also for sharing this very useful library!
GeneralThank Youmemberabdurahman ibn hattab14 Feb '13 - 9:35 
I'm a big user of Infralution Licensing System and just want you to know that it is awesome. Simplicity is the most complex thing at the Earth and it only comes from advanced form of Genius.
GeneralRe: Thank YoumemberGrant Frisken8 May '13 - 21:38 
Thanks. You are right - the hardest thing in software is to come up with a simple elegant solution - but I think simplicity is an extremely important metric because it makes it possible for a human with our limited attention span to understand the solution.
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

QuestionIs it to possible to use an resx enum converter inside multibinding?memberViv Rajkumar12 Feb '13 - 4:44 
I've got
 
<TextBlock.Text>
  <Resx Key="ErrorMessageFormat">
    <Resx BindingPath="ErrorCode" />
    <Resx BindingConverter="{StaticResource ErrorMessagesResxConverter}"
          BindingPath="ErrorMessage" />
  </Resx>
</TextBlock.Text>
 
ErrorMessageFormat has string such as "Error Code {0} : {1}"
 
ErrorMessage is a enum coming from the View Model holding the enum corresponding to error message.
 
This throws an exception "ErrorMessagesResxConverter is Unable to convert Enum to System.Object"
 
However if i have this as
 
<TextBlock.Text>
    <Resx BindingConverter="{StaticResource ErrorMessagesResxConverter}"
          BindingPath="ErrorMessage" />
</TextBlock.Text>
 
It works fine.
 
Is it not possible to apply the custom resx enum converter to a multibinding?
AnswerRe: Is it to possible to use an resx enum converter inside multibinding?memberGrant Frisken12 Feb '13 - 15:04 
This should be possible. I just modified the sample project to use multibinding:
 
<TextBlock.Text>
    <Resx Key="ErrorMessageFormat">
        <Resx BindingElementName="_fileListBox" BindingPath="Name" />
        <Resx BindingElementName="_fileListBox" BindingPath="SelectedItem" BindingConverter="{StaticResource sampleEnumConverter}" />
    </Resx>
</TextBlock.Text>
 
Where ErrorMessageFormat is defined as you have. This worked exactly as expected. If you can replicate the issue in a small project then I'd be happy to have a look.
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: Is it to possible to use an resx enum converter inside multibinding?memberViv Rajkumar13 Feb '13 - 1:17 
Hey I've got s simple project showing this error. Not sure how to upload it here tho. Is there an email id I can send it to or something?
GeneralRe: Is it to possible to use an resx enum converter inside multibinding?memberGrant Frisken13 Feb '13 - 1:43 
You can email a zipped copy of it to me at grant@infralution.com
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: Is it to possible to use an resx enum converter inside multibinding?memberGrant Frisken13 Feb '13 - 12:43 
Thanks for the sample code. The problem appears to be a change in the behaviour of the ConvertTo method in the system base EnumConverter class between .NET 3.5 and .NET 4. Multibindings which contain the ResourceEnumConverter work in .NET 3.5 and not in .NET 4. The fix is to change the ResourceEnumConverter.ConvertTo method to the following:
 
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
    if (culture == null)
        culture = CultureInfo.CurrentCulture;
 
    if (value == null) return null;
    if (destinationType == typeof(string) || destinationType == typeof(object))
    {
        object result = (_isFlagEnum) ?
            GetFlagValueText(culture, value) : GetValueText(culture, value);
        return result;
    }
    else
    {
        return base.ConvertTo(context, culture, value, destinationType);
    }
}
 
I will try to get an fixed version of the code uploaded to Code Project as soon as possible. Are you using the Code Project source code or the precompiled Infralution.Localization.Wpf assembly that comes with Infralution Globalizer?
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: Is it to possible to use an resx enum converter inside multibinding?memberViv Rajkumar13 Feb '13 - 23:39 
Thank you very much for fixing this.
 
I do use the code project source code to build the dll's. I was able to make the change, build and test to see it works fine now Smile | :)
 
Think we will eventually be getting a license for Globalizer since this localisation helper seems to be great for our requirements.
 
Thanks again for this tool Smile | :)
QuestionRelicensingmemberMatt Hamilton8 Feb '13 - 20:24 
Hi, I would like to use this for localization in my own project, but it appears that the Code Project Open License isn't compatible with the Apache license that I am using. What are your opinions on relicensing this code?
AnswerRe: RelicensingmemberGrant Frisken8 Feb '13 - 20:46 
I don't think Code Project open license (CPOL) should be a barrier to using this inside a project where other parts of the code are governed by the Apache license (unless the Apache license prevents your using code licensed under different conditions in conjunction with it). The CPOL basically lets you do whatever you want with the code EXCEPT that you can't claim the work as your own and change its licensing conditions.
 
If you distribute your code under the conditions of the Apache license then as long as you retain the copyright notices in the code and in your own license note that the Resx Extension code is covered by the CPOL (with a link) then I think you are OK by the CPOL and certainly by me.
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

QuestionEncapsulate into DLL?memberClaire Streb7 Feb '13 - 14:44 
This article and code has helped us a lot, but I'm wondering why it isn't in a DLL? I've been trying to make it work in a separate DLL, because I hate duplicating code, but it's challenging. If we have multiple applications that need to share the same default resource files and localization functionality, doesn't it make sense to put it in a DLL?
Claire Streb
http://clairenstreb.brinkster.net

AnswerRe: Encapsulate into DLL?memberGrant Frisken8 Feb '13 - 12:55 
I'm not really sure what you mean. The Resx Extension is already in a separate DLL (Infralution.Localization.WPF). If you want to use one DLL to hold shared localized resources for an application then this is possible however I don't think it is best practice. I believe it is better to define localized resources for each assembly independently. While this may mean that some resources are repeated (if the same text is used by two assemblies) the amount of space you will probably save will be neglible and putting all resources in a shared DLL introduces unnecessary coupling. A good localization tool is able to automatically translated duplicate text that appears in different assemblies so there is no extra translator work in not sharing resources.
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

GeneralRe: Encapsulate into DLL?memberClaire Streb12 Feb '13 - 6:23 
I see your point, but I think "best practice" for sharing resource files depends on the situation. Multiple projects might want to share resources, as here: http://stackoverflow.com/questions/3995315/how-to-use-shared-resource-file-between-projects-in-one-solution?rq=1[^] But, thanks for your reply and I'll take it to heart.
Claire Streb
http://clairenstreb.brinkster.net

QuestionProblem switching Value binding at run-timememberViv Rajkumar2 Feb '13 - 23:25 
Hey,
 
Am having an issue where I'm using a single textblock to display 1 out of 3 resx localised strings.
 
Am setting the resx string to the TextBlock.Text using a DataTrigger
 
<TextBlock.Style>
  <Style>
    <Style.Triggers>
      <DataTrigger Binding="{Binding ElementName=someOtherTextBox1,
                                           Path=CustomDP}"
                              Value="True">
        <Setter Property="TextBlock.Text"
                Value="{Resx Message1}" />
      </DataTrigger>
      <DataTrigger Binding="{Binding ElementName=someOtherTextBox2,
                                           Path=CustomDP}"
                              Value="True">
        <Setter Property="TextBlock.Text"
                Value="{Resx Message2}" />
      </DataTrigger>
      <DataTrigger Binding="{Binding ElementName=someOtherTextBox3,
                                           Path=CustomDP}"
                              Value="True">
        <Setter Property="TextBlock.Text"
                Value="{Resx Message3}" />
      </DataTrigger>
    </Style.Triggers>
  </Style>
</TextBlock.Style>

This causes an exception when the UI culture is changed at runtime.
 
Also see this warning - 'ResxExtension' is not valid for Setter.Value. The only supported MarkupExtension Types are DynamicResourceExtension and BindingBase or derived types.
 
Am sure I'm implementing something wrong than something wrong with the plugin. Just not sure how to work around this.
 
Any help would be great.
 
Thanks
AnswerRe: Problem switching Value binding at run-timememberViv Rajkumar3 Feb '13 - 1:04 
Got a workaround for my issue using the enum method given in the example. However this makes me hold another enum variable in the ViewModel indicating the string to be shown rather than let the view handle it via the datatrigger mentioned previously.
AnswerRe: Problem switching Value binding at run-timememberGrant Frisken8 Feb '13 - 12:56 
The way Style Setter properties are designed means that it is not possible to use Resx Extension with them and support dymanic language changing.
 
See this thread [^] for more information:
Infralution - we provide .NET solutions:
 
Globalizer - .NET Localization made easy
Infralution Licensing System - simple, secure and affordable licensing
Virtual Tree - superfast, flexible, databound tree/list view

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 13 Feb 2013
Article Copyright 2009 by Grant Frisken
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid