From 3973ea1db94f81b8485fe192fee57e333790e7ab Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 30 Dec 2022 18:37:46 +0800 Subject: [PATCH] Add `AbpEnumLocalizer`. --- .../Form/AbpSelectTagHelperService.cs | 25 +++---- .../Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs | 3 +- .../Components/ObjectExtending/EnumHelper.cs | 1 + .../ExtensionPropertyComponentBase.cs | 4 ++ .../SelectExtensionProperty.razor.cs | 2 +- .../Volo/Abp/Localization/AbpEnumLocalizer.cs | 67 +++++++++++++++++++ .../AbpInternalLocalizationHelper.cs | 4 +- .../Abp/Localization/IAbpEnumLocalizer.cs | 11 +++ .../Localization/AbpEnumLocalizer_Tests.cs | 47 +++++++++++++ .../Localization/AbpLocalizationTestModule.cs | 6 +- .../TestResources/Base/Validation/en.json | 9 ++- .../Localization/TestResources/Source/en.json | 9 ++- 12 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpEnumLocalizer.cs create mode 100644 framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpEnumLocalizer_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index e38d74287c..9e60cbc75f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -22,17 +22,20 @@ public class AbpSelectTagHelperService : AbpTagHelperService private readonly HtmlEncoder _encoder; private readonly IAbpTagHelperLocalizer _tagHelperLocalizer; private readonly IStringLocalizerFactory _stringLocalizerFactory; + private readonly IAbpEnumLocalizer _abpEnumLocalizer; public AbpSelectTagHelperService( IHtmlGenerator generator, HtmlEncoder encoder, IAbpTagHelperLocalizer tagHelperLocalizer, - IStringLocalizerFactory stringLocalizerFactory) + IStringLocalizerFactory stringLocalizerFactory, + IAbpEnumLocalizer abpEnumLocalizer) { _generator = generator; _encoder = encoder; _tagHelperLocalizer = tagHelperLocalizer; _stringLocalizerFactory = stringLocalizerFactory; + _abpEnumLocalizer = abpEnumLocalizer; } public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) @@ -264,24 +267,12 @@ public class AbpSelectTagHelperService : AbpTagHelperService foreach (var enumValue in enumType.GetEnumValues()) { - var memberName = enumType.GetEnumName(enumValue); - var localizedMemberName = AbpInternalLocalizationHelper.LocalizeWithFallback( + var localizedMemberName = _abpEnumLocalizer.GetString(enumType, enumValue, new[] { - containerLocalizer, - _stringLocalizerFactory.CreateDefaultOrNull() - }, - new[] - { - $"Enum:{enumType.Name}.{enumValue}", - $"Enum:{enumType.Name}.{memberName}", - $"{enumType.Name}.{enumValue}", - $"{enumType.Name}.{memberName}", - memberName - }, - memberName - ); - + containerLocalizer, + _stringLocalizerFactory.CreateDefaultOrNull() + }); selectItems.Add(new SelectListItem { Value = enumValue.ToString(), diff --git a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs index 500a3dfd86..1e3cf13549 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs @@ -176,6 +176,7 @@ public abstract class AbpCrudPageBase< { [Inject] protected TAppService AppService { get; set; } [Inject] protected IStringLocalizer UiLocalizer { get; set; } + [Inject] public IAbpEnumLocalizer AbpEnumLocalizer { get; set; } protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount; @@ -626,7 +627,7 @@ public abstract class AbpCrudPageBase< if (propertyInfo.Type.IsEnum) { column.ValueConverter = (val) => - EnumHelper.GetLocalizedMemberName(propertyInfo.Type, val.As().ExtraProperties[propertyInfo.Name], StringLocalizerFactory); + AbpEnumLocalizer.GetString(propertyInfo.Type, val.As().ExtraProperties[propertyInfo.Name], new IStringLocalizer[]{ StringLocalizerFactory.CreateDefaultOrNull() }); } yield return column; diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs index 0ec828662f..925476ae77 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs @@ -10,6 +10,7 @@ namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; public static class EnumHelper { + [Obsolete("Use IAbpEnumLocalizer instead.")] public static string GetLocalizedMemberName(Type enumType, object value, IStringLocalizerFactory stringLocalizerFactory) { var memberName = enumType.GetEnumName(value); diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs index 4408741fef..b2a5c1e48d 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionPropertyComponentBase.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Data; +using Volo.Abp.Localization; using Volo.Abp.ObjectExtending; namespace Volo.Abp.BlazoriseUI.Components.ObjectExtending; @@ -17,6 +18,9 @@ public abstract class ExtensionPropertyComponentBase : O [Inject] public IStringLocalizerFactory StringLocalizerFactory { get; set; } + [Inject] + public IAbpEnumLocalizer AbpEnumLocalizer { get; set; } + [Inject] public IValidationMessageLocalizerAttributeFinder ValidationMessageLocalizerAttributeFinder { get; set; } diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs index ddc00a4c8b..32bb53c0fa 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/SelectExtensionProperty.razor.cs @@ -30,7 +30,7 @@ public partial class SelectExtensionProperty selectItems.Add(new SelectItem { Value = (int)enumValue, - Text = EnumHelper.GetLocalizedMemberName(PropertyInfo.Type, enumValue, StringLocalizerFactory) + Text = AbpEnumLocalizer.GetString(PropertyInfo.Type, enumValue, new []{ StringLocalizerFactory.CreateDefaultOrNull() }) }); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs new file mode 100644 index 0000000000..5ff5b27669 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Localization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization; + +public class AbpEnumLocalizer : IAbpEnumLocalizer, ISingletonDependency +{ + protected readonly IStringLocalizerFactory StringLocalizerFactory; + + public AbpEnumLocalizer(IStringLocalizerFactory stringLocalizerFactory) + { + StringLocalizerFactory = stringLocalizerFactory; + } + + public virtual string GetString(Type enumType, object enumValue) + { + return GetStringInternal(enumType, enumValue, StringLocalizerFactory.CreateDefaultOrNull()); + } + + public virtual string GetString(Type enumType, object enumValue, params IStringLocalizer[] specifyLocalizers) + { + return GetStringInternal(enumType, enumValue, specifyLocalizers); + } + + protected virtual string GetStringInternal(Type enumType, object enumValue, params IStringLocalizer[] specifyLocalizers) + { + var memberName = enumType.GetEnumName(enumValue); + var localizedString = GetStringOrNull( + specifyLocalizers, + new[] + { + $"Enum:{enumType.Name}.{enumValue}", + $"Enum:{enumType.Name}.{memberName}", + $"{enumType.Name}.{enumValue}", + $"{enumType.Name}.{memberName}", + memberName + } + ); + + return localizedString ?? memberName; + } + + protected virtual string GetStringOrNull(IStringLocalizer[] localizers, IEnumerable keys) + { + foreach (var key in keys) + { + foreach (var l in localizers) + { + if (l == null) + { + continue; + } + + var localizedString = l[key]; + if (!localizedString.ResourceNotFound) + { + return localizedString.Value; + } + } + } + + return null; + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs index 5386ea362e..f697ba1344 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpInternalLocalizationHelper.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Localization; +using System; +using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; @@ -22,6 +23,7 @@ public static class AbpInternalLocalizationHelper /// Return value if none of the localizers has none of the keys. /// /// + [Obsolete("Use IAbpEnumLocalizer instead.")] public static string LocalizeWithFallback( IStringLocalizer[] localizers, string[] keys, diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpEnumLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpEnumLocalizer.cs new file mode 100644 index 0000000000..cb88667e1c --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpEnumLocalizer.cs @@ -0,0 +1,11 @@ +using System; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization; + +public interface IAbpEnumLocalizer +{ + string GetString(Type enumType, object enumValue); + + string GetString(Type enumType, object enumValue, IStringLocalizer[] specifyLocalizers); +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpEnumLocalizer_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpEnumLocalizer_Tests.cs new file mode 100644 index 0000000000..1571abff2f --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpEnumLocalizer_Tests.cs @@ -0,0 +1,47 @@ +using Microsoft.Extensions.Localization; +using Shouldly; +using Volo.Abp.Localization.TestResources.Base.Validation; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Localization; + +public class AbpEnumLocalizer_Tests : AbpIntegratedTest +{ + private readonly IAbpEnumLocalizer _enumLocalizer; + + public AbpEnumLocalizer_Tests() + { + _enumLocalizer = GetRequiredService(); + } + + [Fact] + public void GetString_Test() + { + using (CultureHelper.Use("en")) + { + _enumLocalizer.GetString(typeof(BookType), BookType.Undefined).ShouldBe("Undefined"); + _enumLocalizer.GetString(typeof(BookType), BookType.Adventure).ShouldBe("Adventure"); + _enumLocalizer.GetString(typeof(BookType), 0).ShouldBe("Undefined with value 0"); + _enumLocalizer.GetString(typeof(BookType), 1).ShouldBe("Adventure with value 1"); + _enumLocalizer.GetString(typeof(BookType), BookType.Biography).ShouldBe("Biography"); + + var specifyLocalizer = new[] + { + GetRequiredService().Create() + }; + _enumLocalizer.GetString(typeof(BookType), BookType.Undefined, specifyLocalizer).ShouldBe("Undefined from ValidationResource"); + _enumLocalizer.GetString(typeof(BookType), BookType.Adventure, specifyLocalizer).ShouldBe("Adventure from ValidationResource"); + _enumLocalizer.GetString(typeof(BookType), 0, specifyLocalizer).ShouldBe("Undefined with value 0 from ValidationResource"); + _enumLocalizer.GetString(typeof(BookType), 1, specifyLocalizer).ShouldBe("Adventure with value 1 from ValidationResource"); + _enumLocalizer.GetString(typeof(BookType), BookType.Biography, specifyLocalizer).ShouldBe("Biography from ValidationResource"); + } + } +} + +enum BookType +{ + Undefined, + Adventure, + Biography, +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs index 910e442968..32835cb8f4 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs @@ -19,6 +19,8 @@ public class AbpLocalizationTestModule : AbpModule Configure(options => { + options.DefaultResourceType = typeof(LocalizationTestResource); + options.Resources .Add("en") .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); @@ -35,8 +37,8 @@ public class AbpLocalizationTestModule : AbpModule options.Resources .Get() .AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); - + options.GlobalContributors.Add(); }); } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json index 6fd963947c..20f8bd4c69 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/Validation/en.json @@ -2,6 +2,11 @@ "culture": "en", "texts": { "ThisFieldIsRequired": "This field is required", - "MaxLenghtErrorMessage": "This field can be maximum of '{0}' chars" + "MaxLenghtErrorMessage": "This field can be maximum of '{0}' chars", + "Enum:BookType.Undefined": "Undefined from ValidationResource", + "Enum:BookType.0": "Undefined with value 0 from ValidationResource", + "BookType.Adventure": "Adventure from ValidationResource", + "BookType.1": "Adventure with value 1 from ValidationResource", + "Biography": "Biography from ValidationResource" } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json index e18b39d241..f0be979f98 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/en.json @@ -6,6 +6,11 @@ "CarPlural": "Cars", "MaxLenghtErrorMessage": "This field's length can be maximum of '{0}' chars", "Universe": "Universe", - "FortyTwo": "Forty Two" + "FortyTwo": "Forty Two", + "Enum:BookType.Undefined": "Undefined", + "Enum:BookType.0": "Undefined with value 0", + "BookType.Adventure": "Adventure", + "BookType.1": "Adventure with value 1", + "Biography": "Biography" } -} \ No newline at end of file +}