diff --git a/readme.md b/readme.md
index ff4bceb5f..17db87467 100644
--- a/readme.md
+++ b/readme.md
@@ -206,6 +206,22 @@ You can even configure the name of the property of attibute to use as descriptio
`Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"`
+If you need to provide localised descriptions you can use `DisplayAttribute` data annotation instead.
+
+```C#
+public enum EnumUnderTest
+{
+ [Display(Description = "EnumUnderTest_Member", ResourceType = typeof(Project.Resources))]
+ Member
+}
+```
+
+You will get:
+
+```C#
+EnumUnderTest.Member.Humanize() => "content" // from Project.Resources found under "EnumUnderTest_Member" resource key
+```
+
Hopefully this will help avoid littering enums with unnecessary attributes!
###Dehumanize Enums
diff --git a/release_notes.md b/release_notes.md
index e9d0f5ae4..053753f32 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -2,6 +2,7 @@
- [#320](https://github.com/MehdiK/Humanizer/pull/320): Fixed Dehumanize actually humanizing an already dehumanized string
- [#322](https://github.com/MehdiK/Humanizer/pull/322): DefaultFormatter.TimeSpanHumanize throws a more meaningful exception when called with TimeUnits larger than TimeUnit.Week
- [#314](https://github.com/MehdiK/Humanizer/pull/314): Added ByteRate class and supporting members to facilitate calculation of byte transfer rates
+ - [#333](https://github.com/MehdiK/Humanizer/pull/333): Added support to humanize enums from resource strings
[Commits](https://github.com/MehdiK/Humanizer/compare/v1.28.0...master)
diff --git a/src/Humanizer.Tests/DehumanizeToEnumTests.cs b/src/Humanizer.Tests/DehumanizeToEnumTests.cs
index 5faaa7d62..c6d1326cf 100644
--- a/src/Humanizer.Tests/DehumanizeToEnumTests.cs
+++ b/src/Humanizer.Tests/DehumanizeToEnumTests.cs
@@ -72,6 +72,20 @@ public void AllCapitalMembersAreReturnedAsIs()
Assert.Equal(EnumUnderTest.ALLCAPITALS, EnumUnderTest.ALLCAPITALS.ToString().DehumanizeTo(typeof(EnumUnderTest)));
}
+ [Fact]
+ public void HonorsDisplayAttribute()
+ {
+ Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo());
+ Assert.Equal(EnumUnderTest.MemberWithDisplayAttribute, EnumTestsResources.MemberWithDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest)));
+ }
+
+ [Fact]
+ public void HonorsLocalizedDisplayAttribute()
+ {
+ Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo());
+ Assert.Equal(EnumUnderTest.MemberWithLocalizedDisplayAttribute, EnumTestsResources.MemberWithLocalizedDisplayAttribute.DehumanizeTo(typeof(EnumUnderTest)));
+ }
+
struct DummyStructWithEnumInterfaces : IComparable, IFormattable, IConvertible
{
public int CompareTo(object obj)
diff --git a/src/Humanizer.Tests/EnumHumanizeTests.cs b/src/Humanizer.Tests/EnumHumanizeTests.cs
index c47d7c41b..c6554cecc 100644
--- a/src/Humanizer.Tests/EnumHumanizeTests.cs
+++ b/src/Humanizer.Tests/EnumHumanizeTests.cs
@@ -55,5 +55,17 @@ public void AllCapitalMembersAreReturnedAsIs()
{
Assert.Equal(EnumUnderTest.ALLCAPITALS.ToString(), EnumUnderTest.ALLCAPITALS.Humanize());
}
+
+ [Fact]
+ public void HonorsDisplayAttribute()
+ {
+ Assert.Equal(EnumTestsResources.MemberWithDisplayAttribute, EnumUnderTest.MemberWithDisplayAttribute.Humanize());
+ }
+
+ [Fact]
+ public void HonorsLocalizedDisplayAttribute()
+ {
+ Assert.Equal(EnumTestsResources.MemberWithLocalizedDisplayAttribute, EnumUnderTest.MemberWithLocalizedDisplayAttribute.Humanize());
+ }
}
}
\ No newline at end of file
diff --git a/src/Humanizer.Tests/EnumUnderTest.cs b/src/Humanizer.Tests/EnumUnderTest.cs
index 8f9423804..cdc5f8f50 100644
--- a/src/Humanizer.Tests/EnumUnderTest.cs
+++ b/src/Humanizer.Tests/EnumUnderTest.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
namespace Humanizer.Tests
{
@@ -16,7 +17,11 @@ public enum EnumUnderTest
[CustomProperty(EnumTestsResources.MemberWithCustomPropertyAttribute)]
MemberWithCustomPropertyAttribute,
MemberWithoutDescriptionAttribute,
- ALLCAPITALS
+ ALLCAPITALS,
+ [Display(Description = EnumTestsResources.MemberWithDisplayAttribute)]
+ MemberWithDisplayAttribute,
+ [Display(Description = "MemberWithLocalizedDisplayAttribute", ResourceType = typeof(EnumTestsResources))]
+ MemberWithLocalizedDisplayAttribute
}
public class EnumTestsResources
@@ -29,6 +34,8 @@ public class EnumTestsResources
public const string MemberWithoutDescriptionAttributeSentence = "Member without description attribute";
public const string MemberWithoutDescriptionAttributeTitle = "Member Without Description Attribute";
public const string MemberWithoutDescriptionAttributeLowerCase = "member without description attribute";
+ public const string MemberWithDisplayAttribute = "Description from Display attribute";
+ public static string MemberWithLocalizedDisplayAttribute { get { return "Localized description from Display attribute"; } }
}
public class ImposterDescriptionAttribute : Attribute
diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj
index 2d6937c42..dbfb88df9 100644
--- a/src/Humanizer.Tests/Humanizer.Tests.csproj
+++ b/src/Humanizer.Tests/Humanizer.Tests.csproj
@@ -43,6 +43,7 @@
..\packages\ApprovalUtilities.3.0.5\lib\net35\ApprovalUtilities.dll
+
diff --git a/src/Humanizer/EnumHumanizeExtensions.cs b/src/Humanizer/EnumHumanizeExtensions.cs
index f7cb3d584..b4f3ae7b8 100644
--- a/src/Humanizer/EnumHumanizeExtensions.cs
+++ b/src/Humanizer/EnumHumanizeExtensions.cs
@@ -10,6 +10,9 @@ namespace Humanizer
///
public static class EnumHumanizeExtensions
{
+ private const string DisplayAttributeTypeName = "System.ComponentModel.DataAnnotations.DisplayAttribute";
+ private const string DisplayAttributeGetDescriptionMethodName = "GetDescription";
+
private static readonly Func StringTypedProperty = p => p.PropertyType == typeof(string);
///
@@ -42,6 +45,12 @@ private static string GetCustomDescription(MemberInfo memberInfo)
foreach (var attr in attrs)
{
var attrType = attr.GetType();
+ if (attrType.FullName == DisplayAttributeTypeName)
+ {
+ var method = attrType.GetMethod(DisplayAttributeGetDescriptionMethodName);
+ if (method != null)
+ return method.Invoke(attr, new object[0]).ToString();
+ }
var descriptionProperty =
attrType.GetProperties()
.Where(StringTypedProperty)