views:

85

answers:

2

I've seen many questions and answers about mapping strings to enums and vice-versa, but how can I map a series of localized strings to enums?

Should I just create an extension method like this that returns the proper string from a resource file? Is there a way to localize attributes (like "Description") that are used in solutions like this?

Which is the preferred solution - extension method or attributes. It seems to me that this isn't the intended purpose of attributes. In fact, now that I think about it, if I were to use an extension method an attribute seems like something I'd use to specify a key in a resource file for the localized string I want to use in place of the enum value.

EDIT - example:

Given the following enum,

public enum TransactionTypes {
    Cheque = 1,
    BankTransfer = 2,
    CreditCard = 3
}

I would like a way to map each type to a localized string. I started off with an extension method for the enum that uses a switch statement and strongly typed references to the resource file.

However, an extension method for every enum doesn't seem like a great solution. I've started following this to create a custom attribute for each enumerated value. The attribute has a base name and key for the resource file containing localized strings. In the above enum, for example, I have this:

...
[EnumResourceAttribute("FinancialTransaction", "Cheque")]
Cheque = 1,
...

Where "FinanacialTransaction" is the resx file and "Cheque" is the string key. I'm trying to create a utility method to which I could pass any value from any enumeration and have it return the localized string representation of that value, assuming the custom attribute is specified. I just can't figure out how to dynamically access a resource file and a key within it.

+6  A: 

I would definitely suggest using a resource file, probably with a method (extension or otherwise) to make it simple to get hold of the relevant resource. As the number of languages you support grows, you don't really want the code to be full of text, distracting you from the values themselves.

Likewise translation companies are likely to be geared up to handle resx files - they're not going to want to mess around in your source code, and you shouldn't let them do so anyway :)

Just use resources which are keyed on the name of the enum and the value within it. Straightforward, scales to multiple enums and multiple languages, doesn't clutter up your source code, works well with translation tools, and is basically going along with the flow of i18n within .NET.

EDIT: For mapping the enum values to the resource names, I'd just do something like:

public static string ToResourceName<T>(this T value) where T : struct
{
    return typeof(T).Name + "." + value;
}

Then you could do:

string resource = MyEnum.SomeValue.ToResourceName();

Obviously that's performing string concatenation every time - you could cache that if you wanted to, but I wouldn't bother unless you had some indication that it was actually a problem.

That doesn't stop you using the extension method for non-enums, of course. If you want to do that, you need something like Unconstrained Melody.

Jon Skeet
+1 I was 1 min too late :)
Shiraz Bhaiji
I should have been more clear - I wasn't going to use anything other than resource files (we're already using them for everything else that needs i18n). I'm looking for solutions to mapping the resource strings to the enumeration.
Duke
@Duke: Okay, it's not terribly clear what you want then - I've updated my answer with a very simple extension method, but I suspect you're after something more than that...
Jon Skeet
I've made a big edit with example, and what I've come up with so far.
Duke
A: 

I continued with the custom attributes and created this utility method:

    public static string getEnumResourceString(Enum value)
    {
        System.Reflection.FieldInfo fi = value.GetType().GetField(value.ToString());
        EnumResourceAttribute attr = (EnumResourceAttribute)System.Attribute.GetCustomAttribute(fi, typeof(EnumResourceAttribute));
        return (string)HttpContext.GetGlobalResourceObject(attr.BaseName, attr.Key);
    }
Duke