Localisation Enum

Comment localisez-vous des énumérations pour un ListBoxFor où plusieurs options sont possibles?

Par exemple un enum qui contient des rôles:

public enum RoleType
{
    [Display(Description = "Administrator", ResourceType = typeof(Resource))]
    Administrator = 1,
    [Display(Description = "Moderator", ResourceType = typeof(Resource))]
    Moderator = 2,
    [Display(Description = "Webmaster", ResourceType = typeof(Resource))]
    Webmaster = 3,
    [Display(Description = "Guest", ResourceType = typeof(Resource))]
    Guest = 4,
    Etc.... = 5,
}

J'ai vu ce fait avec dropdownlist/selectlists. Mais y a-t-il un moyen de le faire pour une liste de sélection multiple?

[MODIFIER]

Voici comment je voudrais l'utiliser, ce qui est la façon dont cela fonctionne maintenant, mais ne se traduit pas dans une autre langue:

var roles = from role r in Enum.GetValues(typeof(RoleType))
            select new
            {
               Id = (int)Enum.Parse(typeof(RoleType), r.ToString()),
               Name = r.ToString()
            };

searchModel.roles = new MultiSelectList(roles, "Id", "Name");

Note: j'ai renommé L'énumération de Role en RoleType.

47
demandé sur Quoter 2013-06-29 17:53:26

12 réponses

Vous pouvez implémenter un attribut description.

public class LocalizedDescriptionAttribute : DescriptionAttribute
{
     private readonly string _resourceKey;
    private readonly ResourceManager _resource;
    public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
    {
        _resource = new ResourceManager(resourceType);
        _resourceKey = resourceKey;
    }

    public override string Description
    {
        get
        {
            string displayName = _resource.GetString(_resourceKey);

            return string.IsNullOrEmpty(displayName)
                ? string.Format("[[{0}]]", _resourceKey)
                : displayName;
        }
    }
}

public static class EnumExtensions
{
    public static string GetDescription(this Enum enumValue) 
    {
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());

        DescriptionAttribute[] attributes =
            (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute),
            false);

        if (attributes != null &&
            attributes.Length > 0)
            return attributes[0].Description;
        else
            return enumValue.ToString();
    }
}

Définissez-le comme ceci:

public enum Roles
{
    [LocalizedDescription("Administrator", typeof(Resource))]
    Administrator,
...
}

Et l'utiliser comme ceci:

var roles = from RoleType role in Enum.GetValues(typeof(RoleType))
                    select new
                    {
                        Id = (int)role,
                        Name = role.GetDescription()
                    };
 searchModel.roles = new MultiSelectList(roles, "Id", "Name");
61
répondu eluxen 2014-03-07 17:32:25

