本地化枚举描述属性

发布于 2024-07-13 21:09:52 字数 229 浏览 7 评论 0原文

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

(有关枚举描述示例,请参阅向枚举常量添加描述

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

虫児飞 2024-07-20 21:09:52

这就是我最终的结果,我没有看到添加自定义属性类来保存资源键然后查找资源文件的价值 - 为什么不只使用枚举类型名+值作为资源键?

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

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);       
  }
}
手心的海 2024-07-20 21:09:52

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

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

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

甜中书 2024-07-20 21:09:52

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

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

    }

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

    }
感情旳空白 2024-07-20 21:09:52

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

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

也许不是一个极其顺利或奇特的解决方案,但它有效 =)

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

小忆控 2024-07-20 21:09:52

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

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

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:

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

        _nameProperty = _resourceType.GetProperty(base.Description, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
    }
}
随波逐流 2024-07-20 21:09:52

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

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

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

See my table example in this question:

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.

〃安静 2024-07-20 21:09:52

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

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

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.

我要还你自由 2024-07-20 21:09:52

我的解决方案受到nairik的答案的启发,是使用现有的DisplayAttribute

using System.ComponentModel.DataAnnotations;
using System.Reflection;

public static string GetLocalizedDescription(this Enum enumValue)
{
    string description = enumValue.ToString();

    FieldInfo fieldInfo = enumValue.GetType().GetField(description)!;
    return fieldInfo.GetCustomAttribute<DisplayAttribute>(false)?.GetName() ?? description;
}

属性用法:

using System.ComponentModel.DataAnnotations;

public enum MyEnum
{
    [Display(ResourceType = typeof(MyResources), Name = nameof(MyResources.FirstValueDescription))]
    FirstValue = 0,
}

My solution, inspired by nairik's answer, is to use the already existing DisplayAttribute:

using System.ComponentModel.DataAnnotations;
using System.Reflection;

public static string GetLocalizedDescription(this Enum enumValue)
{
    string description = enumValue.ToString();

    FieldInfo fieldInfo = enumValue.GetType().GetField(description)!;
    return fieldInfo.GetCustomAttribute<DisplayAttribute>(false)?.GetName() ?? description;
}

Attribute usage:

using System.ComponentModel.DataAnnotations;

public enum MyEnum
{
    [Display(ResourceType = typeof(MyResources), Name = nameof(MyResources.FirstValueDescription))]
    FirstValue = 0,
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文