J'ai une application localisée et je me demande s'il est possible d'avoir le DisplayName
d'un certain ensemble de propriétés de modèle à partir d'une ressource.
J'aimerais faire quelque chose comme ça:
public class MyModel {
[Required]
[DisplayName(Resources.Resources.labelForName)]
public string name{ get; set; }
}
Mais je n'y arrive pas, comme le dit le compilateur: "Un argument d'attribut doit être une expression constante, une expression typeof ou une expression de création de tableau d'un type de paramètre d'attribut" :(
Existe-t-il des solutions de contournement? Je sors les étiquettes manuellement, mais j'ai besoin de celles-ci pour la sortie du validateur!
Que diriez-vous d'écrire un attribut personnalisé:
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
}
}
qui pourrait être utilisé comme ceci:
public class MyModel
{
[Required]
[LocalizedDisplayName("labelForName")]
public string Name { get; set; }
}
Si vous utilisez MVC 3 et .NET 4, vous pouvez utiliser le nouvel attribut Display
dans le System.ComponentModel.DataAnnotations
espace de noms. Cet attribut remplace l'attribut DisplayName
et fournit beaucoup plus de fonctionnalités, y compris la prise en charge de la localisation.
Dans votre cas, vous l'utiliseriez comme ceci:
public class MyModel
{
[Required]
[Display(Name = "labelForName", ResourceType = typeof(Resources.Resources))]
public string name{ get; set; }
}
En remarque, cet attribut ne fonctionnera pas avec les ressources à l'intérieur de App_GlobalResources
ou App_LocalResources
. Cela concerne l'outil personnalisé (GlobalResourceProxyGenerator
) que ces ressources utilisent. Au lieu de cela, assurez-vous que votre fichier de ressources est défini sur 'Ressources incorporées' et utilisez l'outil personnalisé 'ResXFileCodeGenerator'.
(Remarque supplémentaire, vous ne devriez pas utiliser App_GlobalResources
ou App_LocalResources
avec MVC. Vous pouvez en savoir plus sur pourquoi c'est le cas ici )
Si vous ouvrez votre fichier de ressources et modifiez le modificateur d'accès en public ou en interne, une classe sera générée à partir de votre fichier de ressources, ce qui vous permettra de créer des références de ressources fortement typées.
Ce qui signifie que vous pouvez faire quelque chose comme ceci à la place (en utilisant C # 6.0). Ensuite, vous ne devez pas vous souvenir si le prénom était en minuscule ou en camelcas. Et vous pouvez voir si d'autres propriétés utilisent la même valeur de ressource avec une recherche de toutes les références.
[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }
Je sais qu'il est trop tard, mais j'aimerais ajouter cette mise à jour:
J'utilise le fournisseur de métadonnées de modèle conventionnel présenté par Phil Haacked , il est plus puissant et facile à appliquer. Regardez-le : ConventionalModelMetadataProvider
Ici si vous voulez supporter plusieurs types de ressources:
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);
}
}
}
Ensuite, utilisez-le comme ceci:
[LocalizedDisplayName("Password", typeof(Res.Model.Shared.ModelProperties))]
public string Password { get; set; }
Pour le tutoriel de localisation complet, voir cette page .
J'ai obtenu la réponse de Gunders avec mes App_GlobalResources en choisissant les propriétés des ressources, en basculant "Outil personnalisé" sur "PublicResXFileCodeGenerator" et construire l'action en "Ressource incorporée". Veuillez observer le commentaire de Gunders ci-dessous.
Fonctionne comme un charme :)
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))]
}
Définissez Nom de l'attribut utilisé pour la clé de ressource. Après C # 6.0, vous pouvez utiliser nameof
pour la prise en charge avec caractères forts au lieu de coder en dur la clé.
Définissez la culture du thread actuel dans le contrôleur.
Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");
Définir l'accessibilité de la ressource au public
Afficher l'étiquette dans cshtml comme ceci
@Html.DisplayNameFor(model => model.Age)