Атрибут 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");
-
Установить доступность ресурса к общедоступной
-
Отобразите ярлык в cshtml, как этот
@Html.DisplayNameFor(model => model.Age)