Атрибут DisplayName из ресурсов? - PullRequest
158 голосов
/ 12 марта 2010

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

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

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

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

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

Ответы [ 6 ]

366 голосов
/ 23 марта 2011

Если вы используете 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. Подробнее о причинах этого можно прочитать здесь )

108 голосов
/ 12 марта 2010

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

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; }
}
32 голосов
/ 17 марта 2016

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

Option for resource file code generation

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

[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }
20 голосов
/ 05 февраля 2011

Обновление:

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

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

Полное руководство по локализации см. На этой странице .

11 голосов
/ 27 января 2013

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

enter image description here

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

5 голосов
/ 19 июня 2017
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)

...