web-dev-qa-db-fra.com

Attribut DisplayName de ressources?

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!

159
Palantir

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; }
}
108
Darin Dimitrov

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 )

367
René

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.

Option for resource file code generation

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

Mise à jour:

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


Ancienne réponse

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 .

20
Wahid Bitar

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.

enter image description here

Fonctionne comme un charme :)

11
Magnus Karlsson
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. Définissez ResourceType de l'attribut pour qu'il recherche une ressource
  2. 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é.

  3. Définissez la culture du thread actuel dans le contrôleur.

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

  1. Définir l'accessibilité de la ressource au public

  2. Afficher l'étiquette dans cshtml comme ceci

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

5
code4j