From 7b4c0bc23ebf0ad3849058f222600722781c18b8 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Wed, 4 Jul 2018 11:05:22 +0300 Subject: [PATCH] Create IdentityResult localization system. Introduce ILocalizeErrorMessage interface. --- .../DefaultExceptionToErrorInfoConverter.cs | 19 +++++- .../AbpStringLocalizerFactoryExtensions.cs | 10 +++ .../Abp/ApplicationInitializationContext.cs | 3 +- .../ILocalizeErrorMessage.cs | 9 +++ .../Abp/Localization/LocalizationContext.cs | 20 ++++++ .../AbpIdentityApplicationContractsModule.cs | 4 +- .../Abp/Identity/IdentityAppServiceBase.cs | 14 +--- .../Abp/Identity/IdentityRoleAppService.cs | 9 +-- .../Abp/Identity/IdentityUserAppService.cs | 21 +++--- .../Identity/AbpIdentityResultExtensions.cs | 64 +++++++++++++++++++ .../Volo.Abp.Identity.Domain.csproj | 4 ++ .../Abp/Identity/AbpIdentityDomainModule.cs | 15 +++++ .../Identity/AbpIdentityResultException.cs | 38 +++++++++++ .../Abp/Identity/Localization/Domain/en.json | 7 ++ .../Abp/Identity/Localization/Domain/tr.json | 7 ++ .../AbpIdentityResultException_Tests.cs | 37 +++++++++++ 16 files changed, 250 insertions(+), 31 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/ILocalizeErrorMessage.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/Localization/LocalizationContext.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json create mode 100644 modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json create mode 100644 modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs index 009ddf37bf..512ec10f97 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Localization.Resources.AbpUi; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Volo.Abp.Authorization; @@ -10,6 +11,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; using Volo.Abp.ExceptionHandling; using Volo.Abp.Http; +using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.UI; using Volo.Abp.Validation; @@ -23,12 +25,15 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling protected ExceptionLocalizationOptions LocalizationOptions { get; } protected IStringLocalizerFactory StringLocalizerFactory { get; } protected IStringLocalizer L { get; } + protected IServiceProvider ServiceProvider { get; } public DefaultExceptionToErrorInfoConverter( IOptions localizationOptions, IStringLocalizerFactory stringLocalizerFactory, - IStringLocalizer abpUiStringLocalizer) + IStringLocalizer abpUiStringLocalizer, + IServiceProvider serviceProvider) { + ServiceProvider = serviceProvider; StringLocalizerFactory = stringLocalizerFactory; L = abpUiStringLocalizer; LocalizationOptions = localizationOptions.Value; @@ -101,6 +106,16 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling protected virtual void TryToLocalizeExceptionMessage(Exception exception, RemoteServiceErrorInfo errorInfo) { + if (exception is ILocalizeErrorMessage localizeErrorMessageException) + { + using (var scope = ServiceProvider.CreateScope()) + { + errorInfo.Message = localizeErrorMessageException.LocalizeMessage(new LocalizationContext(scope.ServiceProvider)); + } + + return; + } + if (!(exception is IHasErrorCode exceptionWithErrorCode)) { return; @@ -166,7 +181,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling aggException.InnerException is AbpValidationException || aggException.InnerException is EntityNotFoundException || aggException.InnerException is AbpAuthorizationException || - aggException.InnerException is BusinessException) + aggException.InnerException is IBusinessException) { return aggException.InnerException; } diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs new file mode 100644 index 0000000000..34931bfc95 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Extensions.Localization +{ + public static class AbpStringLocalizerFactoryExtensions + { + public static IStringLocalizer Create(this IStringLocalizerFactory localizerFactory) + { + return localizerFactory.Create(typeof(TResource)); + } + } +} diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/ApplicationInitializationContext.cs b/framework/src/Volo.Abp.Core/Volo/Abp/ApplicationInitializationContext.cs index 32b4fe53a4..064d551a59 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/ApplicationInitializationContext.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/ApplicationInitializationContext.cs @@ -1,9 +1,10 @@ using System; using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; namespace Volo.Abp { - public class ApplicationInitializationContext + public class ApplicationInitializationContext : IServiceProviderAccessor { public IServiceProvider ServiceProvider { get; set; } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/ILocalizeErrorMessage.cs b/framework/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/ILocalizeErrorMessage.cs new file mode 100644 index 0000000000..c7d6faca5a --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/ExceptionHandling/ILocalizeErrorMessage.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Localization; + +namespace Volo.Abp.ExceptionHandling +{ + public interface ILocalizeErrorMessage + { + string LocalizeMessage(LocalizationContext context); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/LocalizationContext.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/LocalizationContext.cs new file mode 100644 index 0000000000..0ea87a7169 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/LocalizationContext.cs @@ -0,0 +1,20 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization +{ + public class LocalizationContext : IServiceProviderAccessor + { + public IServiceProvider ServiceProvider { get; } + + public IStringLocalizerFactory LocalizerFactory { get; } + + public LocalizationContext(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + LocalizerFactory = ServiceProvider.GetRequiredService(); + } + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs index 7cadc77a85..b7deadb432 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/AbpIdentityApplicationContractsModule.cs @@ -30,7 +30,9 @@ namespace Volo.Abp.Identity services.Configure(options => { - options.Resources.Get().AddVirtualJson("/Volo/Abp/Identity/Localization/ApplicationContracts"); + options.Resources + .Get() + .AddVirtualJson("/Volo/Abp/Identity/Localization/ApplicationContracts"); }); services.AddAssemblyOf(); diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityAppServiceBase.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityAppServiceBase.cs index 3f1919323f..0c98e5b5dd 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityAppServiceBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityAppServiceBase.cs @@ -1,21 +1,9 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Identity; -using Volo.Abp.Application.Services; +using Volo.Abp.Application.Services; namespace Volo.Abp.Identity { public abstract class IdentityAppServiceBase : ApplicationService { - protected void CheckIdentityErrors(IdentityResult identityResult) - { - if (!identityResult.Succeeded) - { - //TODO: A better exception that can be shown on UI as localized? - throw new AbpException("Operation failed: " + identityResult.Errors.Select(e => $"[{e.Code}] {e.Description}").JoinAsString(", ")); - } - //identityResult.CheckErrors(LocalizationManager); //TODO: Get from old Abp - } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs index 0b59826963..b8cbcb67a9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Authorization.Permissions; @@ -70,7 +71,7 @@ namespace Volo.Abp.Identity { var role = new IdentityRole(GuidGenerator.Create(), input.Name, CurrentTenant.Id); - await _roleManager.CreateAsync(role); + (await _roleManager.CreateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(role); @@ -81,9 +82,9 @@ namespace Volo.Abp.Identity { var role = await _roleManager.GetByIdAsync(id); - await _roleManager.SetRoleNameAsync(role, input.Name); + (await _roleManager.SetRoleNameAsync(role, input.Name)).CheckErrors(); - await _roleManager.UpdateAsync(role); + (await _roleManager.UpdateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(role); @@ -98,7 +99,7 @@ namespace Volo.Abp.Identity return; } - await _roleManager.DeleteAsync(role); + (await _roleManager.DeleteAsync(role)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index 5946acbd79..4ee5644c87 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Volo.Abp.Application.Dtos; using Volo.Abp.Authorization.Permissions; using Volo.Abp.PermissionManagement; @@ -56,7 +57,7 @@ namespace Volo.Abp.Identity { var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.Email, CurrentTenant.Id); - CheckIdentityErrors(await _userManager.CreateAsync(user, input.Password)); + (await _userManager.CreateAsync(user, input.Password)).CheckErrors(); await UpdateUserByInput(user, input); await CurrentUnitOfWork.SaveChangesAsync(); @@ -69,9 +70,9 @@ namespace Volo.Abp.Identity { var user = await _userManager.GetByIdAsync(id); - CheckIdentityErrors(await _userManager.SetUserNameAsync(user, input.UserName)); + (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); await UpdateUserByInput(user, input); - CheckIdentityErrors(await _userManager.UpdateAsync(user)); + (await _userManager.UpdateAsync(user)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(user); @@ -86,14 +87,14 @@ namespace Volo.Abp.Identity return; } - CheckIdentityErrors(await _userManager.DeleteAsync(user)); + (await _userManager.DeleteAsync(user)).CheckErrors(); } [Authorize(IdentityPermissions.Users.Update)] public async Task UpdateRolesAsync(Guid id, IdentityUserUpdateRolesDto input) { var user = await _userManager.GetByIdAsync(id); - CheckIdentityErrors(await _userManager.SetRolesAsync(user, input.RoleNames)); + (await _userManager.SetRolesAsync(user, input.RoleNames)).CheckErrors(); await _userRepository.UpdateAsync(user); } @@ -114,14 +115,14 @@ namespace Volo.Abp.Identity private async Task UpdateUserByInput(IdentityUser user, IdentityUserCreateOrUpdateDtoBase input) { - CheckIdentityErrors(await _userManager.SetEmailAsync(user, input.Email)); - CheckIdentityErrors(await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber)); - CheckIdentityErrors(await _userManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled)); - CheckIdentityErrors(await _userManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)); + (await _userManager.SetEmailAsync(user, input.Email)).CheckErrors(); + (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors(); + (await _userManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled)).CheckErrors(); + (await _userManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)).CheckErrors(); if (input.RoleNames != null) { - CheckIdentityErrors(await _userManager.SetRolesAsync(user, input.RoleNames)); + (await _userManager.SetRolesAsync(user, input.RoleNames)).CheckErrors(); } } } diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs new file mode 100644 index 0000000000..298ae4fc01 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Microsoft/AspNetCore/Identity/AbpIdentityResultExtensions.cs @@ -0,0 +1,64 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Globalization; +using Microsoft.Extensions.Localization; +using Volo.Abp.Identity; +using Volo.Abp.Text.Formatting; + +namespace Microsoft.AspNetCore.Identity +{ + public static class AbpIdentityResultExtensions + { + public static void CheckErrors(this IdentityResult identityResult) + { + if (identityResult.Succeeded) + { + return; + } + + if (identityResult.Errors == null) + { + throw new ArgumentException("identityResult.Errors should not be null."); + } + + throw new AbpIdentityResultException(identityResult); + } + + public static string LocalizeErrors(this IdentityResult identityResult, IStringLocalizer localizer) + { + if (identityResult.Succeeded) + { + throw new ArgumentException("identityResult.Succeeded should be false in order to localize errors."); + } + + if (identityResult.Errors == null) + { + throw new ArgumentException("identityResult.Errors should not be null."); + } + + return identityResult.Errors.Select(err => LocalizeErrorMessage(err, localizer)).JoinAsString(", "); + } + + public static string LocalizeErrorMessage(this IdentityError error, IStringLocalizer localizer) + { + var key = $"Identity.{error.Code}"; + + var localizedString = localizer[key]; + + if (!localizedString.ResourceNotFound) + { + var englishLocalizedString = localizer.WithCulture(CultureInfo.GetCultureInfo("en"))[key]; + if (!englishLocalizedString.ResourceNotFound) + { + if (FormattedStringValueExtracter.IsMatch(error.Description, englishLocalizedString.Value, out var values)) + { + return string.Format(localizedString.Value, values.Cast().ToArray()); + } + } + } + + return localizer["Identity.Default"]; + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo.Abp.Identity.Domain.csproj b/modules/identity/src/Volo.Abp.Identity.Domain/Volo.Abp.Identity.Domain.csproj index 117b5d685c..a151c385b9 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo.Abp.Identity.Domain.csproj +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo.Abp.Identity.Domain.csproj @@ -13,6 +13,10 @@ + + + + diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs index ab10ec8412..26a7555b2c 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs @@ -3,10 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Volo.Abp.Domain; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement; using Volo.Abp.Settings; using Volo.Abp.Users; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Identity { @@ -29,6 +32,18 @@ namespace Volo.Abp.Identity options.DefinitionProviders.Add(); }); + services.Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + services.Configure(options => + { + options.Resources + .Get() + .AddVirtualJson("/Volo/Abp/Identity/Localization/Domain"); + }); + var identityBuilder = services.AddAbpIdentity(options => { options.User.RequireUniqueEmail = true; diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs new file mode 100644 index 0000000000..eb0aaccbcc --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityResultException.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Localization; +using Volo.Abp.ExceptionHandling; +using Volo.Abp.Identity.Localization; +using Volo.Abp.Localization; + +namespace Volo.Abp.Identity +{ + [Serializable] + public class AbpIdentityResultException : BusinessException, ILocalizeErrorMessage + { + public IdentityResult IdentityResult { get; } + + public AbpIdentityResultException([NotNull] IdentityResult identityResult) + : base( + code: $"Identity.{identityResult.Errors.First().Code}", + message: identityResult.Errors.Select(err => err.Description).JoinAsString(", ")) + { + IdentityResult = Check.NotNull(identityResult, nameof(identityResult)); + } + + public AbpIdentityResultException(SerializationInfo serializationInfo, StreamingContext context) + : base(serializationInfo, context) + { + + } + + public string LocalizeMessage(LocalizationContext context) + { + return IdentityResult.LocalizeErrors(context.LocalizerFactory.Create()); + } + } +} diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json new file mode 100644 index 0000000000..284850e093 --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "Identity.PasswordTooShort": "Passwords must be at least {0} characters.", + "Identity.PasswordRequiresNonAlphanumeric": "Passwords must have at least one non alphanumeric character." + } +} \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json new file mode 100644 index 0000000000..2e3462386f --- /dev/null +++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/Localization/Domain/tr.json @@ -0,0 +1,7 @@ +{ + "culture": "tr", + "texts": { + "Identity.PasswordTooShort": "Şifre en az {0} karakter uzunluğunda olmalı.", + "Identity.PasswordRequiresNonAlphanumeric": "Şifre en az bir sayı ya da harf olmayan karakter içermeli." + } +} \ No newline at end of file diff --git a/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs new file mode 100644 index 0000000000..6f81d8dcf5 --- /dev/null +++ b/modules/identity/test/Volo.Abp.Identity.Domain.Tests/Volo/Abp/Identity/AbpIdentityResultException_Tests.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Identity; +using Shouldly; +using Volo.Abp.Localization; +using Xunit; + +namespace Volo.Abp.Identity +{ + public class AbpIdentityResultException_Tests : AbpIdentityDomainTestBase + { + [Fact] + public void Should_Localize_Messages() + { + var exception = new AbpIdentityResultException( + IdentityResult.Failed( + new IdentityError + { + Code = "PasswordTooShort", + Description = "Passwords must be at least 6 characters." + }, + new IdentityError + { + Code = "PasswordRequiresNonAlphanumeric", + Description = "Passwords must have at least one non alphanumeric character." + } + ) + ); + + using (AbpCultureHelper.Use("tr")) + { + var localizeMessage = exception.LocalizeMessage(new LocalizationContext(ServiceProvider)); + + localizeMessage.ShouldContain("Şifre en az 6 karakter uzunluğunda olmalı."); + localizeMessage.ShouldContain("Şifre en az bir sayı ya da harf olmayan karakter içermeli."); + } + } + } +}