我有一个本地化的应用程序,我想知道是否可以从资源中为某个模型属性集设置DisplayName
。
我想做这样的事情:
public class MyModel {
[Required]
[DisplayName(Resources.Resources.labelForName)]
public string name{ get; set; }
}
但我不能这样,因为编译器说:“属性参数必须是属性参数类型的常量表达式,typeof表达式或数组创建表达式”:(
有任何变通方法吗?我手动输出标签,但我需要这些用于验证器输出!
答案 0 :(得分:365)
如果使用MVC 3和.NET 4,则可以使用System.ComponentModel.DataAnnotations
命名空间中的新Display
属性。此属性替换DisplayName
属性并提供更多功能,包括本地化支持。
在你的情况下,你会像这样使用它:
public class MyModel
{
[Required]
[Display(Name = "labelForName", ResourceType = typeof(Resources.Resources))]
public string name{ get; set; }
}
作为旁注,此属性不适用于App_GlobalResources
或App_LocalResources
内的资源。这与这些资源使用的自定义工具(GlobalResourceProxyGenerator
)有关。而是确保您的资源文件设置为“嵌入资源”并使用“ResXFileCodeGenerator”自定义工具。
(另请注意,您不应该将App_GlobalResources
或App_LocalResources
与MVC一起使用。您可以详细了解为何会出现这种情况here)
答案 1 :(得分:108)
如何编写自定义属性:
public class LocalizedDisplayNameAttribute: DisplayNameAttribute
{
public LocalizedDisplayNameAttribute(string resourceId)
: base(GetMessageFromResource(resourceId))
{ }
private static string GetMessageFromResource(string resourceId)
{
// TODO: Return the string from the resource file
}
}
可以像这样使用:
public class MyModel
{
[Required]
[LocalizedDisplayName("labelForName")]
public string Name { get; set; }
}
答案 2 :(得分:30)
如果您打开资源文件并将访问修饰符更改为public或internal,它将从您的资源文件生成一个类,允许您创建强类型资源引用。
这意味着你可以做这样的事情(使用C#6.0)。 然后你不必记住firstname是小写还是camelcased。您可以查看其他属性是否使用相同的资源值和查找所有引用。
[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }
答案 3 :(得分:20)
我知道为时已晚,但我想添加此更新:
我正在使用由Phil Haacked提供的常规模型元数据提供程序,它更强大且易于应用,请查看它: ConventionalModelMetadataProvider
如果您想支持多种类型的资源,请点击此处:
public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
private readonly PropertyInfo nameProperty;
public LocalizedDisplayNameAttribute(string displayNameKey, Type resourceType = null)
: base(displayNameKey)
{
if (resourceType != null)
{
nameProperty = resourceType.GetProperty(base.DisplayName,
BindingFlags.Static | BindingFlags.Public);
}
}
public override string DisplayName
{
get
{
if (nameProperty == null)
{
return base.DisplayName;
}
return (string)nameProperty.GetValue(nameProperty.DeclaringType, null);
}
}
}
然后像这样使用它:
[LocalizedDisplayName("Password", typeof(Res.Model.Shared.ModelProperties))]
public string Password { get; set; }
有关完整的本地化教程,请参阅this page。
答案 4 :(得分:11)
通过选择资源属性并将“Custom Tool”切换为“PublicResXFileCodeGenerator”并将操作构建到“Embedded Resource”,我让Gunders回答了我的App_GlobalResources。 请观察下面的Gunders评论。
像魅力一样工作:)
答案 5 :(得分:5)
public class Person
{
// Before C# 6.0
[Display(Name = "Age", ResourceType = typeof(Testi18n.Resource))]
public string Age { get; set; }
// After C# 6.0
// [Display(Name = nameof(Resource.Age), ResourceType = typeof(Resource))]
}
定义用于资源键的属性的名称,在C#6.0之后,您可以使用nameof
进行强类型支持,而不是对密钥进行硬编码。
在控制器中设置当前线程的文化。
Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");
将资源的可访问性设置为public
在 cshtml 中显示标签
@Html.DisplayNameFor(model => model.Age)