views:

1929

answers:

5

What is the best way to localize enumeration descriptions in .net?

(See Adding descriptions to enumeration constants for enum description example)

Ideally I would like something that uses ResourceManager and resource files so it fits in with how other areas of the app are localized.

+3  A: 

Hi, there is an easy solution: use LocalizedDescription attribute to pass a resource key.

    [Serializable]
    public class LocalizableDescriptionAttribute:DescriptionAttribute
    {
        public LocalizableDescriptionAttribute(string resourceKey)
            :base(Resources.ResourceManager.GetString(resourceKey))
        { }

    }
Valentin Vasiliev
I am not sure what this gets you over using the enums full type name (namespace.enumname.value) as the resourceKey. It seems like an extra unnecessary step (using reflection to get the LocalizableDescriptionAttribute) over just going to the resourceManager - what am I missing?
Ryan
I think we have a misunderstanding. I use my attribute to localize enum values description. I guess you're talking about localizing enums but not their values.
Valentin Vasiliev
You can't decorate enum value with Description attribute and pass a resource key.
Valentin Vasiliev
Nope - I want to leave the enum values the same, just localize a description. My own answer below may make my comment clearer. (BTW - ignore where I said reflection, I should have said LocalizableDescriptionAttribute.GetCustomAttribute)
Ryan
A: 

See my table example in this question:

http://stackoverflow.com/questions/537204/localisation-i18n-of-database-data-in-linq-to-sql

The status type table maps to Enumeration values. The real benefit here is that you can have localisation in your reports and across your applications, and specify external IDs for integration with 3rd parties who don't want your internal values etc. It decouples the enum description from it's value.

Neil Barnwell
Nice method for db centric apps, but really overkill for my needs.
Ryan
A: 

You can't have multiple System.ComponentModel.DescriptionAttribute applied (so that option is out).

So add a level of indirection, the description holds a resource name, and then use the localisation support in resources. Clearly users of the enum will need to call your helper method to do this.

Richard
This is what Valentin Vasiliev proposes but without the need to use a helper method - the same comment applies too.
Ryan
+2  A: 

One way I did it once, was to add an extention method in the same namespace as an enum, which returned a string. In my case it was just hardcoded, but would be no problem getting them from a resource file.

    public static string Describe(this SomeEnum e)
    {
        switch(e)
        {
            SomeEnum.A:
                return "Some text from resourcefile";
            SomeEnum.B:
                return "Some other text from resourcefile";
            ...:
                return ...;
        }
    }

Maybe not an extremly smooth or fancy solution, but it works =)

Svish
+ 1 for using an extension method...though I would prefer to use the enum's fully qualified type name as the resource key (see Ryans answer)
SDX2000
@SDX2000: Yeah, that could be a very nice alternative way of getting the strings.
Svish
+9  A: 

This is what I ended up going with, I didn't see the value in adding a custom attribute class to hold a resource key and then looking up into the resource files - why not just use the enums typename + value as a resource key?

using System;
using System.Resources;
using System.Reflection;

public class MyClass
{
  enum SomeEnum {Small,Large};

  private ResourceManager _resources = new ResourceManager("MyClass.myResources",
                          System.Reflection.Assembly.GetExecutingAssembly());    

  public string EnumDescription(Enum enumerator)
  {  
    string rk = String.Format("{0}.{1}",enumerator.GetType(),enumerator);
    string localizedDescription = _resources.GetString(rk);

    if (localizedDescription == null)
       {
       // A localized string was not found so you can either just return
       // the enums value - most likely readable and a good fallback.
       return enumerator.ToString();

       // Or you can return the full resourceKey which will be helpful when
       // editing the resource files(e.g. MyClass+SomeEnum.Small) 
       // return resourceKey;
       }
    else
       return localizedDescription;
    }


  void SomeRoutine()
  {
    // Looks in resource file for a string matching the key
    // "MyClass+SomeEnum.Large"
    string s1 = EnumDescription(SomeEnum.Large);       
  }
}
Ryan
Excellent work! Had the same problem and your solution helped me a lot! Thanks a million!
Nikos Steiakakis
an Enum is not an enumerator, is it? It's an enumerated type, but an enumerator is something quite different I believe...
Svish
Using C# 3.5 you can make that method an extension method so that you can then use SomeEnum.Large.EnumDescription();
KeeperOfTheSoul
Just stumbled upon this question when searching for another issue.I'd only remind that using type and member names makes your application more difficult to obfuscate (you must exclude the sensible declaration from the process).
Erik Burigo