【问题标题】:how to localize a property description in c#?如何在 C# 中本地化属性描述?
【发布时间】:2011-11-15 22:52:18
【问题描述】:

我正在编写一门课程,该课程将被其他国家的一些人使用。我必须本地化每条消息,警告 e.c.以便他们能够理解我们的意思。在许多情况下,我实现了我的目标。但是这些像描述这样的属性属性实在是太让人头疼了。

这是我现在拥有的:

[Category("Editable Values"), Description("Sets the minimum select...")]
    public Ampere Simin
    {
        get
        {...}
        set
        {...}
    }

[Category("Editable Values"), Description(Localisation.Simin)] // "Localisation" here is the internal resource file that i wrote for messages, warnings, exceptions and -unfortunately- descriptions
        public Ampere Simin
        {
            get
            {...}
            set
            {...}
        }

这就是我想要做的。但是以这种方式使用本地化是不可能的。对我可以使用的东西有什么建议吗?

【问题讨论】:

    标签: c# localization properties


    【解决方案1】:

    子类:

    [STAThread]
    static void Main()
    {   // just some example code to show it working in winforms, but
        // anything using System.ComponentModel should see the change
        Application.EnableVisualStyles();        
        Application.Run(new Form {Controls = {new PropertyGrid {Dock = DockStyle.Fill, SelectedObject = new Foo()}}});
    }
    
    class Foo
    {   // assume the following literals are keys, for example to a RESX
        [LocalizedCategory("cat")]
        [LocalizedDescription("desc")]
        [LocalizedDisplayName("disp name")]
        public string Bar { get; set; }
    }
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter)]
    class LocalizedDescriptionAttribute : DescriptionAttribute
    {
        static string Localize(string key)
        {
            // TODO: lookup from resx, perhaps with cache etc
            return "Something for " + key;
        }
        public LocalizedDescriptionAttribute(string key)
            : base(Localize(key))
        {
        }
    }
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)]
    class LocalizedDisplayNameAttribute : DisplayNameAttribute
    {
        static string Localize(string key)
        {
            // TODO: lookup from resx, perhaps with cache etc
            return "Something for " + key;
        }
        public LocalizedDisplayNameAttribute(string key)
            : base(Localize(key))
        {
        }
    }
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter)]
    class LocalizedCategoryAttribute : CategoryAttribute
    {
        public LocalizedCategoryAttribute(string key) : base(key) { }
        protected override string  GetLocalizedString(string value)
        {
                // TODO: lookup from resx, perhaps with cache etc
            return "Something for " + value;
        }
    }
    

    【讨论】:

    • 我必须承认我无法真正理解。那就是“desc”是本地化属性的键吗?如何访问指定属性的属性?你能把你的例子改编成我的吗?
    • @3yanlis1bos 在示例中我只使用字符串作为键 - 您必须手动从 RESX 中提取(请参阅 RESX 后面生成的文件),或使用反射
    • 好的,我想我明白了。您已经扩展了 description 属性并进行了修改以满足我的需要,例如将本地化字符串作为输入。那正确吗?那么我唯一要做的就是使用新属性而不是旧属性?
    • 提示:如果你有LocalizedDescriptionAttribute 扩展DescriptionAttribute,你应该小心同时给任何两个属性,因为尝试访问Description 可能会产生LocalizedDescription。 :::曾经浪费了 15 分钟才发现这个明显的事后诸葛亮的问题:::
    【解决方案2】:

    我结合了Marc Gravelldsmith 的答案:

    首先:创建一个名为 LocalizedDescriptionAttribute 的 Attribute 类

    public class LocalizedDescriptionAttribute : DescriptionAttribute
    {
        static string Localize(string key)
        {
            return YourResourceClassName.ResourceManager.GetString(key);
        }
    
        public LocalizedDescriptionAttribute(string key)
            : base(Localize(key))
        {
        }
    }
    

    将其用作LocalizedDescription(“属性”一词不是必需的)

    public class Foo
    {   
        // myString is a key that exists in your Resources file
        [LocalizedDescription("myString")]
        public string Bar { get; set; }
    }
    

    【讨论】:

      【解决方案3】:
      [Required(ErrorMessageResourceName = "LogOnModel_UserName_Required",     
            ErrorMessageResourceType = typeof(Resources.Global))]    
      [Display(Name = "LogOnModel_UserName_Required",resourceType = typeof(Resources.Global))]  
      public string UserName { get; set; }
      

      见:http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx

      【讨论】:

      • 由于 OP 使用的是CategoryAttribute/DescriptionAttribute,他们可能在说 regular System.ComponentModel,而不是 MVC - 在这种情况下,这根本不适用。
      • 啊,不知道。我主要开发 MVC,并认为属性将是通用的(不过会是一个很棒的功能)。
      • @Patrick 我也不明白 :)。有点 C# 的新手。但还是感谢您的尝试。是您访问本地化资源字符串的“Resources.Global”吗?如果是,我如何在描述属性中写类似的东西?
      【解决方案4】:

      让我们以这个示例类为例:

      // ------------------------------------------------------------------------
      public class Customer
      {
          // ----------------------------------------------------------------------
          [Category( "Editable Values" ), LocDescription( "FirstName", "Sets the first name..." )]
          public string FirstName { get; set; }
      
          // ----------------------------------------------------------------------
          [Category( "Editable Values" ), LocDescription(  Key = "LastName", DefaultDescription = "Sets the last name..." )]
          public string LastName { get; set; }
      } // class Customer
      

      现在可以实现自定义属性类了:

      // ------------------------------------------------------------------------
      public class LocDescriptionAttribute : DescriptionAttribute
      {
          // ----------------------------------------------------------------------
          public LocDescriptionAttribute()
          {
          } // LocDescriptionAttribute
      
          // ----------------------------------------------------------------------
          public LocDescriptionAttribute( string key, string defaultDescription ) :
              base( defaultDescription )
          {
              Key = key;
              DefaultDescription = defaultDescription;
          } // LocDescriptionAttribute
      
          // ----------------------------------------------------------------------
          public string Key { get; set; }
      
          // ----------------------------------------------------------------------
          public string DefaultDescription { get; set; }
      
          // ----------------------------------------------------------------------
          public override string Description
          {
              get
              {
                  // load from resx
                  string description = Strings.GetString( Key );
                  if ( string.IsNullOrEmpty( description ) )
                  {
                      description = DefaultDescription;
                  }
                  return description;
              }
          } // Description
      } // class LocDescriptionAttribute
      

      现在您有了本地化描述:

      AttributeCollection attributes = TypeDescriptor.GetProperties( customer )[ "FirstName" ].Attributes;
      DescriptionAttribute myAttribute = (DescriptionAttribute)attributes[ typeof( DescriptionAttribute ) ];
      ConsoleWiterLine( myAttribute.Description );
      

      【讨论】:

      • 我已经有一个资源文件。我也将它们用于我的警告和消息。但问题是,你可以t pass a localized resource to a description attribute (not possible) . thats 我的意思。
      • 我看起来和马克一样。但它s easier to understand for me. I think ill 试试这个。
      【解决方案5】:

      对 Jani 的回答稍作扩展(对我来说效果很好):

      string description = Strings.GetString( Key );
      

      可以更清楚地做到

      ResourceManager rm = YourResourceClassName.ResourceManager;
      string description = rm.GetString(Key);
      

      含糊其辞,但不清楚原始代码中缺少什么。资源类的.ResourceManager 属性是自动生成的。

      然后,要访问它,请使用 Glennular 在此处描述的扩展方法:StackOverflow 而不是在字段/类名称中进行硬编码(只需使用 LocDescriptionAttribute 而不是 DescriptionAttribute)。

      我所做的唯一其他调整是基于this IComparable enum 使其成为静态,以允许它被任何枚举使用,而不是被锁定为特定类型;这是我能做的最好的事情,因为我无法应用接口将其限制为我添加了描述的枚举。

      【讨论】:

        【解决方案6】:

        CategoryAttribute 似乎有根据内部资源查找本地化字符串的代码,但DescriptionAttribute 没有本地化。

        来自反射器:

        public string Category
        {
            get
            {
                if (!this.localized)
                {
                    this.localized = true;
                    string localizedString = this.GetLocalizedString(this.categoryValue);
                    if (localizedString != null)
                    {
                        this.categoryValue = localizedString;
                    }
                }
                return this.categoryValue;
             }
        }
        

        我认为您会扩展属性并创建自己的实现,传入 ResourceType。像这样的东西,模糊地基于DataAnnotation 逻辑。显然需要更多的清理。

        public class LocaleDescriptionAttribute : DescriptionAttribute
        {
            ...
        
            public LocaleDescriptionAttribute(string resourceKey, Type resourceType)
                : base(resourceKey)
            {
                this.resourceType = resourceType;
            }
        
            public override string  Description
            {
                get 
                { 
                    var description = base.Description;
                    PropertyInfo property = resourceType.GetProperty(
                               description, BindingFlags.Public | BindingFlags.Static);
                    if (property == null)
                    {
                        return description;
                    }
                    return property.GetValue(null, null) as string;
                }
            }    
        }
        

        【讨论】:

        • 其实这个Category属性和Description的最终效果并没有太大的不同。我的文件中有本地化字符串,但我可以t get any permission to apply them to an Attribute like applying them in an Exception. The only thing that im 尝试了解如何填充,即 DescriptionAttribute 与您所说的内部源。
        猜你喜欢
        • 1970-01-01
        • 2018-09-26
        • 1970-01-01
        • 2014-04-15
        • 2015-01-26
        • 1970-01-01
        • 1970-01-01
        • 2012-03-25
        • 2020-06-07
        相关资源
        最近更新 更多