如何在c#中本地化属性描述?

时间:2011-09-13 08:07:24

标签: c# localization properties

我正在开设一个将被其他国家的某些人使用的课程。我必须本地化每条消息,警告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
            {...}
        }

这就是我想要做的。但是不可能以这种方式使用Localisations。有关我可以使用的东西的任何建议而不是它吗?

6 个答案:

答案 0 :(得分:20)

子类:

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

答案 1 :(得分:4)

[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

答案 2 :(得分:3)

我们来看看这个示例类:

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

答案 3 :(得分:3)

我已合并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; }
}

答案 4 :(得分:2)

对Jani答案的轻微扩展(对我来说效果很好):

string description = Strings.GetString( Key );

可以更明确地完成

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

隐晦暗示,但不清楚原始代码中缺少什么。资源类的.ResourceManager属性是自动生成的。

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

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

答案 5 :(得分:1)

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

来自Reflector:

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