Search code examples
c#visual-studio-2008localizationattributes

Localization of DisplayNameAttribute


I am looking for a way to localize properties names displayed in a PropertyGrid. The property's name may be "overriden" using the DisplayNameAttribute attribute. Unfortunately attributes can not have non constant expressions. So I can not use strongly typed resources such as:

class Foo
{
   [DisplayAttribute(Resources.MyPropertyNameLocalized)]  // do not compile
   string MyProperty {get; set;}
}

I had a look around and found some suggestion to inherit from DisplayNameAttribute to be able to use resource. I would end up up with code like:

class Foo
{
   [MyLocalizedDisplayAttribute("MyPropertyNameLocalized")] // not strongly typed
   string MyProperty {get; set;}
}

However I lose strongly typed resource benefits which is definitely not a good thing. Then I came across DisplayNameResourceAttribute which may be what I'm looking for. But it's supposed to be in Microsoft.VisualStudio.Modeling.Design namespace and I can't find what reference I am supposed to add for this namespace.

Anybody know if there's a easier way to achieve DisplayName localization in a good way ? or if there is as way to use what Microsoft seems to be using for Visual Studio ?


Solution

  • Here is the solution I ended up with in a separate assembly (called "Common" in my case):

       [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
       public class DisplayNameLocalizedAttribute : DisplayNameAttribute
       {
          public DisplayNameLocalizedAttribute(Type resourceManagerProvider, string resourceKey)
             : base(Utils.LookupResource(resourceManagerProvider, resourceKey))
          {
          }
       }
    

    with the code to look up the resource:

      internal static string LookupResource(Type resourceManagerProvider, string resourceKey)
      {
         foreach (PropertyInfo staticProperty in  resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic))
         {
            if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
            {
               System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
               return resourceManager.GetString(resourceKey);
            }
         }
    
         return resourceKey; // Fallback with the key name
      }
    

    Typical usage would be:

    class Foo
    {
          [Common.DisplayNameLocalized(typeof(Resources.Resource), "CreationDateDisplayName"),
          Common.DescriptionLocalized(typeof(Resources.Resource), "CreationDateDescription")]
          public DateTime CreationDate
          {
             get;
             set;
          }
    }
    

    What is pretty much ugly as I use literal strings for resource key. Using a constant there would mean to modify Resources.Designer.cs which is probably not a good idea.

    Conclusion: I am not happy with that, but I am even less happy about Microsoft who can't provide anything useful for such a common task.