Локализация атрибутов описаний перечислений - PullRequest
36 голосов
/ 20 февраля 2009

Каков наилучший способ локализации описаний перечисления в .net?

(см. Добавление описаний в константы перечисления для примера описания перечисления)

В идеале я хотел бы, чтобы что-то использовало ResourceManager и файлы ресурсов, чтобы оно соответствовало локализации других областей приложения.

Ответы [ 8 ]

25 голосов
/ 21 февраля 2009

Это то, чем я закончил, я не видел смысла в добавлении пользовательского класса атрибута для хранения ключа ресурса, а затем просматривал файлы ресурсов - почему бы просто не использовать перечисление typename + value в качестве ресурсный ключ?

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);       
  }
}
23 голосов
/ 24 февраля 2011

Мое решение, используя собственный атрибут расшифровки:

public class LocalizedEnumAttribute : DescriptionAttribute
{
    private PropertyInfo _nameProperty;
    private Type _resourceType;

    public LocalizedEnumAttribute(string displayNameKey)
        : base(displayNameKey)
    {

    }

    public Type NameResourceType
    {
        get
        {
            return _resourceType;
        }
        set
        {
            _resourceType = value;

            _nameProperty = _resourceType.GetProperty(this.Description, BindingFlags.Static | BindingFlags.Public);
        }
    }

    public override string Description
    {
        get
        {
            //check if nameProperty is null and return original display name value
            if (_nameProperty == null)
            {
                return base.Description;
            }

            return (string)_nameProperty.GetValue(_nameProperty.DeclaringType, null);
        }
    }
}

public static class EnumExtender
{
    public static string GetLocalizedDescription(this Enum @enum)
    {
        if (@enum == null)
            return null;

        string description = @enum.ToString();

        FieldInfo fieldInfo = @enum.GetType().GetField(description);
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes.Any())
            return attributes[0].Description;

        return description;
    }
}

Декларация Enum

public enum MyEnum
{
    [LocalizedEnum("ResourceName", NameResourceType = typeof(ResourceType))]
    Test = 0
}

Затем позвоните MyEnumInstance.GetLocalizedDescription()

8 голосов
/ 20 февраля 2009

есть простое решение: используйте атрибут LocalizedDescription для передачи ключа ресурса.

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

    }
3 голосов
/ 20 февраля 2009

Один из способов сделать это один раз - добавить метод расширения в том же пространстве имен, что и enum, который возвращает строку. В моем случае это было просто жестко закодировано, но было бы без проблем получить их из файла ресурсов.

    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 ...;
        }
    }

Возможно, не очень гладкое или причудливое решение, но оно работает =)

1 голос
/ 12 ноября 2012

Замените метод @ nairik следующим, чтобы добавить поддержку перечислений флагов.

public static string GetLocalizedDescription(this Enum @enum)
{
    if ( @enum == null )
        return null;

    StringBuilder sbRet = new StringBuilder();

    string description = @enum.ToString();

    var fields = description.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);

    foreach ( var field in fields )
    {
        FieldInfo fieldInfo = @enum.GetType().GetField(field);
        DescriptionAttribute[] attributes = ( DescriptionAttribute[] )fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if ( attributes.Any() )
            sbRet.AppendFormat("{0}, ", attributes[0].Description);
        else
            sbRet.AppendFormat("{0}, ", field);
    }

    if ( sbRet.Length > 2 )
        sbRet.Remove(sbRet.Length - 2, 2);

    return sbRet.ToString();
}

и замените NameResourceType в атрибуте:

public Type NameResourceType
{
    get
    {
        return _resourceType;
    }
    set
    {
        _resourceType = value;

        _nameProperty = _resourceType.GetProperty(base.Description, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
    }
}
0 голосов
/ 31 января 2012
0 голосов
/ 20 февраля 2009

Нельзя использовать несколько System.ComponentModel.DescriptionAttribute (так что этот параметр отсутствует).

Итак, добавьте уровень косвенности, описание содержит имя ресурса, а затем используйте поддержку локализации в ресурсах. Очевидно, что для этого пользователям enum потребуется вызвать ваш вспомогательный метод.

0 голосов
/ 20 февраля 2009

См. Мой пример таблицы в этом вопросе:

Локализация / I18n данных базы данных в LINQ to SQL

Таблица типов состояний соответствует значениям перечисления. Реальным преимуществом здесь является то, что вы можете иметь локализацию в своих отчетах и ​​во всех приложениях, а также указывать внешние идентификаторы для интеграции со сторонними организациями, которым не нужны ваши внутренние значения и т. Д. Он отделяет описание enum от его значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...