165

我有一个本地化的应用程序,我想知道是否可以DisplayName从资源中设置某个模型属性。

我想做这样的事情:

public class MyModel {
  [Required]
  [DisplayName(Resources.Resources.labelForName)]
  public string name{ get; set; }
}

但我不能这样做,正如编译器所说:“属性参数必须是属性参数类型的常量表达式、类型表达式或数组创建表达式”:(

有什么解决方法吗?我正在手动输出标签,但我需要这些用于验证器输出!

4

6 回答 6

385

如果您使用 MVC 3 和 .NET 4,则可以使用命名空间Display中的新属性System.ComponentModel.DataAnnotations。此属性替换了该DisplayName属性并提供了更多功能,包括本地化支持。

在你的情况下,你会像这样使用它:

public class MyModel
{
    [Required]
    [Display(Name = "labelForName", ResourceType = typeof(Resources.Resources))]
    public string name{ get; set; }
}

附带说明一下,此属性不适用于App_GlobalResourcesor中的资源App_LocalResources。这与GlobalResourceProxyGenerator这些资源使用的自定义工具 ( ) 有关。相反,请确保您的资源文件设置为“嵌入式资源”并使用“ResXFileCodeGenerator”自定义工具。

(作为进一步的说明,您不应该使用MVCApp_GlobalResources或与 MVC 一起使用。您可以在此处App_LocalResources阅读更多关于为什么会出现这种情况的信息)

于 2011-03-23T14:04:30.667 回答
115

如何编写自定义属性:

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; }
}
于 2010-03-12T12:05:06.667 回答
36

如果您打开资源文件并将访问修饰符更改为 public 或 internal ,它将从您的资源文件生成一个类,该类允许您创建强类型资源引用。

资源文件代码生成选项

这意味着您可以改为执行此类操作(使用 C# 6.0)。然后你不必记住名字是小写还是驼峰。您可以通过查找所有引用查看其他属性是否使用相同的资源值。

[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }
于 2016-03-17T15:05:28.087 回答
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; }

有关完整的本地化教程,请参阅此页面

于 2011-02-05T12:46:46.473 回答
11

通过选择资源属性并将“自定义工具”切换到“PublicResXFileCodeGenerator”并将操作构建到“嵌入式资源”,我得到了 Gunders 使用我的 App_GlobalResources 的答案。请注意下面的 Gunders 评论。

在此处输入图像描述

奇迹般有效 :)

于 2013-01-27T16:04:44.590 回答
6
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))]
}
  1. 定义属性的ResourceType以便它查找资源
  2. 定义用于资源键的属性名称nameof,在 C# 6.0 之后,您可以使用强类型支持而不是硬编码键。

  3. 在控制器中设置当前线程的文化。

Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");

  1. 将资源的可访问性设置为公开

  2. 像这样在cshtml中显示标签

@Html.DisplayNameFor(model => model.Age)

于 2017-06-19T08:04:06.110 回答