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

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

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

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

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

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

6 ответов


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

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

если вы используете 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. Вы можете узнать больше о том, почему это так здесь)


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

Option for resource file code generation

что означает, что вы можете сделать что-то вроде этого (с использованием C# 6.0). Тогда вам не нужно помнить, было ли firstname строчным или camelcased. И вы можете увидеть, используют ли другие свойства то же значение ресурса с помощью find all ссылки на литературу.

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

обновление:

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

Я использую Поставщик Метаданных Обычной Модели, который представил Фил 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; }

полный учебник по локализации см. В разделе на этой странице.


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

enter image description here

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


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. определение имя атрибута, который используется для ключевых ресурсов, после C# 6.0, вы можете использовать nameof для сильной типизированной поддержки вместо жесткого кодирования ключа.

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

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

  1. установить доступность ресурса для общественности

  2. отображение метки в cshtml по такой

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