diff --git a/src/CommandLine/BaseAttribute.cs b/src/CommandLine/BaseAttribute.cs index e390e88c..bf179d78 100644 --- a/src/CommandLine/BaseAttribute.cs +++ b/src/CommandLine/BaseAttribute.cs @@ -12,8 +12,9 @@ public abstract class BaseAttribute : Attribute private int min; private int max; private object @default; - private string helpText; + private Infrastructure.LocalizableAttributeProperty helpText; private string metaValue; + private Type resourceType; /// /// Initializes a new instance of the class. @@ -22,8 +23,9 @@ protected internal BaseAttribute() { min = -1; max = -1; - helpText = string.Empty; + helpText = new Infrastructure.LocalizableAttributeProperty(nameof(HelpText)); metaValue = string.Empty; + resourceType = null; } /// @@ -90,7 +92,7 @@ public object Default /// public string HelpText { - get { return helpText; } + get { return helpText.Value; } set { if (value == null) @@ -98,7 +100,7 @@ public string HelpText throw new ArgumentNullException("value"); } - helpText = value; + helpText.Value = value; } } @@ -127,5 +129,18 @@ public bool Hidden get; set; } + + /// + /// Gets or sets the that contains the resources for . + /// + public Type ResourceType + { + get { return resourceType; } + set + { + resourceType = + helpText.ResourceType = value; + } + } } } diff --git a/src/CommandLine/CommandLine.csproj b/src/CommandLine/CommandLine.csproj index 8f829c9f..1f179fc5 100644 --- a/src/CommandLine/CommandLine.csproj +++ b/src/CommandLine/CommandLine.csproj @@ -84,6 +84,7 @@ + @@ -169,8 +170,16 @@ - - + + + + ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll + True + True + + + + ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll diff --git a/src/CommandLine/Infrastructure/LocalizableAttributeProperty.cs b/src/CommandLine/Infrastructure/LocalizableAttributeProperty.cs new file mode 100644 index 00000000..3e622918 --- /dev/null +++ b/src/CommandLine/Infrastructure/LocalizableAttributeProperty.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace CommandLine.Infrastructure +{ + internal class LocalizableAttributeProperty + { + private string _propertyName; + private string _value; + private Type _type; + private PropertyInfo _localizationPropertyInfo; + + public LocalizableAttributeProperty(string propertyName) + { + _propertyName = propertyName; + } + + public string Value + { + get { return GetLocalizedValue(); } + set + { + _localizationPropertyInfo = null; + _value = value; + } + } + + public Type ResourceType + { + set + { + _localizationPropertyInfo = null; + _type = value; + } + } + + private string GetLocalizedValue() + { + if (String.IsNullOrEmpty(_value) || _type == null) + return _value; + if (_localizationPropertyInfo == null) + { + // Static class IsAbstract +#if NETSTANDARD1_5 + if (!_type.GetTypeInfo().IsVisible) +#else + if (!_type.IsVisible) +#endif + throw new ArgumentException("Invalid resource type", _propertyName); + PropertyInfo propertyInfo = _type.GetProperty(_value, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static); + if (propertyInfo == null || !propertyInfo.CanRead || propertyInfo.PropertyType != typeof(string)) + throw new ArgumentException("Invalid resource property name", _propertyName); + _localizationPropertyInfo = propertyInfo; + } + return (string)_localizationPropertyInfo.GetValue(null, null); + } + } + +} diff --git a/tests/CommandLine.Tests.Properties/CommandLine.Tests.Properties.csproj b/tests/CommandLine.Tests.Properties/CommandLine.Tests.Properties.csproj index cb2b6b96..9940f4c6 100644 --- a/tests/CommandLine.Tests.Properties/CommandLine.Tests.Properties.csproj +++ b/tests/CommandLine.Tests.Properties/CommandLine.Tests.Properties.csproj @@ -58,12 +58,12 @@ - + <__paket__xunit_runner_visualstudio_props>net20\xunit.runner.visualstudio - + <__paket__xunit_runner_visualstudio_props>portable-net45+win8+wp8+wpa81\xunit.runner.visualstudio @@ -94,7 +94,7 @@ <__paket__xunit_core_props>Xamarin.iOS\xunit.core - + <__paket__xunit_core_props>monoandroid\xunit.core @@ -109,7 +109,7 @@ <__paket__xunit_core_props>portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core - + <__paket__xunit_core_props>portable-win81+wpa81\xunit.core <__paket__xunit_core_targets>portable-win81+wpa81\xunit.core @@ -137,7 +137,7 @@ --> - + ..\..\packages\FluentAssertions\lib\monoandroid\FluentAssertions.Core.dll @@ -169,7 +169,7 @@ - + ..\..\packages\FluentAssertions\lib\net45\FluentAssertions.dll @@ -183,7 +183,7 @@ - + ..\..\packages\FluentAssertions\lib\portable-net40+sl5+win8+wp8+wpa81\FluentAssertions.dll @@ -197,7 +197,7 @@ - + ..\..\packages\FluentAssertions\lib\portable-win81+wpa81\FluentAssertions.dll @@ -255,7 +255,7 @@ - + ..\..\packages\FsCheck\lib\net45\FsCheck.dll @@ -264,7 +264,7 @@ - + ..\..\packages\FsCheck\lib\portable-net45+netcore45\FsCheck.dll @@ -302,7 +302,7 @@ - + ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll @@ -311,7 +311,7 @@ - + ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll @@ -349,7 +349,7 @@ - + ..\..\packages\xunit.abstractions\lib\net35\xunit.abstractions.dll @@ -358,7 +358,7 @@ - + ..\..\packages\xunit.abstractions\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll @@ -369,7 +369,7 @@ - + ..\..\packages\xunit.assert\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll @@ -380,7 +380,7 @@ - + ..\..\packages\xunit.extensibility.core\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll diff --git a/tests/CommandLine.Tests/CommandLine.Tests.csproj b/tests/CommandLine.Tests/CommandLine.Tests.csproj index f96b4e2e..1d53d813 100644 --- a/tests/CommandLine.Tests/CommandLine.Tests.csproj +++ b/tests/CommandLine.Tests/CommandLine.Tests.csproj @@ -73,6 +73,7 @@ + @@ -143,12 +144,12 @@ - + <__paket__xunit_runner_visualstudio_props>net20\xunit.runner.visualstudio - + <__paket__xunit_runner_visualstudio_props>portable-net45+win8+wp8+wpa81\xunit.runner.visualstudio @@ -179,7 +180,7 @@ <__paket__xunit_core_props>Xamarin.iOS\xunit.core - + <__paket__xunit_core_props>monoandroid\xunit.core @@ -194,7 +195,7 @@ <__paket__xunit_core_props>portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core - + <__paket__xunit_core_props>portable-win81+wpa81\xunit.core <__paket__xunit_core_targets>portable-win81+wpa81\xunit.core @@ -220,7 +221,7 @@ --> - + ..\..\packages\FluentAssertions\lib\monoandroid\FluentAssertions.Core.dll @@ -252,7 +253,7 @@ - + ..\..\packages\FluentAssertions\lib\net45\FluentAssertions.dll @@ -266,7 +267,7 @@ - + ..\..\packages\FluentAssertions\lib\portable-net40+sl5+win8+wp8+wpa81\FluentAssertions.dll @@ -280,7 +281,7 @@ - + ..\..\packages\FluentAssertions\lib\portable-win81+wpa81\FluentAssertions.dll @@ -347,8 +348,16 @@ - - + + + + ..\..\packages\FSharp.Core\lib\net40\FSharp.Core.dll + True + True + + + + ..\..\packages\FSharp.Core\lib\portable-net45+netcore45\FSharp.Core.dll @@ -386,7 +395,7 @@ - + ..\..\packages\xunit.abstractions\lib\net35\xunit.abstractions.dll @@ -395,7 +404,7 @@ - + ..\..\packages\xunit.abstractions\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.abstractions.dll @@ -406,7 +415,7 @@ - + ..\..\packages\xunit.assert\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.assert.dll @@ -417,7 +426,7 @@ - + ..\..\packages\xunit.extensibility.core\lib\portable-net45+win+wpa81+wp80+monotouch+monoandroid+Xamarin.iOS\xunit.core.dll diff --git a/tests/CommandLine.Tests/Fakes/ResourceFakes.cs b/tests/CommandLine.Tests/Fakes/ResourceFakes.cs new file mode 100644 index 00000000..917d51bf --- /dev/null +++ b/tests/CommandLine.Tests/Fakes/ResourceFakes.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CommandLine.Tests.Fakes +{ + public static class StaticResource + { + public static string HelpText { get { return "Localized HelpText"; } } + } + + public class NonStaticResource + { + public static string HelpText { get { return "Localized HelpText"; } } + public static string WriteOnlyText { set { value?.ToString(); } } + private static string PrivateHelpText { get { return "Localized HelpText"; } } + } + + public class NonStaticResource_WithNonStaticProperty + { + public string HelpText { get { return "Localized HelpText"; } } + } + + internal class InternalResource + { + public static string HelpText { get { return "Localized HelpText"; } } + } + +} diff --git a/tests/CommandLine.Tests/Unit/BaseAttributeTests.cs b/tests/CommandLine.Tests/Unit/BaseAttributeTests.cs index 79d20c7b..72cf81b4 100644 --- a/tests/CommandLine.Tests/Unit/BaseAttributeTests.cs +++ b/tests/CommandLine.Tests/Unit/BaseAttributeTests.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; using Xunit; namespace CommandLine.Tests.Unit @@ -20,6 +16,37 @@ public static void Default(object defaultValue) Assert.Equal(defaultValue, baseAttribute.Default); } + [Theory] + [InlineData("", null, "")] + [InlineData("", typeof(Fakes.StaticResource), "")] + [InlineData("Help text", null, "Help text")] + [InlineData("HelpText", typeof(Fakes.StaticResource), "Localized HelpText")] + [InlineData("HelpText", typeof(Fakes.NonStaticResource), "Localized HelpText")] + public static void HelpText(string helpText, Type resourceType, string expected) + { + TestBaseAttribute baseAttribute = new TestBaseAttribute(); + baseAttribute.HelpText = helpText; + baseAttribute.ResourceType = resourceType; + + Assert.Equal(expected, baseAttribute.HelpText); + } + + [Theory] + [InlineData("HelpText", typeof(Fakes.NonStaticResource_WithNonStaticProperty))] + [InlineData("WriteOnlyText", typeof(Fakes.NonStaticResource))] + [InlineData("PrivateOnlyText", typeof(Fakes.NonStaticResource))] + [InlineData("HelpText", typeof(Fakes.InternalResource))] + public void ThrowsHelpText(string helpText, Type resourceType) + { + TestBaseAttribute baseAttribute = new TestBaseAttribute(); + baseAttribute.HelpText = helpText; + baseAttribute.ResourceType = resourceType; + + // Verify exception + Assert.Throws(() => baseAttribute.HelpText.ToString()); + } + + private class TestBaseAttribute : BaseAttribute { public TestBaseAttribute() @@ -27,5 +54,6 @@ public TestBaseAttribute() // Do nothing } } + } }