C# 本地化枚举描述属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/569298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 08:35:59  来源:igfitidea点击:

Localizing enum descriptions attributes

c#.netlocalizationenums

提问by Ryan

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

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

(See Adding descriptions to enumeration constantsfor 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.

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

采纳答案by Ryan

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

回答by Valentin Vasilyev

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

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

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

    }

回答by Neil Barnwell

See my table example in this question:

在这个问题中查看我的表格示例:

Localisation/I18n of database data in LINQ to SQL

LINQ to SQL 中数据库数据的本地化/I18n

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.

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

回答by Richard

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

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

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.

所以加一层间接,description 持有一个资源名称,然后在资源中使用本地化支持。显然,枚举的用户需要调用您的辅助方法来执行此操作。

回答by Svish

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

也许不是一个非常流畅或奇特的解决方案,但它有效 =)

回答by nairik

My solution, using native decription attribute:

我的解决方案,使用本机描述属性:

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

The Enum declaration

枚举声明

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

Then call MyEnumInstance.GetLocalizedDescription()

然后打电话 MyEnumInstance.GetLocalizedDescription()

回答by kerem

Replace @nairik's method with the following to add support for flags enums.

将@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();
}

and replace NameResourceType in the attribute:

并替换属性中的 NameResourceType:

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

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