我正在开设一个将被其他国家的某些人使用的课程。我必须本地化每条消息,警告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。有关我可以使用的东西的任何建议而不是它吗?
答案 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; }
答案 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 Gravell和dsmith的答案:
首先:创建一个名为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;
}
}
}