Атрибут DisplayName из ресурсов?

У меня есть локализованное приложение, и мне интересно, возможно ли иметь DisplayName для определенного свойства модели, заданного из Ресурса.

Я хотел бы сделать что-то вроде этого:

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

Но я не могу этого сделать, поскольку компилятор говорит: "Аргумент атрибута должен быть константным выражением, выражением типаof или выражением для создания массива типа атрибута": (

Есть ли способы обхода? Я выводил метки вручную, но мне нужны они для вывода валидатора.

Ответ 1

Как насчет написания пользовательского атрибута:

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

Если вы используете 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_GlobalResources или App_LocalResources. Это связано с настраиваемым инструментом (GlobalResourceProxyGenerator), который использует эти ресурсы. Вместо этого убедитесь, что ваш файл ресурсов установлен в "Встроенный ресурс" и использует специальный инструмент "ResXFileCodeGenerator".

(В качестве дополнительной заметки вам не следует использовать App_GlobalResources или App_LocalResources с MVC. Вы можете узнать больше о том, почему это так здесь)

Ответ 3

Update:

Я знаю это слишком поздно, но я хотел бы добавить это обновление:

Я использую Поставщик метаданных обычной модели, который представлен Phil Haacked, который более мощный и простой в применении, взгляните на него: ОбычнаяModelMetadataProvider


Старый ответ

Здесь, если вы хотите поддерживать многие типы ресурсов:

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

Для полного руководства по локализации см. эту страницу.

Ответ 4

Если вы откроете файл ресурсов и измените модификатор доступа на общедоступный или внутренний, он будет генерировать класс из вашего файла ресурсов, который позволяет создавать строго типизированные ссылки на ресурсы.

Вариант генерации кода ресурса

Это означает, что вы можете сделать что-то подобное (используя С# 6.0). Тогда вам не нужно помнить, было ли первое имя нижним или верблюжьим. И вы можете увидеть, используют ли другие свойства одно и то же значение ресурса при поиске всех ссылок.

[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }

Ответ 5

Я получил ответ Gunders на работу с моими App_GlobalResources, выбрав свойства ресурсов и переключив "Custom Tool" на "PublicResXFileCodeGenerator" и создав действие для "Embedded Resource". Пожалуйста, обратите внимание на комментарий Гундера ниже.

enter image description here

Работает как шарм:)

Ответ 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))]
}
  • Определите ResourceType атрибута, чтобы он искал ресурс
  • Определите Имя атрибута, который используется для ключа ресурса, после С# 6.0 вы можете использовать nameof для сильной типизированной поддержки вместо жесткого кодирования ключа.

  • Установите культуру текущего потока в контроллере.

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

  1. Установить доступность ресурса к общедоступной

  2. Отобразите ярлык в cshtml, как этот

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