J'ai résolu le problème en créant une extension EnumExtension que j'utilise à mon avis. Cette extension recherche un fichier de ressources appelé " EnumResources.resx " et recherche la ressource par la convention de nommage suivante {Nom de EnumType}_{valeur de l'énumération transmise}. Si la clé de ressource est manquante, elle affichera la valeur de la ressource encapsulée entre crochets doubles [[EnumValue]]. De cette façon, il est facile de trouver une énumération "non traduite" à votre avis. En outre, cela aide à vous rappeler si vous avez oublié de mettre à jour le fichier de ressources après un renommage ou tel.

public static class EnumExtensions
{
    public static string GetDisplayName(this Enum e)
    {
        var rm = new ResourceManager(typeof (EnumResources));
        var resourceDisplayName = rm.GetString(e.GetType().Name + "_" + e);

        return string.IsNullOrWhiteSpace(resourceDisplayName) ? string.Format("[[{0}]]", e) : resourceDisplayName;
    }
}

Le fichier de ressources ressemble à ceci: Fichier de ressources

Utilisation:

<div>@ContractStatus.Created.GetDisplayName()</div>
25
répondu disco 2014-03-19 12:57:06

Il existe un moyen d'utiliser des attributs pour spécifier une chaîne à utiliser pour les énumérations lors de leur affichage, mais nous l'avons trouvé trop difficile lorsque vous deviez gérer la localisation.

Donc, ce que nous faisons habituellement pour les énumérations qui doivent être localisées est d'écrire une classe d'extension qui fournit une méthode pour obtenir le nom traduit. Vous pouvez simplement utiliser un commutateur qui renvoie des chaînes à partir des ressources habituelles. De cette façon, vous fournissez des chaînes traduites pour les énumérations via les ressources comme vous le faites pour les autres chaîne.

Par exemple:

public enum Role
{
    Administrator,
    Moderator,
    Webmaster,
    Guest
}

public static class RoleExt
{
    public static string AsDisplayString(this Role role)
    {
        switch (role)
        {
            case Role.Administrator: return Resources.RoleAdministrator;
            case Role.Moderator:     return Resources.RoleModerator;
            case Role.Webmaster:     return Resources.RoleWebmaster;
            case Role.Guest:         return Resources.RoleGuest;

            default: throw new ArgumentOutOfRangeException("role");
        }
    }
}

Que vous pouvez utiliser comme ceci:

var role = Role.Administrator;
Console.WriteLine(role.AsDisplayString());

Si vous conservez l'implémentation de la classe RoleExt à côté de l'implémentation enum Role, elle fera effectivement partie de l'interface pour Role. Bien sûr, vous pouvez également ajouter à cette classe d'autres extensions utiles pour l'énumération .

[Modifier]

Si vous voulez gérer plusieurs paramètres de drapeaux ("administrateur et modérateur et Webmaster"), vous devez faire les choses un peu autrement:

[Flags]
public enum Roles
{
    None          = 0,
    Administrator = 1,
    Moderator     = 2,
    Webmaster     = 4,
    Guest         = 8
}

public static class RolesExt
{
    public static string AsDisplayString(this Roles roles)
    {
        if (roles == 0)
            return Resources.RoleNone;

        var result = new StringBuilder();

        if ((roles & Roles.Administrator) != 0)
            result.Append(Resources.RoleAdministrator + " ");

        if ((roles & Roles.Moderator) != 0)
            result.Append(Resources.RoleModerator + " ");

        if ((roles & Roles.Webmaster) != 0)
            result.Append(Resources.RoleWebmaster + " ");

        if ((roles & Roles.Guest) != 0)
            result.Append(Resources.RoleGuest + " ");

        return result.ToString().TrimEnd();
    }
}

Que vous pouvez utiliser comme ceci:

Roles roles = Roles.Administrator | Roles.Guest | Roles.Moderator;
Console.WriteLine(roles.AsDisplayString());

Fichiers De Ressources

Les fichiers de ressources sont la façon dont vous internationalisez vos chaînes. Pour plus d'informations sur la façon de les utiliser, voir ici:

Http://msdn.microsoft.com/en-us/library/vstudio/aa992030%28v=vs.100%29.aspx http://msdn.microsoft.com/en-us/library/vstudio/756hydy4%28v=vs.100%29.aspx

8
répondu Matthew Watson 2013-06-30 08:55:39

Vous pouvez utiliser votre valeur enum pour faire ce que vous voulez.

public enum Roles
{
    Administrator = 0,
    Moderator = 1 ,
    Webmaster  = 2,
    Guest = 3 ,
    Etc.... = 4 
}

Lorsque vous voulez obtenir l'énumération sélectionnée dans la listbox, vous récupérez l'élément listbox, puis vous récupérez le numéro d'énumération associé.

Ensuite, vous allez convertir cela en un élément enum comme ceci

Roles myrol = (Roles) i

(i est associé int vale pour cet exemple)

Convertir l'élément enum en entier et la valeur entière en élément enum

 Enum Item to Integer----- 
    int i =  (int)Roles.Admin ;
    Integer to enum Itenm
    Roles r = (Roles)i ; 

     //Getting the name of the enum
     string role =  Role.Admin.ToString() 

Si vous ajoutez à une table de hachage, vous pouvez le faire ceci façon

Hashtable h = new Hashtable() ; 
h.Items.Add((int)Roles.Admin , Roles.Admin.ToStrinng() ) ;
h.Items.Add((int)Roles.Local , Roles.Local.ToStrinng() ) ; 

Lorsque vous choisissez un élément dans la table de hachage , convertir Enum élément et l'utiliser où vous voulez. Vous pouvez utiliser la même manière pour remplir Datatables / Comboboxes , listes déroulantes et ainsi de suite

2
répondu Kas 2017-05-03 20:32:36

Une version de la réponse de @eluxen fonctionnant pour certaines bibliothèques portables (PCL) (spécifiquement pour Profile47) où la solution originale ne fonctionnera pas. Deux problèmes ont été résolus: DescriptionAttribute n'est pas disponible dans les bibliothèques portables, et le problème signalé par @Jitendra Pancholi avec l'erreur "Impossible de trouver des ressources" est résolu

public class LocalizedDescriptionAttribute : Attribute
{
    private readonly string _resourceKey;
    private readonly Type _resourceType;
    public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
    {
        _resourceType = resourceType;
        _resourceKey = resourceKey;
    }

    public string Description
    {
        get
        {
            string displayName = String.Empty;
            ResourceManager resMan = _resourceType.GetProperty(
                @"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;
            CultureInfo culture = _resourceType.GetProperty(
                    @"Culture", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as CultureInfo;

            if (resMan != null)
            {
                displayName = resMan.GetString(_resourceKey, culture);
            }

            var ret = string.IsNullOrEmpty(displayName) ? string.Format("[[{0}]]", _resourceKey) : displayName;
            return ret;
        }
    }
}

Pour l'utilisation, voir la réponse originale . Et si vous ne rencontrez aucun problème, j'utiliserais toujours la réponse originale car elle ne contient pas de solutions de contournement par réflexion

1
répondu avitenberg 2017-05-23 11:54:46

L'un des problèmes avec la traduction / localisation des énumérations est que non seulement vous devez les traduire pour les afficher, mais aussi analyser les traductions à la valeur enum. Le fichier C# suivant contient Comment j'ai surmonté les problèmes de traductions bidirectionnelles des énumérations. Pardonnez les commentaires excessifs, mais je suis assez bavard sur mes créations.

//
// EnumExtensions.cs  
//
using System;
using System.Collections.Generic;

namespace EnumExtensionsLibrary
{
    /// <summary>
    /// The functions in this class use the localized strings in the resources
    /// to translate the enum value when output to the UI and reverse--
    /// translate when receiving input from the UI to store as the actual
    /// enum value.
    /// </summary>
    /// 
    /// <Note>
    /// Some of the exported functions assume that the ParserEnumLocalizationHolder
    /// and ToStringEnumLocalizationHolder dictionaries (maps) may contain the enum 
    /// types since they callthe Initialize methods with the input type before executing.
    /// </Note>
    public static class EnumExtensions
    {
        #region Exported methods
        /// <summary>
        /// Save resource from calling project so that we can look up enums as needed.
        /// </summary>
        /// <param name="resourceManager">Where we fish the translated strings from</param>
        /// <remarks>
        /// We do not have access to all of the resources from the other projects directly,
        /// so they must be loaded from the code from within the project.
        /// </remarks>
        public static void RegisterResource(System.Resources.ResourceManager resourceManager)
        {
            if (!MapOfResourceManagers.Contains(resourceManager))
                MapOfResourceManagers.Add(resourceManager);
        }

        /// <summary>
        /// Parses the localized string value of the enum by mapping it 
        /// to the saved enum value
        /// </summary>
        /// <remarks>
        /// In some cases, string for enums in the applications may not be translated to the
        /// localized version (usually when the program presets parameters).  If the enumMap
        /// doesn't contain the value string, we call to Enum.Parse() to handle the conversion
        /// or throw an exception.
        /// </remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <exception cref="ArgumentNullException"> enumType or value is null.</exception>
        /// <exception cref="ArgumentException"> enumType is not an Enum. value is either an 
        /// empty string or only contains white space, value is a name, but not one of the 
        /// named constants defined for the enumeration.</exception>
        /// <exception cref="ArgumentNullException">enumType or value is null.</exception>
        /// <returns>
        /// The enum value that matched the input string if found.  If not found, we call 
        /// Enum.Parse to handle the value.
        /// </returns>
        public static T ParseEnum<T>(this string value) where T : struct
        {
            ParserInitialize(typeof(T));
            var enumMap = ParserEnumLocalizationHolder[typeof(T)];
            if (enumMap.ContainsKey(value))
                return (T) enumMap[value];
            return (T)Enum.Parse(typeof(T), value); 
        }

        /// <summary>
        /// Parses the localized string value of the enum by mapping it 
        /// to the saved enum value.  
        /// </summary>
        /// <remarks>
        /// In some cases, string for enums in the applications may not be translated to the
        /// localized version (usually when the program presets parameters).  If the enumMap
        /// doesn't contain the value string, we call to Enum.TryParse() to handle the 
        /// conversion. and return.
        /// </remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="result"></param>
        /// <returns>
        /// Returns true if the enum mapping contains the localized string value and the data 
        /// in the returned result parameter will be a valid value of that enum type. if the
        /// string value is not mapped, then calls Enum.TryParse to handle the conversion and 
        /// return result.
        /// </returns>
        public static bool TryParseEnum<T>(this string value, out T result) where T : struct
        {
            ParserInitialize(typeof(T));
            var enumMap = ParserEnumLocalizationHolder[typeof(T)];
            if (!enumMap.ContainsKey(value))
                return Enum.TryParse(value, out result);
            result = (T)enumMap[value];
            return true;
        }

        /// <summary>
        /// Converts the enum value to a localized string.
        /// </summary>
        /// <typeparam name="T">must be an enum to work</typeparam>
        /// <param name="value">is an enum</param>
        /// <returns>
        /// The localized string equivalent of the input enum value
        /// </returns>
        public static string EnumToString<T>(this T value) where T : struct
        {
            ToStringInitialize(typeof(T));
            var toStringMap = ToStringEnumLocalizationHolder[typeof(T)];
            return toStringMap.ContainsKey(value) ? toStringMap[value] : value.ToString();

            //return EnumDescription(value);
        }

        /// <summary>
        /// Gathers all of the localized translations for each 
        /// value of the input enum type into an array
        /// </summary>
        /// <remarks>
        /// The return array from Type.GetEnumValues(), the array elements are sorted by 
        /// the binary values (that is, the unsigned values) of the enumeration constants.
        /// </remarks>
        /// <param name="enumType"></param>
        /// <exception cref="ArgumentException"> The current type is not an enumeration.</exception>
        /// <returns>
        /// A string array with the localized strings representing
        /// each of the values of the input enumType.
        /// </returns>
        public static string[] AllDescription(this Type enumType)
        {
            ToStringInitialize(enumType);
            var descriptions = new List<string>();
            var values = enumType.GetEnumValues();
            var toStringMap = ToStringEnumLocalizationHolder[enumType];
            foreach (var value in values)
            {
                descriptions.Add(toStringMap.ContainsKey(value) ? toStringMap[value] : value.ToString());
            }
            return descriptions.ToArray();
        }
        #endregion

        #region Helper methods
        /// <summary>
        /// Translates an enum value into its localized string equivalent
        /// </summary>
        /// <remarks>
        /// This assumes that the "name" for the localized string in the 
        /// resources will look like "enum-type-name""value".  For example,  
        /// if I have an enum setup as:
        /// 
        ///     enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
        /// 
        /// the value "Sun" in the enum must have the name: "DaysSun"
        /// in the resources. The localized (translated) string will
        /// be in the value field.  E.g.,
        ///
        ///  <data name="DaysSun" xml:space="preserve">
        /// <value>Sunday</value>
        ///  </data>    
        /// 
        /// 2nd note: there may be multiple resources to pull from.
        /// Will look in each resource until we find a match or 
        /// return null.
        /// </remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumType">the enum type</param>
        /// <param name="value">the specific enum value</param>
        /// <returns>
        /// If the enum value is found in the resources, then return 
        /// that string.  If not, then return null. 
        /// </returns>
        private static string LocalEnumDescription<T>(Type enumType, T value)
        {
            foreach (var resourceManager in MapOfResourceManagers)
            {
                // The following live line uses string interpolation to perform:
                //var rk = string.Format("{0}{1}", enumType.Name, value);
                var rk = $"{enumType.Name}{value}";

                // Given the above string formatting/interpolation, neither the enum.Name 
                // nor the value will have a '.' so we do not have to remove it.
                var result = resourceManager.GetString(rk);
                if (!string.IsNullOrEmpty(result))
                    return result;
            }
            return null;
        }

        /// <summary>
        /// Initializes the mapping of the enum type to its mapping of localized strings to 
        /// the enum's values.
        /// </summary>
        /// <remarks>
        /// The reason for each enum type to have a mapping from the localized string back 
        /// to its values is for ParseEnum and TryParseEnum to quickly return a value rather
        /// than doing a lengthy loop comparing each value in the resources.
        /// 
        /// Also, we only map the corresponding resource string if it exists in the resources.
        /// If not in the resources, then we call the Enum methods Parse() and TryParse() to
        /// figure the results and throw the appropriate exception as needed.
        /// </remarks>
        /// 
        /// <param name="enumType"></param>
        private static void ParserInitialize(Type enumType)
        {
            if (!ParserEnumLocalizationHolder.ContainsKey(enumType))
            {
                var values = enumType.GetEnumValues();  // See remark for AllDescription().
                var enumMap = new Dictionary<string, object>();
                foreach (var value in values)
                {
                    var description = LocalEnumDescription(enumType, value);
                    if (description != null)
                        enumMap[description] = value;
                }
                ParserEnumLocalizationHolder[enumType] = enumMap;
            }
        }

        /// <summary>
        /// Initializes the mapping of the enum type to its mapping of the enum's values
        /// to their localized strings.
        /// </summary>
        /// <remarks>
        /// The reason for each enum type to have a mapping from the localized string to its
        /// values is for AllDescription and EnumToString to quickly return a value rather 
        /// than doing a lengthy loop runing through each of the resources.
        /// 
        /// Also, we only map the corresponding resource string if it exists in the resources.
        /// See the EnumDescription method for more information.
        /// </remarks>
        /// 
        /// <param name="enumType"></param>
        private static void ToStringInitialize(Type enumType)
        {
            if (!ToStringEnumLocalizationHolder.ContainsKey(enumType))
            {
                var values = enumType.GetEnumValues();  // See remark for AllDescription().
                var enumMap = new Dictionary<object, string>();
                foreach (var value in values)
                {
                    var description = LocalEnumDescription(enumType, value);
                    if (description != null)
                        enumMap[value] = description;
                }
                ToStringEnumLocalizationHolder[enumType] = enumMap;
            }
        }
        #endregion

        #region Data
        private static readonly List<System.Resources.ResourceManager> MapOfResourceManagers =
            new List<System.Resources.ResourceManager>();
        private static readonly Dictionary<Type, Dictionary<string, object>> ParserEnumLocalizationHolder =
            new Dictionary<Type, Dictionary<string, object>>();
        private static readonly Dictionary<Type, Dictionary<object, string>> ToStringEnumLocalizationHolder =
            new Dictionary<Type, Dictionary<object, string>>();
        #endregion
    }
}

Cela ne nécessite pas d'attribut avant chaque valeur enum, mais nécessite que l'attribut name de votre chaîne enum traduite dans le resources est formaté de telle sorte qu'il s'agisse d'une concaténation du nom-type-enum et de la valeur enum. Voir le commentaire ci-dessus la méthode LocalEnumDescription pour plus d'informations. En outre, il préserve les traductions des énumérations (à la fois vers l'avant et vers l'arrière) en mappant leurs traductions de sorte que nous n'avons pas besoin de rechercher la traduction chaque fois que nous rencontrons une valeur enum.

J'espère que c'est assez facile à comprendre et à utiliser.

1
répondu Jim Lonero 2016-08-26 22:26:52

Encore une autre possibilité est de créer un mondial nom d'affichage de stockage la classe d'extension de plus de Enum classe:

// Enum display names
public static class EnumDisplayNames {
  // Display name storage
  private static Dictionary<Type, Dictionary<Enum, String>> s_Names = 
    new Dictionary<Type, Dictionary<Enum, String>>();

  // Display name for the single enum's option
  private static String CoreAsDisplayName(Enum value) {
    Dictionary<Enum, String> dict = null;

    if (s_Names.TryGetValue(value.GetType(), out dict)) {
      String result = null;

      if (dict.TryGetValue(value, out result))
        return result;
      else
        return Enum.GetName(value.GetType(), value);
    }
    else
      return Enum.GetName(value.GetType(), value);
  }

  // Register new display name
  public static void RegisterDisplayName(this Enum value, String name) {
    Dictionary<Enum, String> dict = null;

    if (!s_Names.TryGetValue(value.GetType(), out dict)) {
      dict = new Dictionary<Enum, String>();

      s_Names.Add(value.GetType(), dict);
    }

    if (dict.ContainsKey(value))
      dict[value] = name;
    else
      dict.Add(value, name);
  }

  // Get display name
  public static String AsDisplayName(this Enum value) {
    Type tp = value.GetType();

    // If enum hasn't Flags attribute, just put vaue's name 
    if (Object.ReferenceEquals(null, Attribute.GetCustomAttribute(tp, typeof(FlagsAttribute))))
      return CoreAsDisplayName(value);

    // If enum has Flags attribute, enumerate all set options
    Array items = Enum.GetValues(tp);

    StringBuilder Sb = new StringBuilder();

    foreach (var it in items) {
      Enum item = (Enum) it;

      if (Object.Equals(item, Enum.ToObject(tp, 0)))
        continue;

      if (value.HasFlag(item)) {
        if (Sb.Length > 0)
          Sb.Append(", ");
        Sb.Append(CoreAsDisplayName(item));
      }
    }

    Sb.Insert(0, '[');

    Sb.Append(']');

    return Sb.ToString();
  }
}

L'utilisation Possible est très simple, par exemple:

  public enum TestEnum {
    None,
    One,
    Two,
    Three
  }

  [Flags]
  public enum TestOptions {
    None = 0,
    One = 1,
    Two = 2,
    Three = 4
  }

  ...

  // Let them be in German (for demonstration only)... 
  TestEnum.None.RegisterDisplayName("Nichts");
  TestEnum.One.RegisterDisplayName("Eins");
  TestEnum.Two.RegisterDisplayName("Zwei");
  TestEnum.Three.RegisterDisplayName("Drei");

  // Usually, you obtain display names from resources:
  // TestEnum.None.RegisterDisplayName(Resources.NoneName);
  // ...

  TestOptions.None.RegisterDisplayName("-");
  TestOptions.One.RegisterDisplayName("bit 0 set");
  TestOptions.Two.RegisterDisplayName("bit 1 set");
  TestOptions.Three.RegisterDisplayName("bit 2 set");
  TestOptions.Four.RegisterDisplayName("bit 3 set");

  ...

  TestEnum v = TestEnum.Two;
  String result = v.AsDisplayName(); // <- "Zwei"

  TestOptions o = TestOptions.One | TestOptions.Three | TestOptions.Four;
  String result2 = o.AsDisplayName(); // <- "[bit 0 set, bit 2 set, bit 3 set]"
0
répondu Dmitry Bychenko 2013-06-29 18:02:59

La méthode d'extension de ci-dessous a fonctionné pour moi.

    public static string GetDisplayValue(this Enum value)
    {
        try
        {
            var fieldInfo = value.GetType().GetField(value.ToString());
            var descriptionAttributes = fieldInfo.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];

            if (descriptionAttributes == null || descriptionAttributes.Length == 0) return value.ToString();

            if (descriptionAttributes[0].ResourceType != null)
            {
                var resource = descriptionAttributes[0].ResourceType.GetProperty("ResourceManager").GetValue(null) as ResourceManager;
                return resource.GetString(descriptionAttributes[0].Name);
            }
            else
            {
                return descriptionAttributes[0].Name;
            }
        }
        catch
        {
            return value.ToString();
        }
    }

Je holpe aide.

0
répondu jmsandy 2016-01-27 23:30:21

Même réponse que la réponse acceptée mais sans avertissements d'analyse de code

 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments", Justification ="Resourcetype is only needed to instantiate Resource manager, and ResourceManager is exposed")]
[AttributeUsage(AttributeTargets.All)]
public sealed class LocalizedDescriptionAttribute 
    : DescriptionAttribute
{
    private readonly string _resourceKey;
    private readonly ResourceManager _resourceManager;

    public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
    {
        _resourceManager = new ResourceManager(resourceType);
        _resourceKey = resourceKey;
    }

    public string ResourceKey
    {
        get { return _resourceKey; }
    }

    public ResourceManager ResourceManager
    {
        get { return _resourceManager; }
    }

    public override string Description
    {
        get
        {
            string displayName = _resourceManager.GetString(_resourceKey);
            return string.IsNullOrEmpty(displayName)? string.Format(CultureInfo.CurrentUICulture ,"[[{0}]]", _resourceKey) : displayName;
        }
    }
}

public static class EnumExtensions
{
    public static string GetDescription(this Enum enumValue)
    {
        if (enumValue == null)
        {
            throw new ArgumentNullException("enumValue");
        }
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes != null && attributes.Length > 0)
        {
            return attributes[0].Description;
        }
        else
        {
            return enumValue.ToString();
        }
    }
}
0
répondu Martijn 2016-07-04 11:27:45

Les solutions ci-dessus avec LocalizedDescriptionAttribute le lisent à partir de la langue actuelle du programme. Parfait pour un client, pas si flexible pour un côté serveur lorsque vous voulez passer la langue en paramètre.

J'ai donc étendu la solution eluxen avec LocalizedDescriptionAttribute en ajoutant une autre méthode:

    /// <summary>
    /// Gets the description, stored in this attribute, reading from the resource using the cultureInfo defined by the language!
    /// </summary>
    /// <param name="language">The language.</param>
    /// <returns>Description for the given language if found; the default Description or ressourceKey otherwise</returns>
    public string GetDescription(string language)
    {
        return resource.GetStringFromResourceForLanguage(resourceKey, language, Description);
    }

    public static string GetStringFromResourceForLanguage(this ResourceManager resourceManager, string resourceKey, string language, string defaultValue = null)
    {
        if (string.IsNullOrEmpty(defaultValue))
            defaultValue = resourceKey;
        try
        {
            CultureInfo culture = CultureInfo.GetCultureInfo(language);
            string displayName = resourceManager.GetString(resourceKey, culture);
            return !string.IsNullOrEmpty(displayName) ? displayName : defaultValue;
        }
        catch // any, not only CultureNotFoundException
        {
            return defaultValue;
        }
    }

Avec l'extension GetDescription également avec le paramètre de langue:

            bool hasLanguage = !string.IsNullOrEmpty(language);
            if (hasLanguage)
            {
                var attribute = (LocalizedDescriptionAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(LocalizedDescriptionAttribute));
                if (attribute != null)
                {
                    description = attribute.GetDescription(language);
                }
                else
                    hasLanguage = false;
            }
            if (!hasLanguage)
            {
                var attribute = (DescriptionAttribute)Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute));
                if (attribute != null)
                {
                    description = attribute.Description;
                }
            }

