Атрибут 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, он создаст класс из вашего файла ресурсов, который позволит вам создавать строго типизированные ссылки на ресурсы.
что означает, что вы можете сделать что-то вроде этого (с использованием 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 комментарий ниже.
работает как шарм :)
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 атрибута, поэтому он ищет ресурс
определение имя атрибута, который используется для ключевых ресурсов, после C# 6.0, вы можете использовать
nameof
для сильной типизированной поддержки вместо жесткого кодирования ключа.установите культуру текущего потока в контроллере.
Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");
установить доступность ресурса для общественности
отображение метки в cshtml по такой
@Html.DisplayNameFor(model => model.Age)