Hannish
Hannish

Reputation: 1532

Localization in MEF: export attribute does not support a resource (WPF - C#)

I have an application with a plugin architecture using MEF. For every exported part there is an attribute with the part's name, and I want to have the names translated, because I use these strings to display the available parts in ListBoxes (or the like).

So, I tried to set the 'Name = Strings.SomeText" in the [Export] annotation, but I get the following error:

"An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type"

Is there a solution to this? I find the use of the Metadata very useful (I do lazy loading) and I would not want to redesign everything just to get a few texts translated.

Any ideas? Thanks.

Upvotes: 1

Views: 1057

Answers (1)

Petrik
Petrik

Reputation: 1981

Unfortunately you can't directly provide the translated text to the attributes because an attribute can only contain data that is known at compile time. So you will need to provide some compile time constant value that you can later use to look up the translated test.

One solution would be to pass the resource name to the attribute. Then when you want to display the translated text you grab the resource name, look up the text in the resources and display the result.

For instance your attribute could look something like:

[Export(Name = "SomeText")]
public class MyExport
{
}

Then when you want to display the string you load the resources from the assembly that defines the export and you extract the actual text from the loaded resources. For instance like this (as borrowed from another answer):

var assembly = typeof(MyExport).Assembly;

// Resource file.. namespace.ClassName
var rm = new ResourceManager("MyAssembly.Strings", assembly);

// exportName contains the text provided to the Name property 
// of the Export attribute
var text = rm.GetString(exportName);

The one obvious drawback about this solution is that you lose the type-safety that you get from using the Strings.SomeText property.

--------- EDIT ---------

In order to make it a little easier to get the translated text you could create a derivative of the ExportAttribute which takes enough information to extract the translated text. For example the custom ExportAttribute could look like this

public sealed class NamedExportAttribute : ExportAttribute
{
    public NamedExportAttribute()
        : base()
    { 
    }

    public string ResourceName
    {
        get;
        set;
    }

    public Type ResourceType
    {
        get;
        set;
    }

    public string ResourceText()
    {
        var rm = new ResourceManager(ResourceType);
        return rm.GetString(ResourceName);
    }
}

Using this attribute you can apply it like this

[NamedExport(
    ResourceName = "SomeText", 
    ResourceType = typeof(MyNamespace.Properties.Resources))]
public sealed class MyClass
{ 
}

Finally when you need to get the translated text you can do this

var attribute = typeof(MyClass).GetCustomAttribute<NamedExportAttribute>();
var text = attribute.ResourceText();

Another option is to use the DisplayAttribute

Upvotes: 3

Related Questions