本地化枚举描述属性

时间:2009-02-20 11:48:50

标签: c# .net localization enums

在.net中本地化枚举描述的最佳方法是什么?

(有关枚举说明示例,请参阅Adding descriptions to enumeration constants

理想情况下,我想要使用ResourceManager和资源文件的东西,以便它适合应用程序的其他区域的本地化。

8 个答案:

答案 0 :(得分:25)

这就是我最终的目的,我没有看到添加自定义属性类来保存资源键然后查找资源文件的价值 - 为什么不直接使用enums 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);       
  }
}

答案 1 :(得分:23)

我的解决方案,使用原生描述属性:

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()

答案 2 :(得分:8)

有一个简单的解决方案: 使用LocalizedDescription属性传递资源键。

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

    }

答案 3 :(得分:3)

我做过一次的一种方法是在与枚举相同的命名空间中添加一个扩展方法,它返回一个字符串。在我的情况下,它只是硬编码,但从资源文件中获取它们没有问题。

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

也许不是一个极端平滑或奇特的解决方案,但它的工作原理=)

答案 4 :(得分:1)

使用以下内容替换@ 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);
    }
}

答案 5 :(得分:0)

请参阅此问题中的表格示例:

Localisation/I18n of database data in LINQ to SQL

状态类型表映射到枚举值。这里的真正好处是,您可以在报表和应用程序中进行本地化,并指定外部ID以与不希望您的内部值等的第三方集成。它将枚举描述与其值进行分离。

答案 6 :(得分:0)

您不能应用多个System.ComponentModel.DescriptionAttribute(因此该选项已用完)。

因此,添加一个间接级别,描述包含资源名称,然后在资源中使用本地化支持。很明显,枚举的用户需要调用你的帮助方法来执行此操作。

答案 7 :(得分:0)