Et finalement, je préfère éviter toute chaîne dans l'attribut utilisation, en utilisant nameof.

public enum QualityPersonInfo
{
    Ok = 0,
    [LocalizedDescription(nameof(QualityStrings.P1), typeof(QualityStrings))]
    Duplicate = 1,
    [LocalizedDescription(nameof(QualityStrings.P2), typeof(QualityStrings))]
    IdMissing = 2,
}

, que j'utilise dans mon code comme suit:

 QualityPersonInfo status = QualityPersonInfo.IdMissing; 
 var description = status.GetDescription("ch-DE");
0
répondu EricBDev 2017-03-16 16:12:09
public enum RoleEnum
{
    Administrator = 4,
    Official = 1,
    Trader = 3,
    HeadOfOffice = 2
}
public static class RoleEnumExtension
{
    private static readonly ResourceManager Resource =
        new ResourceManager("Project.CommonResource", typeof(CommonResource).Assembly);

    public static string Display(this RoleEnum role)
    {
        return Resource.GetString("RoleType_" + role);
    }
}

Vous pouvez l'utiliser comme

RoleEnum.Administrator.Display()

J'espère que cela aidera quelqu'un

0
répondu tech-gayan 2017-10-04 07:37:57

Je l'utilise actuellement, j'espère que ça aide!:

    /// <summary>
    ///  Retrieves a translated value from an enumerated list.
    /// </summary>
    /// <param name="value">Enum</param>
    /// <param name="resource">string</param>
    /// <returns>string</returns>
    protected string GetTranslatedEnum(Enum value, string resource)
    {
        string path = String.Format("Resources.{0}", resource);

        ResourceManager resources = new ResourceManager(path, global::System.Reflection.Assembly.Load("App_GlobalResources"));

        if (resources != null) {
            return resources.GetString(value.ToString());
        } else {
            return value.ToString();
        }
    }

Créé un .fichier resx nommé " App_GlobalResources\ProductNames.resx".

Utilisation:

// Convert the ProductId integer on the item to its Enum equivalent.
Products product = (Products) item.ProductId;

string productName = this.GetTranslatedEnum(product, "ProductNames");
0
répondu Steve Bauman 2018-06-26 19:45:27