From 3466e6b117d2b867fac58edbcab1727ce2221feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 11:37:39 +0300 Subject: [PATCH 01/10] Check enum value first for localization --- .../TagHelpers/Form/AbpSelectTagHelperService.cs | 1 + .../Components/ObjectExtending/EnumHelper.cs | 1 + 2 files changed, 2 insertions(+) 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 350898d41d..b6559b367a 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 @@ -273,6 +273,7 @@ public class AbpSelectTagHelperService : AbpTagHelperService }, new[] { + $"Enum:{enumType.Name}.{enumValue}", $"Enum:{enumType.Name}.{memberName}", $"{enumType.Name}.{memberName}", memberName diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs index 773e906640..dd461123b3 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs @@ -20,6 +20,7 @@ public static class EnumHelper }, new[] { + $"Enum:{enumType.Name}.{value}", $"Enum:{enumType.Name}.{memberName}", $"{enumType.Name}.{memberName}", memberName From 68292e461591eb857b50bc1d416b815b968559b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 11:43:51 +0300 Subject: [PATCH 02/10] Added enum.value syntax too. --- .../TagHelpers/Form/AbpSelectTagHelperService.cs | 1 + .../Components/ObjectExtending/EnumHelper.cs | 1 + 2 files changed, 2 insertions(+) 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 b6559b367a..e38d74287c 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 @@ -275,6 +275,7 @@ public class AbpSelectTagHelperService : AbpTagHelperService { $"Enum:{enumType.Name}.{enumValue}", $"Enum:{enumType.Name}.{memberName}", + $"{enumType.Name}.{enumValue}", $"{enumType.Name}.{memberName}", memberName }, diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs index dd461123b3..0ec828662f 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/EnumHelper.cs @@ -22,6 +22,7 @@ public static class EnumHelper { $"Enum:{enumType.Name}.{value}", $"Enum:{enumType.Name}.{memberName}", + $"{enumType.Name}.{value}", $"{enumType.Name}.{memberName}", memberName }, From 244be8c54a200a1a3b447d8bdbd5e7fd93dfdb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 11:50:49 +0300 Subject: [PATCH 03/10] Update tutorial for enum change --- docs/en/Tutorials/Part-10.md | 2 +- docs/en/Tutorials/Part-2.md | 24 ++++++++++++------------ docs/en/Tutorials/Part-3.md | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/en/Tutorials/Part-10.md b/docs/en/Tutorials/Part-10.md index a384583175..b2ce526bd5 100644 --- a/docs/en/Tutorials/Part-10.md +++ b/docs/en/Tutorials/Part-10.md @@ -725,7 +725,7 @@ Book list page change is trivial. Open the `Pages/Books/Index.js` in the `Acme.B title: l('Type'), data: "type", render: function (data) { - return l('Enum:BookType:' + data); + return l('Enum:BookType.' + data); } }, ... diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md index 4f056523ce..91b0453b53 100644 --- a/docs/en/Tutorials/Part-2.md +++ b/docs/en/Tutorials/Part-2.md @@ -132,22 +132,22 @@ Open the `en.json` (*the English translations*) file and change the content as s "CreationTime": "Creation time", "AreYouSure": "Are you sure?", "AreYouSureToDelete": "Are you sure you want to delete this item?", - "Enum:BookType.Undefined": "Undefined", - "Enum:BookType.Adventure": "Adventure", - "Enum:BookType.Biography": "Biography", - "Enum:BookType.Dystopia": "Dystopia", - "Enum:BookType.Fantastic": "Fantastic", - "Enum:BookType.Horror": "Horror", - "Enum:BookType.Science": "Science", - "Enum:BookType.ScienceFiction": "Science fiction", - "Enum:BookType.Poetry": "Poetry" + "Enum:BookType.0": "Undefined", + "Enum:BookType.1": "Adventure", + "Enum:BookType.2": "Biography", + "Enum:BookType.3": "Dystopia", + "Enum:BookType.4": "Fantastic", + "Enum:BookType.5": "Horror", + "Enum:BookType.6": "Science", + "Enum:BookType.7": "Science fiction", + "Enum:BookType.8": "Poetry" } } ```` * Localization key names are arbitrary. You can set any name. We prefer some conventions for specific text types; * Add `Menu:` prefix for menu items. - * Use `Enum:.` or `.` or `` naming convention to localize the enum members. When you do it like that, ABP can automatically localize the enums in some proper cases. + * Use `Enum:.` or `.` naming convention to localize the enum members. When you do it like that, ABP can automatically localize the enums in some proper cases. If a text is not defined in the localization file, it **falls back** to the localization key (as ASP.NET Core's standard behavior). @@ -279,7 +279,7 @@ $(function () { title: l('Type'), data: "type", render: function (data) { - return l('Enum:BookType:' + data); + return l('Enum:BookType.' + data); } }, { @@ -517,7 +517,7 @@ Open the `/src/app/book/book.component.html` and replace the content as shown be - {%{{{ '::Enum:BookType:' + row.type | abpLocalization }}}%} + {%{{{ '::Enum:BookType.' + row.type | abpLocalization }}}%} diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md index dc92eec337..bc5e899f2d 100644 --- a/docs/en/Tutorials/Part-3.md +++ b/docs/en/Tutorials/Part-3.md @@ -232,7 +232,7 @@ $(function () { title: l('Type'), data: "type", render: function (data) { - return l('Enum:BookType:' + data); + return l('Enum:BookType.' + data); } }, { @@ -418,7 +418,7 @@ $(function () { title: l('Type'), data: "type", render: function (data) { - return l('Enum:BookType:' + data); + return l('Enum:BookType.' + data); } }, { @@ -556,7 +556,7 @@ $(function () { title: l('Type'), data: "type", render: function (data) { - return l('Enum:BookType:' + data); + return l('Enum:BookType.' + data); } }, { From 81e88a28c6d14b7f92395868cf4f8faeecd58479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 11:53:15 +0300 Subject: [PATCH 04/10] Update Module-Entity-Extensions.md --- docs/en/Module-Entity-Extensions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/Module-Entity-Extensions.md b/docs/en/Module-Entity-Extensions.md index 1a3c318c6b..47436a7dd9 100644 --- a/docs/en/Module-Entity-Extensions.md +++ b/docs/en/Module-Entity-Extensions.md @@ -312,12 +312,14 @@ An enum properties is shown as combobox (select) in the create/edit forms: Enum member name is shown on the table and forms by default. If you want to localize it, just create a new entry on your [localization](https://docs.abp.io/en/abp/latest/Localization) file: ````json -"UserType.SuperUser": "Super user" +"Enum:UserType.0": "Super user" ```` One of the following names can be used as the localization key: +* `Enum:UserType.0` * `Enum:UserType.SuperUser` +* `UserType.0` * `UserType.SuperUser` * `SuperUser` From 7dbe75a94d56598953aa9a96b6738439108683c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 12:09:04 +0300 Subject: [PATCH 05/10] Update Forms-Validation.md --- docs/en/UI/AspNetCore/Forms-Validation.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/en/UI/AspNetCore/Forms-Validation.md b/docs/en/UI/AspNetCore/Forms-Validation.md index 48d7937013..257752a517 100644 --- a/docs/en/UI/AspNetCore/Forms-Validation.md +++ b/docs/en/UI/AspNetCore/Forms-Validation.md @@ -201,6 +201,27 @@ In this case, you can add an entry to the localization file using the key `MyNam > If you use the `[DisplayName]` but not add a corresponding entity to the localization file, then ABP Framework shows the given key as the field name, `MyNameKey` for this case. So, it provides a way to specify a hard coded display name even if you don't need to use the localization system. +### Enum Localization + +Enum members are also automatically localized wherever possible. For example, when we added `` to the form (like we did in the *ABP Form Tag Helpers* section), ABP can automatically fill the localized names of Enum members. To enabled it, you should define the localized values in your localization JSON file. Example entries for the `Genre` Enum defined in the *ABP Form Tag Helpers* section: + +````json +"Enum:Genre.0": "Classic movie", +"Enum:Genre.1": "Action movie", +"Enum:Genre.2": "Fiction", +"Enum:Genre.3": "Fantasy", +"Enum:Genre.4": "Animation/Cartoon" +```` + +You can use one of the following syntaxes for the localization keys: + +* `Enum:.` +* `.` + +> Remember that if you don't specify values for your Enum, the values will be ordered, starting from `0`. + +> MVC tag helpers also support using Enum member names instead of values (so, you can define `"Enum:Genre.Action"` instead of `"Enum:Genre.1"`, for example), but it is not suggested. Because, when you serialize Enum properties to JSON and send to clients, default serializer uses Enum values instead of Enum names. So, the Enum name won't be available to clients, and it will be a problem if you want to use the same localization values on the client side. + ## See Also * [Server Side Validation](../../Validation.md) From 3973ea1db94f81b8485fe192fee57e333790e7ab Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 30 Dec 2022 18:37:46 +0800 Subject: [PATCH 06/10] 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 +} From b9e531ed0c8343c66aaf9eb773929cf38e7779c5 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 30 Dec 2022 18:51:34 +0800 Subject: [PATCH 07/10] Add `AbpEnumLocalizerExtensions`. --- .../AbpEnumLocalizerExtensions.cs | 19 ++++++++++++++++++ .../Localization/AbpEnumLocalizer_Tests.cs | 20 +++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizerExtensions.cs diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizerExtensions.cs new file mode 100644 index 0000000000..796ba0da9d --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizerExtensions.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization; + +public static class AbpEnumLocalizerExtensions +{ + public static string GetString(this IAbpEnumLocalizer abpEnumLocalizer, object enumValue) + where TEnum : Enum + { + return abpEnumLocalizer.GetString(typeof(TEnum), enumValue); + } + + public static string GetString(this IAbpEnumLocalizer abpEnumLocalizer, object enumValue, IStringLocalizer[] specifyLocalizers) + where TEnum : Enum + { + return abpEnumLocalizer.GetString(typeof(TEnum), enumValue, 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 index 1571abff2f..c53236809f 100644 --- 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 @@ -20,21 +20,21 @@ public class AbpEnumLocalizer_Tests : AbpIntegratedTest(BookType.Undefined).ShouldBe("Undefined"); + _enumLocalizer.GetString(BookType.Adventure).ShouldBe("Adventure"); + _enumLocalizer.GetString(0).ShouldBe("Undefined with value 0"); + _enumLocalizer.GetString(1).ShouldBe("Adventure with value 1"); + _enumLocalizer.GetString(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"); + _enumLocalizer.GetString(BookType.Undefined, specifyLocalizer).ShouldBe("Undefined from ValidationResource"); + _enumLocalizer.GetString(BookType.Adventure, specifyLocalizer).ShouldBe("Adventure from ValidationResource"); + _enumLocalizer.GetString(0, specifyLocalizer).ShouldBe("Undefined with value 0 from ValidationResource"); + _enumLocalizer.GetString(1, specifyLocalizer).ShouldBe("Adventure with value 1 from ValidationResource"); + _enumLocalizer.GetString(BookType.Biography, specifyLocalizer).ShouldBe("Biography from ValidationResource"); } } } From 64cdd67b2df65e561d4633839c42ec486a21bdd3 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 30 Dec 2022 18:54:17 +0800 Subject: [PATCH 08/10] Update AbpEnumLocalizer.cs --- .../Volo/Abp/Localization/AbpEnumLocalizer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs index 5ff5b27669..7019137c24 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.Localization; using Volo.Abp.DependencyInjection; @@ -8,16 +7,16 @@ namespace Volo.Abp.Localization; public class AbpEnumLocalizer : IAbpEnumLocalizer, ISingletonDependency { - protected readonly IStringLocalizerFactory StringLocalizerFactory; + protected readonly IStringLocalizer StringLocalizer; public AbpEnumLocalizer(IStringLocalizerFactory stringLocalizerFactory) { - StringLocalizerFactory = stringLocalizerFactory; + StringLocalizer = stringLocalizerFactory.CreateDefaultOrNull(); } public virtual string GetString(Type enumType, object enumValue) { - return GetStringInternal(enumType, enumValue, StringLocalizerFactory.CreateDefaultOrNull()); + return GetStringInternal(enumType, enumValue, StringLocalizer); } public virtual string GetString(Type enumType, object enumValue, params IStringLocalizer[] specifyLocalizers) From 88bf9eadff12ce0a5b85247ecf42a5f2cf1049ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 30 Dec 2022 14:21:38 +0300 Subject: [PATCH 09/10] Change part-1 and 7 for ef core migration usage --- docs/en/Tutorials/Part-1.md | 2 +- docs/en/Tutorials/Part-7.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index aefed89da7..0e09804ed5 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -199,7 +199,7 @@ This will add a new migration class to the project: ![bookstore-efcore-migration](./images/bookstore-efcore-migration.png) -> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity -c BookStoreDbContext` and `Update-Database -Context BookStoreDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that `Acme.BookStore.EntityFrameworkCore` is the startup project in Visual Studio and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{end}} diff --git a/docs/en/Tutorials/Part-7.md b/docs/en/Tutorials/Part-7.md index 08c8636203..d60d030f13 100644 --- a/docs/en/Tutorials/Part-7.md +++ b/docs/en/Tutorials/Part-7.md @@ -90,7 +90,7 @@ You can apply changes to the database using the following command, in the same c dotnet ef database update ```` -> If you are using Visual Studio, you may want to use `Add-Migration Added_Authors -c BookStoreDbContext` and `Update-Database -Context BookStoreDbContext` commands in the *Package Manager Console (PMC)*. In this case, ensure that {{if UI=="MVC"}}`Acme.BookStore.Web`{{else if UI=="BlazorServer"}}`Acme.BookStore.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`Acme.BookStore.HttpApi.Host`{{end}} is the startup project and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. +> If you are using Visual Studio, you may want to use the `Add-Migration Created_Book_Entity` and `Update-Database` commands in the *Package Manager Console (PMC)*. In this case, ensure that `Acme.BookStore.EntityFrameworkCore` is the startup project in Visual Studio and `Acme.BookStore.EntityFrameworkCore` is the *Default Project* in PMC. {{else if DB=="Mongo"}} From 8b6ca78c649ef36fda8ffa0ced4fd2c6f9ceb8d8 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 31 Dec 2022 09:35:03 +0800 Subject: [PATCH 10/10] Update AbpEnumLocalizer.cs --- .../Volo/Abp/Localization/AbpEnumLocalizer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs index 7019137c24..3fc053da6a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpEnumLocalizer.cs @@ -5,18 +5,18 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Localization; -public class AbpEnumLocalizer : IAbpEnumLocalizer, ISingletonDependency +public class AbpEnumLocalizer : IAbpEnumLocalizer, ITransientDependency { - protected readonly IStringLocalizer StringLocalizer; + protected readonly IStringLocalizerFactory StringLocalizerFactory; public AbpEnumLocalizer(IStringLocalizerFactory stringLocalizerFactory) { - StringLocalizer = stringLocalizerFactory.CreateDefaultOrNull(); + StringLocalizerFactory = stringLocalizerFactory; } public virtual string GetString(Type enumType, object enumValue) { - return GetStringInternal(enumType, enumValue, StringLocalizer); + return GetStringInternal(enumType, enumValue, StringLocalizerFactory.CreateDefaultOrNull()); } public virtual string GetString(Type enumType, object enumValue, params IStringLocalizer[] specifyLocalizers)