From f426ef443b21f7cdfd8ce52def401e20eaf512ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 22 Aug 2022 16:38:39 +0300 Subject: [PATCH 01/61] Use async overload. --- .../Themes/Basic/Layouts/Application.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 23c19c077d..539873ce4b 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -58,7 +58,7 @@ @(await Component.InvokeAsync())
- @RenderSection("content_toolbar", false) + @await RenderSectionAsync("content_toolbar", false)
@await Component.InvokeLayoutHookAsync(LayoutHooks.PageContent.First, StandardLayouts.Application) From aa08492ca1c67dc9e62559d28fd7196e47acb7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 22 Aug 2022 16:38:47 +0300 Subject: [PATCH 02/61] Remove old todo --- .../Mvc/ProxyScripting/ServiceProxyGenerationModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs index 20ac2e4cb8..3501882e3a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ProxyScripting/ServiceProxyGenerationModel.cs @@ -5,7 +5,7 @@ using Volo.Abp.Http.ProxyScripting.Generators.JQuery; namespace Volo.Abp.AspNetCore.Mvc.ProxyScripting; -public class ServiceProxyGenerationModel //: TODO: IShouldNormalize +public class ServiceProxyGenerationModel { public string Type { get; set; } From 24eda4c9ea11d01293f9e78cf402bed3b16fe621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 22 Aug 2022 17:08:15 +0300 Subject: [PATCH 03/61] Added initial AbpLocalizationScriptController --- .../Localization/AbpLanguagesController.cs | 2 + .../AbpLocalizationScriptController.cs | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs index dc44f12124..9f5d6aa530 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLanguagesController.cs @@ -3,12 +3,14 @@ using Microsoft.AspNetCore.Mvc; using System; using System.Threading.Tasks; using Microsoft.AspNetCore.RequestLocalization; +using Volo.Abp.Auditing; using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.Localization; [Area("Abp")] [Route("Abp/Languages/[action]")] +[DisableAuditing] [RemoteService(false)] [ApiExplorerSettings(IgnoreApi = true)] public class AbpLanguagesController : AbpController diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs new file mode 100644 index 0000000000..cd95768c3f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.Auditing; +using Volo.Abp.Localization; + +namespace Volo.Abp.AspNetCore.Mvc.Localization; + +[Area("Abp")] +[Route("Abp/LocalizationScript")] +[DisableAuditing] +[RemoteService(false)] +[ApiExplorerSettings(IgnoreApi = true)] +public class AbpLocalizationScriptController +{ + protected AbpLocalizationOptions LocalizationOptions { get; } + protected IStringLocalizerFactory StringLocalizerFactory { get; } + + public AbpLocalizationScriptController( + IOptions localizationOptions, + IStringLocalizerFactory stringLocalizerFactory) + { + StringLocalizerFactory = stringLocalizerFactory; + LocalizationOptions = localizationOptions.Value; + } + + [HttpGet] + [Route("{culture}")] + public async Task GetAsync(string culture) + { + // TODO: Should not get dynamic overloads, but how? What if we do? (Can be switched to host?) + using (CultureHelper.Use(culture)) + { + foreach (var resource in LocalizationOptions.Resources.Values) + { + var localizer = StringLocalizerFactory.Create(resource.ResourceType); + localizer.GetAllStrings(); + } + } + } +} \ No newline at end of file From 56d12224079ca7847a587807db73132f324f724c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 24 Aug 2022 15:23:30 +0300 Subject: [PATCH 04/61] Introduce IDistributedLocalizationStore. --- .../AbpApplicationConfigurationAppService.cs | 13 ++++++++++- .../DistributedLocalizationData.cs | 18 +++++++++++++++ .../DistributedLocalizationResourceData.cs | 22 +++++++++++++++++++ .../IDistributedLocalizationStore.cs | 10 +++++++++ .../NUllDistributedLocalizationStore.cs | 19 ++++++++++++++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 7bcc0b3cd9..5e48b42d0b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -17,6 +17,7 @@ using Volo.Abp.Data; using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; +using Volo.Abp.Localization.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Volo.Abp.Timing; @@ -42,6 +43,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp private readonly ITimezoneProvider _timezoneProvider; private readonly AbpClockOptions _abpClockOptions; private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; + private readonly IDistributedLocalizationStore _distributedLocalizationStore; private readonly AbpApplicationConfigurationOptions _options; public AbpApplicationConfigurationAppService( @@ -61,7 +63,8 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp ITimezoneProvider timezoneProvider, IOptions abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, - IOptions options) + IOptions options, + IDistributedLocalizationStore distributedLocalizationStore) { _serviceProvider = serviceProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; @@ -77,6 +80,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp _timezoneProvider = timezoneProvider; _abpClockOptions = abpClockOptions.Value; _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; + _distributedLocalizationStore = distributedLocalizationStore; _options = options.Value; _localizationOptions = localizationOptions.Value; _multiTenancyOptions = multiTenancyOptions.Value; @@ -227,6 +231,13 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp localizationConfig.Values[resource.ResourceName] = dictionary; } + var distributedLocalizationData = await _distributedLocalizationStore.GetAsync(); + + foreach (var resource in distributedLocalizationData.Resources) + { + localizationConfig.Values[resource.ResourceName] = resource.Texts; + } + localizationConfig.CurrentCulture = GetCurrentCultureInfo(); if (_localizationOptions.DefaultResourceType != null) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs new file mode 100644 index 0000000000..b8374f7119 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Localization.Distributed; + +public class DistributedLocalizationData +{ + public List Resources { get; } + + public DistributedLocalizationData() + { + Resources = new(); + } + + public DistributedLocalizationData(List resources) + { + Resources = Check.NotNull(resources, nameof(resources)); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs new file mode 100644 index 0000000000..bbb449a380 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Localization.Distributed; + +public class DistributedLocalizationResourceData +{ + public string ResourceName { get; } + + public Dictionary Texts { get; } + + public DistributedLocalizationResourceData(string resourceName) + { + ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + Texts = new(); + } + + public DistributedLocalizationResourceData(string resourceName, Dictionary texts) + { + ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + Texts = Check.NotNull(texts, nameof(texts)); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs new file mode 100644 index 0000000000..9dbf699838 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Localization.Distributed; + +public interface IDistributedLocalizationStore +{ + Task SaveAsync(); + + Task GetAsync(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs new file mode 100644 index 0000000000..51fae60544 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization.Distributed; + +public class NUllDistributedLocalizationStore : IDistributedLocalizationStore, ISingletonDependency +{ + private readonly DistributedLocalizationData _data = new(); + + public Task SaveAsync() + { + return Task.CompletedTask; + } + + public Task GetAsync() + { + return Task.FromResult(_data); + } +} \ No newline at end of file From 54b4a3859f24aa330afeb7dd26b1939dac6376fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 24 Aug 2022 15:35:29 +0300 Subject: [PATCH 05/61] Introduce AbpDistributedLocalizationOptions --- .../AbpApplicationConfigurationAppService.cs | 16 +++++++++++----- .../AbpDistributedLocalizationOptions.cs | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 5e48b42d0b..b9116b2e8d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -44,6 +44,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp private readonly AbpClockOptions _abpClockOptions; private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; private readonly IDistributedLocalizationStore _distributedLocalizationStore; + private readonly AbpDistributedLocalizationOptions _distributedLocalizationOptions; private readonly AbpApplicationConfigurationOptions _options; public AbpApplicationConfigurationAppService( @@ -64,7 +65,8 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp IOptions abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, IOptions options, - IDistributedLocalizationStore distributedLocalizationStore) + IDistributedLocalizationStore distributedLocalizationStore, + IOptions distributedLocalizationOptions) { _serviceProvider = serviceProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; @@ -81,6 +83,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp _abpClockOptions = abpClockOptions.Value; _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; _distributedLocalizationStore = distributedLocalizationStore; + _distributedLocalizationOptions = distributedLocalizationOptions.Value; _options = options.Value; _localizationOptions = localizationOptions.Value; _multiTenancyOptions = multiTenancyOptions.Value; @@ -231,11 +234,14 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp localizationConfig.Values[resource.ResourceName] = dictionary; } - var distributedLocalizationData = await _distributedLocalizationStore.GetAsync(); - - foreach (var resource in distributedLocalizationData.Resources) + if (_distributedLocalizationOptions.GetFromDistributedStore) { - localizationConfig.Values[resource.ResourceName] = resource.Texts; + var distributedLocalizationData = await _distributedLocalizationStore.GetAsync(); + + foreach (var resource in distributedLocalizationData.Resources) + { + localizationConfig.Values[resource.ResourceName] = resource.Texts; + } } localizationConfig.CurrentCulture = GetCurrentCultureInfo(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs new file mode 100644 index 0000000000..802bc15a06 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs @@ -0,0 +1,14 @@ +namespace Volo.Abp.Localization.Distributed; + +public class AbpDistributedLocalizationOptions +{ + /// + /// Default: true. + /// + public bool SaveToDistributedStore { get; set; } = true; + + /// + /// Default: false. + /// + public bool GetFromDistributedStore { get; set; } +} \ No newline at end of file From a812c5aa2005030aa46762421541bf5165c7120d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 24 Aug 2022 15:47:34 +0300 Subject: [PATCH 06/61] Save localizations on startup. --- .../Volo.Abp.Localization.csproj | 5 ++ .../Abp/Localization/AbpLocalizationModule.cs | 89 ++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj index 64352257f3..2aefa76caa 100644 --- a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj +++ b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj @@ -22,6 +22,11 @@ + + + + + diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 4ce8c32f88..6508976d85 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -1,6 +1,17 @@ -using Volo.Abp.Localization.Resources.AbpLocalization; +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Polly; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization.Distributed; +using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; using Volo.Abp.Settings; +using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Localization; @@ -8,10 +19,13 @@ namespace Volo.Abp.Localization; [DependsOn( typeof(AbpVirtualFileSystemModule), typeof(AbpSettingsModule), - typeof(AbpLocalizationAbstractionsModule) + typeof(AbpLocalizationAbstractionsModule), + typeof(AbpThreadingModule) )] public class AbpLocalizationModule : AbpModule { + private readonly CancellationTokenSource _cancellationTokenSource = new(); + public override void ConfigureServices(ServiceConfigurationContext context) { AbpStringLocalizerFactory.Replace(context.Services); @@ -33,4 +47,75 @@ public class AbpLocalizationModule : AbpModule .AddVirtualJson("/Localization/Resources/AbpLocalization"); }); } + + public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + await SaveLocalizationsAsync(context); + } + + public override Task OnApplicationShutdownAsync(ApplicationShutdownContext context) + { + _cancellationTokenSource.Cancel(); + return Task.CompletedTask; + } + + private async Task SaveLocalizationsAsync(ApplicationInitializationContext context) + { + var options = context + .ServiceProvider + .GetRequiredService>() + .Value; + + if (!options.SaveToDistributedStore) + { + return; + } + + var rootServiceProvider = context.ServiceProvider.GetRequiredService(); + + Task.Run(async () => + { + using var scope = rootServiceProvider.CreateScope(); + var applicationLifetime = scope.ServiceProvider.GetService(); + var cancellationTokenProvider = scope.ServiceProvider.GetRequiredService(); + var cancellationToken = applicationLifetime?.ApplicationStopping ?? _cancellationTokenSource.Token; + + try + { + using (cancellationTokenProvider.Use(cancellationToken)) + { + if (cancellationTokenProvider.Token.IsCancellationRequested) + { + return; + } + + await Policy + .Handle() + .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .ExecuteAsync(async _ => + { + try + { + // ReSharper disable once AccessToDisposedClosure + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope.ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // Polly will catch it + } + }, cancellationTokenProvider.Token); + } + } + // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) + catch { } + }); + } } From b24f1a8c1ea7b3f2d97f5b54945aed27d48189fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 24 Aug 2022 16:11:47 +0300 Subject: [PATCH 07/61] Lazy resolve IDistributedLocalizationStore --- .../AbpApplicationConfigurationAppService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index b9116b2e8d..b486536a1f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -43,7 +43,6 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp private readonly ITimezoneProvider _timezoneProvider; private readonly AbpClockOptions _abpClockOptions; private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; - private readonly IDistributedLocalizationStore _distributedLocalizationStore; private readonly AbpDistributedLocalizationOptions _distributedLocalizationOptions; private readonly AbpApplicationConfigurationOptions _options; @@ -65,7 +64,6 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp IOptions abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, IOptions options, - IDistributedLocalizationStore distributedLocalizationStore, IOptions distributedLocalizationOptions) { _serviceProvider = serviceProvider; @@ -82,7 +80,6 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp _timezoneProvider = timezoneProvider; _abpClockOptions = abpClockOptions.Value; _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; - _distributedLocalizationStore = distributedLocalizationStore; _distributedLocalizationOptions = distributedLocalizationOptions.Value; _options = options.Value; _localizationOptions = localizationOptions.Value; @@ -236,7 +233,10 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp if (_distributedLocalizationOptions.GetFromDistributedStore) { - var distributedLocalizationData = await _distributedLocalizationStore.GetAsync(); + var distributedLocalizationData = await this + .LazyServiceProvider + .LazyGetRequiredService() + .GetAsync(); foreach (var resource in distributedLocalizationData.Resources) { From c05a4b04b6f2301c6cf8776ae92f2f0cd685fb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 25 Aug 2022 10:06:19 +0300 Subject: [PATCH 08/61] Introduce IDistributedLocalizationStore.GetResourceNames --- .../Distributed/IDistributedLocalizationStore.cs | 2 ++ ...zationStore.cs => NullDistributedLocalizationStore.cs} | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) rename framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/{NUllDistributedLocalizationStore.cs => NullDistributedLocalizationStore.cs} (67%) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs index 9dbf699838..52f2b52cdb 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs @@ -7,4 +7,6 @@ public interface IDistributedLocalizationStore Task SaveAsync(); Task GetAsync(); + + Task GetResourceNames(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs similarity index 67% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs index 51fae60544..579b434a33 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NUllDistributedLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs @@ -1,9 +1,10 @@ +using System; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Localization.Distributed; -public class NUllDistributedLocalizationStore : IDistributedLocalizationStore, ISingletonDependency +public class NullDistributedLocalizationStore : IDistributedLocalizationStore, ISingletonDependency { private readonly DistributedLocalizationData _data = new(); @@ -16,4 +17,9 @@ public class NUllDistributedLocalizationStore : IDistributedLocalizationStore, I { return Task.FromResult(_data); } + + public Task GetResourceNames() + { + return Task.FromResult(Array.Empty()); + } } \ No newline at end of file From 614512d1f1a21c402af36ade1b52c75491705c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 10:11:17 +0300 Subject: [PATCH 09/61] Allow to create stringlocalizer by resource name instead of resource type --- .../AbpStringLocalizerFactoryExtensions.cs | 10 +++++- ...pport.cs => IAbpStringLocalizerFactory.cs} | 5 ++- .../Localization/AbpStringLocalizerFactory.cs | 18 +++++++++- .../AbpStringLocalizerFactory_Tests.cs | 34 +++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) rename framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/{IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs => IAbpStringLocalizerFactory.cs} (50%) create mode 100644 framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs index 896fdb6fa0..87c7a2a2be 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -4,7 +4,15 @@ public static class AbpStringLocalizerFactoryExtensions { public static IStringLocalizer CreateDefaultOrNull(this IStringLocalizerFactory localizerFactory) { - return (localizerFactory as IAbpStringLocalizerFactoryWithDefaultResourceSupport) + return (localizerFactory as IAbpStringLocalizerFactory) ?.CreateDefaultOrNull(); } + + public static IStringLocalizer CreateByResourceNameOrNull( + this IStringLocalizerFactory localizerFactory, + string resourceName) + { + return (localizerFactory as IAbpStringLocalizerFactory) + ?.CreateByResourceNameOrNull(resourceName); + } } diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs similarity index 50% rename from framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs rename to framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs index 0ab20aec4b..d9ae96c324 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs @@ -2,8 +2,11 @@ namespace Microsoft.Extensions.Localization; -public interface IAbpStringLocalizerFactoryWithDefaultResourceSupport +public interface IAbpStringLocalizerFactory { [CanBeNull] IStringLocalizer CreateDefaultOrNull(); + + [CanBeNull] + IStringLocalizer CreateByResourceNameOrNull([NotNull] string resourceName); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 3f47fd779d..5e8769ddab 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Options; namespace Volo.Abp.Localization; -public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLocalizerFactoryWithDefaultResourceSupport +public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLocalizerFactory { protected internal AbpLocalizationOptions AbpLocalizationOptions { get; } protected ResourceManagerStringLocalizerFactory InnerFactory { get; } @@ -37,6 +37,22 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return InnerFactory.Create(resourceType); } + return CreateInternal(resourceType, resource); + } + + public IStringLocalizer CreateByResourceNameOrNull(string resourceName) + { + var resource = AbpLocalizationOptions.Resources.GetOrNull(resourceName); + if (resource == null) + { + return null; + } + + return CreateInternal(resource.ResourceType, resource); + } + + private IStringLocalizer CreateInternal(Type resourceType, LocalizationResource resource) + { if (LocalizerCache.TryGetValue(resourceType, out var cacheItem)) { return cacheItem.Localizer; diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs new file mode 100644 index 0000000000..47db1bbd26 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs @@ -0,0 +1,34 @@ +using Microsoft.Extensions.Localization; +using Shouldly; +using Volo.Abp.DynamicProxy; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Localization; + +public class AbpStringLocalizerFactory_Tests : AbpIntegratedTest +{ + private readonly IStringLocalizerFactory _factory; + + public AbpStringLocalizerFactory_Tests() + { + _factory = GetRequiredService(); + } + + [Fact] + public void Factory_Type_Should_Be_AbpStringLocalizerFactory() + { + ProxyHelper.UnProxy(_factory).ShouldBeOfType(); + } + + [Fact] + public void Should_Create_Resource_By_Name() + { + using (CultureHelper.Use("en")) + { + var localizer = _factory.CreateByResourceNameOrNull("Test"); + localizer.ShouldNotBeNull(); + localizer["CarPlural"].Value.ShouldBe("Cars"); + } + } +} \ No newline at end of file From 6756fdd9ad74eb085de14e4af611af36320d89da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 11:24:15 +0300 Subject: [PATCH 10/61] Added extension method: CreateByResourceName --- .../AbpStringLocalizerFactoryExtensions.cs | 17 ++++++++++++++++- .../AbpStringLocalizerFactory_Tests.cs | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs index 87c7a2a2be..534a7e0eb9 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -1,4 +1,6 @@ -namespace Microsoft.Extensions.Localization; +using Volo.Abp; + +namespace Microsoft.Extensions.Localization; public static class AbpStringLocalizerFactoryExtensions { @@ -15,4 +17,17 @@ public static class AbpStringLocalizerFactoryExtensions return (localizerFactory as IAbpStringLocalizerFactory) ?.CreateByResourceNameOrNull(resourceName); } + + public static IStringLocalizer CreateByResourceName( + this IStringLocalizerFactory localizerFactory, + string resourceName) + { + var localizer = localizerFactory.CreateByResourceNameOrNull(resourceName); + if (localizer == null) + { + throw new AbpException("Couldn't find a localizer with given resource name: " + resourceName); + } + + return localizer; + } } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs index 47db1bbd26..d5e41a624a 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs @@ -31,4 +31,13 @@ public class AbpStringLocalizerFactory_Tests : AbpIntegratedTest( + () => _factory.CreateByResourceName("UnknownResourceName") + ); + } } \ No newline at end of file From 560ba6fce30f8544ac4246781bf5d85ed5a2de2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 13:41:04 +0300 Subject: [PATCH 11/61] Allow to work with non-typed localization resources --- .../AbpApplicationConfigurationAppService.cs | 13 +++-- .../AbpLocalizationScriptController.cs | 4 +- .../System/AbpObjectExtensions.cs | 2 + .../AbpStringLocalizerFactoryExtensions.cs | 6 ++- .../Abp/Localization/LocalizableString.cs | 54 ++++++++++++++++--- .../AbpDictionaryBasedStringLocalizer.cs | 5 +- .../Localization/AbpStringLocalizerFactory.cs | 41 +++++++++----- .../IExternalLocalizationStore.cs | 9 ++++ .../LocalizableStringSerializer.cs | 12 ++--- .../Abp/Localization/LocalizationResource.cs | 28 +++------- .../Localization/LocalizationResourceBase.cs | 25 +++++++++ .../LocalizationResourceDictionary.cs | 5 ++ .../LocalizationResourceExtensions.cs | 30 +++++++++-- .../NullExternalLocalizationStore.cs | 11 ++++ ...xtensionPropertyConfigurationExtensions.cs | 10 ++-- .../AbpStringLocalizerFactory_Tests.cs | 1 - .../LocalizableStringSerializer_Tests.cs | 2 +- 17 files changed, 187 insertions(+), 71 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index b486536a1f..97ae0c868d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -218,14 +218,13 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp foreach (var resource in _localizationOptions.Resources.Values) { var dictionary = new Dictionary(); - - var localizer = (IStringLocalizer) _serviceProvider.GetRequiredService( - typeof(IStringLocalizer<>).MakeGenericType(resource.ResourceType) - ); - - foreach (var localizedString in localizer.GetAllStrings()) + var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resource.ResourceName); + if (localizer != null) { - dictionary[localizedString.Name] = localizedString.Value; + foreach (var localizedString in localizer.GetAllStrings()) + { + dictionary[localizedString.Name] = localizedString.Value; + } } localizationConfig.Values[resource.ResourceName] = dictionary; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs index cd95768c3f..f4e22e0f41 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs @@ -34,8 +34,8 @@ public class AbpLocalizationScriptController { foreach (var resource in LocalizationOptions.Resources.Values) { - var localizer = StringLocalizerFactory.Create(resource.ResourceType); - localizer.GetAllStrings(); + var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resource.ResourceName); + localizer?.GetAllStrings(); } } } diff --git a/framework/src/Volo.Abp.Core/System/AbpObjectExtensions.cs b/framework/src/Volo.Abp.Core/System/AbpObjectExtensions.cs index 2d19fa8bc2..24ece0e52e 100644 --- a/framework/src/Volo.Abp.Core/System/AbpObjectExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/AbpObjectExtensions.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace System; @@ -17,6 +18,7 @@ public static class AbpObjectExtensions /// Type to be casted /// Object to cast /// Casted object + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T As(this object obj) where T : class { diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs index 534a7e0eb9..ccd9718de9 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -1,15 +1,18 @@ -using Volo.Abp; +using JetBrains.Annotations; +using Volo.Abp; namespace Microsoft.Extensions.Localization; public static class AbpStringLocalizerFactoryExtensions { + [CanBeNull] public static IStringLocalizer CreateDefaultOrNull(this IStringLocalizerFactory localizerFactory) { return (localizerFactory as IAbpStringLocalizerFactory) ?.CreateDefaultOrNull(); } + [CanBeNull] public static IStringLocalizer CreateByResourceNameOrNull( this IStringLocalizerFactory localizerFactory, string resourceName) @@ -18,6 +21,7 @@ public static class AbpStringLocalizerFactoryExtensions ?.CreateByResourceNameOrNull(resourceName); } + [NotNull] public static IStringLocalizer CreateByResourceName( this IStringLocalizerFactory localizerFactory, string resourceName) diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 88eb8a399d..ef2027b415 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -6,6 +6,9 @@ namespace Volo.Abp.Localization; public class LocalizableString : ILocalizableString { + [CanBeNull] + public string ResourceName { get; } + [CanBeNull] public Type ResourceType { get; } @@ -16,22 +19,30 @@ public class LocalizableString : ILocalizableString { Name = Check.NotNullOrEmpty(name, nameof(name)); ResourceType = resourceType; + + if (resourceType != null) + { + ResourceName = LocalizationResourceNameAttribute.GetName(resourceType); + } } - public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory) + public LocalizableString([NotNull] string name, [CanBeNull] string resourceName = null) { - var localizer = ResourceType != null - ? stringLocalizerFactory.Create(ResourceType) - : stringLocalizerFactory.CreateDefaultOrNull(); + Name = Check.NotNullOrEmpty(name, nameof(name)); + ResourceName = resourceName; + } + public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory) + { + var localizer = CreateStringLocalizerOrNull(stringLocalizerFactory); if (localizer == null) { - throw new AbpException($"Set {nameof(ResourceType)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); + throw new AbpException($"Set {nameof(ResourceName)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); } var result = localizer[Name]; - if (result.ResourceNotFound && ResourceType != null) + if (result.ResourceNotFound && ResourceName != null) { /* Search in the default resource if not found in the provided resource */ localizer = stringLocalizerFactory.CreateDefaultOrNull(); @@ -44,8 +55,37 @@ public class LocalizableString : ILocalizableString return result; } + private IStringLocalizer CreateStringLocalizerOrNull(IStringLocalizerFactory stringLocalizerFactory) + { + if (ResourceType != null) + { + return stringLocalizerFactory.Create(ResourceType); + } + + if (ResourceName != null) + { + var localizerByName = stringLocalizerFactory.CreateByResourceNameOrNull(ResourceName); + if (localizerByName != null) + { + return localizerByName; + } + } + + return stringLocalizerFactory.CreateDefaultOrNull(); + } + public static LocalizableString Create([NotNull] string name) { - return new LocalizableString(typeof(TResource), name); + return Create(typeof(TResource), name); + } + + public static LocalizableString Create(Type resourceType,[NotNull] string name) + { + return new LocalizableString(resourceType, name); + } + + public static LocalizableString Create([NotNull] string name, [CanBeNull] string resourceName = null) + { + return new LocalizableString(name, resourceName); } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 61621c2479..102e5971d6 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -20,7 +20,10 @@ public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocali public virtual LocalizedString this[string name, params object[] arguments] => GetLocalizedStringFormatted(name, arguments); - public AbpDictionaryBasedStringLocalizer(LocalizationResource resource, List baseLocalizers, AbpLocalizationOptions abpLocalizationOptions) + public AbpDictionaryBasedStringLocalizer( + LocalizationResource resource, + List baseLocalizers, + AbpLocalizationOptions abpLocalizationOptions) { Resource = resource; BaseLocalizers = baseLocalizers; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 5e8769ddab..63206a4d31 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -14,19 +14,22 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca protected internal AbpLocalizationOptions AbpLocalizationOptions { get; } protected ResourceManagerStringLocalizerFactory InnerFactory { get; } protected IServiceProvider ServiceProvider { get; } - protected ConcurrentDictionary LocalizerCache { get; } + protected IExternalLocalizationStore ExternalLocalizationStore { get; } + protected ConcurrentDictionary LocalizerCache { get; } //TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency. public AbpStringLocalizerFactory( ResourceManagerStringLocalizerFactory innerFactory, IOptions abpLocalizationOptions, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + IExternalLocalizationStore externalLocalizationStore) { InnerFactory = innerFactory; ServiceProvider = serviceProvider; + ExternalLocalizationStore = externalLocalizationStore; AbpLocalizationOptions = abpLocalizationOptions.Value; - LocalizerCache = new ConcurrentDictionary(); + LocalizerCache = new ConcurrentDictionary(); } public virtual IStringLocalizer Create(Type resourceType) @@ -37,7 +40,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return InnerFactory.Create(resourceType); } - return CreateInternal(resourceType, resource); + return CreateInternal(resource.ResourceName, resource); } public IStringLocalizer CreateByResourceNameOrNull(string resourceName) @@ -45,15 +48,19 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca var resource = AbpLocalizationOptions.Resources.GetOrNull(resourceName); if (resource == null) { - return null; + resource = ExternalLocalizationStore.GetResourceOrNull(resourceName); + if (resource == null) + { + return null; + } } - return CreateInternal(resource.ResourceType, resource); + return CreateInternal(resourceName, resource); } - private IStringLocalizer CreateInternal(Type resourceType, LocalizationResource resource) + private IStringLocalizer CreateInternal(string resourceName, LocalizationResource resource) { - if (LocalizerCache.TryGetValue(resourceType, out var cacheItem)) + if (LocalizerCache.TryGetValue(resourceName, out var cacheItem)) { return cacheItem.Localizer; } @@ -61,7 +68,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca lock (LocalizerCache) { return LocalizerCache.GetOrAdd( - resourceType, + resourceName, _ => CreateStringLocalizerCacheItem(resource) ).Localizer; } @@ -69,9 +76,13 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResource resource) { - foreach (var globalContributor in AbpLocalizationOptions.GlobalContributors) + foreach (var globalContributorType in AbpLocalizationOptions.GlobalContributors) { - resource.Contributors.Add((ILocalizationResourceContributor)Activator.CreateInstance(globalContributor)); + resource.Contributors.Add( + Activator + .CreateInstance(globalContributorType) + .As() + ); } var context = new LocalizationResourceInitializationContext(resource, ServiceProvider); @@ -84,7 +95,11 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return new StringLocalizerCacheItem( new AbpDictionaryBasedStringLocalizer( resource, - resource.BaseResourceTypes.Select(Create).ToList(), + resource + .BaseResourceNames + .Select(CreateByResourceNameOrNull) + .Where(x => x != null) + .ToList(), AbpLocalizationOptions ) ); @@ -122,4 +137,4 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return Create(AbpLocalizationOptions.DefaultResourceType); } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs new file mode 100644 index 0000000000..420bab414f --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs @@ -0,0 +1,9 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.Localization; + +public interface IExternalLocalizationStore +{ + [CanBeNull] + LocalizationResource GetResourceOrNull([NotNull] string resourceName); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs index 4cfd6e2f32..655175f1ac 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -55,13 +55,13 @@ public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransi { throw new AbpException("Invalid LocalizableString value: " + value); } + + if (!LocalizationOptions.Resources.ContainsResource(resourceName)) + { + resourceName = null; + } - var resourceType = LocalizationOptions.Resources.GetOrNull(resourceName)?.ResourceType; - - return new LocalizableString( - resourceType, - name - ); + return LocalizableString.Create(name, resourceName); default: return new FixedLocalizableString(value); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs index a2202dc959..7996ab2dbf 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs @@ -5,40 +5,26 @@ using JetBrains.Annotations; namespace Volo.Abp.Localization; -public class LocalizationResource +public class LocalizationResource : LocalizationResourceBase { [NotNull] - public Type ResourceType { get; } - - [NotNull] - public string ResourceName => LocalizationResourceNameAttribute.GetName(ResourceType); - - [CanBeNull] - public string DefaultCultureName { get; set; } - - [NotNull] - public LocalizationResourceContributorList Contributors { get; } - - [NotNull] - public List BaseResourceTypes { get; } + private Type ResourceType { get; } public LocalizationResource( [NotNull] Type resourceType, [CanBeNull] string defaultCultureName = null, [CanBeNull] ILocalizationResourceContributor initialContributor = null) + : base(LocalizationResourceNameAttribute.GetName(resourceType)) { ResourceType = Check.NotNull(resourceType, nameof(resourceType)); DefaultCultureName = defaultCultureName; - BaseResourceTypes = new List(); - Contributors = new LocalizationResourceContributorList(); - + AddBaseResourceTypes(); + if (initialContributor != null) { Contributors.Add(initialContributor); } - - AddBaseResourceTypes(); } protected virtual void AddBaseResourceTypes() @@ -51,8 +37,8 @@ public class LocalizationResource { foreach (var baseResourceType in descriptor.GetInheritedResourceTypes()) { - BaseResourceTypes.AddIfNotContains(baseResourceType); + BaseResourceNames.AddIfNotContains(LocalizationResourceNameAttribute.GetName(baseResourceType)); } } } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs new file mode 100644 index 0000000000..f523569ba3 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.Localization; + +public abstract class LocalizationResourceBase +{ + [NotNull] + public string ResourceName { get; } + + public List BaseResourceNames { get; } + + [CanBeNull] + public string DefaultCultureName { get; set; } + + [NotNull] + public LocalizationResourceContributorList Contributors { get; } + + public LocalizationResourceBase([NotNull] string resourceName) + { + ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + Contributors = new LocalizationResourceContributorList(); + BaseResourceNames = new(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs index d672a2f17a..548e7ae37d 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs @@ -56,4 +56,9 @@ public class LocalizationResourceDictionary : Dictionary( + [NotNull] this TLocalizationResource localizationResource, [NotNull] string virtualPath) + where TLocalizationResource : LocalizationResourceBase { Check.NotNull(localizationResource, nameof(localizationResource)); Check.NotNull(virtualPath, nameof(virtualPath)); @@ -21,16 +22,35 @@ public static class LocalizationResourceExtensions return localizationResource; } - public static LocalizationResource AddBaseTypes( - [NotNull] this LocalizationResource localizationResource, + public static TLocalizationResource AddBaseTypes( + [NotNull] this TLocalizationResource localizationResource, [NotNull] params Type[] types) + where TLocalizationResource : LocalizationResourceBase { Check.NotNull(localizationResource, nameof(localizationResource)); Check.NotNull(types, nameof(types)); foreach (var type in types) { - localizationResource.BaseResourceTypes.AddIfNotContains(type); + localizationResource + .BaseResourceNames + .AddIfNotContains(LocalizationResourceNameAttribute.GetName(type)); + } + + return localizationResource; + } + + public static TLocalizationResource AddBaseResources( + [NotNull] this TLocalizationResource localizationResource, + [NotNull] params string[] baseResourceNames) + where TLocalizationResource : LocalizationResourceBase + { + Check.NotNull(localizationResource, nameof(localizationResource)); + Check.NotNull(baseResourceNames, nameof(baseResourceNames)); + + foreach (var baseResourceName in baseResourceNames) + { + localizationResource.BaseResourceNames.AddIfNotContains(baseResourceName); } return localizationResource; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs new file mode 100644 index 0000000000..f44174d1d3 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs @@ -0,0 +1,11 @@ +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization; + +public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency +{ + public LocalizationResource GetResourceOrNull(string resourceName) + { + return null; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs index 8b9dca76be..085e486756 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyConfigurationExtensions.cs @@ -8,20 +8,18 @@ public static class ExtensionPropertyConfigurationExtensions public static string GetLocalizationResourceNameOrNull( this ExtensionPropertyConfiguration property) { - var resourceType = property.GetLocalizationResourceTypeOrNull(); - if (resourceType == null) + if (property.DisplayName is LocalizableString localizableString) { - return null; + return localizableString.ResourceName; } - return LocalizationResourceNameAttribute.GetName(resourceType); + return null; } public static Type GetLocalizationResourceTypeOrNull( this ExtensionPropertyConfiguration property) { - if (property.DisplayName != null && - property.DisplayName is LocalizableString localizableString) + if (property.DisplayName is LocalizableString localizableString) { return localizableString.ResourceType; } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs index d5e41a624a..352a7ea3a3 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs @@ -32,7 +32,6 @@ public class AbpStringLocalizerFactory_Tests : AbpIntegratedTest(); - localizableString.ResourceType.ShouldBe(typeof(LocalizationTestResource)); + localizableString.ResourceName.ShouldBe("Test"); localizableString.Name.ShouldBe("Car"); Assert.Throws(() => From 2b5e7fd03fbd89c268cf01fd256ae18d7c0917b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:07:00 +0300 Subject: [PATCH 12/61] Allow to define non-typed localization resources. --- .../Client/RemoteLocalizationContributor.cs | 2 +- .../AbpDictionaryBasedStringLocalizer.cs | 4 +- .../Localization/AbpStringLocalizerFactory.cs | 8 +-- .../LocalizableStringSerializer.cs | 2 +- .../Abp/Localization/LocalizationResource.cs | 12 ++--- .../Localization/LocalizationResourceBase.cs | 12 ++++- .../LocalizationResourceDictionary.cs | 54 ++++++++++++++----- ...calizationResourceInitializationContext.cs | 4 +- .../NonTypedLocalizationResource.cs | 17 ++++++ .../Localization/AbpLocalizationTestModule.cs | 8 +-- .../LocalizationTestCountryNamesResource.cs | 6 --- .../Source/LocalizationTestResource.cs | 6 +-- 12 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NonTypedLocalizationResource.cs delete mode 100644 framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/LocalizationTestCountryNamesResource.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index c01fc6a1af..319739dc09 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Client; public class RemoteLocalizationContributor : ILocalizationResourceContributor { - private LocalizationResource _resource; + private LocalizationResourceBase _resource; private ICachedApplicationConfigurationClient _applicationConfigurationClient; private ILogger _logger; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 102e5971d6..3acafa833e 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Localization; public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocalizerSupportsInheritance { - public LocalizationResource Resource { get; } + public LocalizationResourceBase Resource { get; } public List BaseLocalizers { get; } @@ -21,7 +21,7 @@ public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocali public virtual LocalizedString this[string name, params object[] arguments] => GetLocalizedStringFormatted(name, arguments); public AbpDictionaryBasedStringLocalizer( - LocalizationResource resource, + LocalizationResourceBase resource, List baseLocalizers, AbpLocalizationOptions abpLocalizationOptions) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 63206a4d31..0712fe567c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -34,7 +34,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca public virtual IStringLocalizer Create(Type resourceType) { - var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceType); + var resource = AbpLocalizationOptions.Resources.GetOrNull(resourceType); if (resource == null) { return InnerFactory.Create(resourceType); @@ -45,7 +45,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca public IStringLocalizer CreateByResourceNameOrNull(string resourceName) { - var resource = AbpLocalizationOptions.Resources.GetOrNull(resourceName); + var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceName); if (resource == null) { resource = ExternalLocalizationStore.GetResourceOrNull(resourceName); @@ -58,7 +58,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return CreateInternal(resourceName, resource); } - private IStringLocalizer CreateInternal(string resourceName, LocalizationResource resource) + private IStringLocalizer CreateInternal(string resourceName, LocalizationResourceBase resource) { if (LocalizerCache.TryGetValue(resourceName, out var cacheItem)) { @@ -74,7 +74,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca } } - private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResource resource) + private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResourceBase resource) { foreach (var globalContributorType in AbpLocalizationOptions.GlobalContributors) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs index 655175f1ac..a6181d0a61 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -56,7 +56,7 @@ public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransi throw new AbpException("Invalid LocalizableString value: " + value); } - if (!LocalizationOptions.Resources.ContainsResource(resourceName)) + if (!LocalizationOptions.Resources.ContainsKey(resourceName)) { resourceName = null; } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs index 7996ab2dbf..8158cb77b1 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs @@ -14,17 +14,13 @@ public class LocalizationResource : LocalizationResourceBase [NotNull] Type resourceType, [CanBeNull] string defaultCultureName = null, [CanBeNull] ILocalizationResourceContributor initialContributor = null) - : base(LocalizationResourceNameAttribute.GetName(resourceType)) + : base( + LocalizationResourceNameAttribute.GetName(resourceType), + defaultCultureName, + initialContributor) { ResourceType = Check.NotNull(resourceType, nameof(resourceType)); - DefaultCultureName = defaultCultureName; - AddBaseResourceTypes(); - - if (initialContributor != null) - { - Contributors.Add(initialContributor); - } } protected virtual void AddBaseResourceTypes() diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs index f523569ba3..a7ec4fb93b 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs @@ -16,10 +16,20 @@ public abstract class LocalizationResourceBase [NotNull] public LocalizationResourceContributorList Contributors { get; } - public LocalizationResourceBase([NotNull] string resourceName) + public LocalizationResourceBase( + [NotNull] string resourceName, + [CanBeNull] string defaultCultureName = null, + [CanBeNull] ILocalizationResourceContributor initialContributor = null) { ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); + DefaultCultureName = defaultCultureName; + Contributors = new LocalizationResourceContributorList(); BaseResourceNames = new(); + + if (initialContributor != null) + { + Contributors.Add(initialContributor); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs index 548e7ae37d..4a88eac199 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs @@ -4,9 +4,9 @@ using JetBrains.Annotations; namespace Volo.Abp.Localization; -public class LocalizationResourceDictionary : Dictionary +public class LocalizationResourceDictionary : Dictionary { - private readonly Dictionary _resourcesByNames = new(); + private readonly Dictionary _resourcesByTypes = new(); public LocalizationResource Add([CanBeNull] string defaultCultureName = null) { @@ -15,24 +15,41 @@ public class LocalizationResourceDictionary : Dictionary() + public LocalizationResourceBase Get() { var resourceType = typeof(TResource); - var resource = this.GetOrDefault(resourceType); + var resource = _resourcesByTypes.GetOrDefault(resourceType); if (resource == null) { throw new AbpException("Can not find a resource with given type: " + resourceType.AssemblyQualifiedName); @@ -41,9 +58,9 @@ public class LocalizationResourceDictionary : Dictionary("en") + .Add("LocalizationTestCountryNames") .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); options.Resources .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source") + .AddBaseResources("LocalizationTestCountryNames"); options.Resources .Get() diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/LocalizationTestCountryNamesResource.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/LocalizationTestCountryNamesResource.cs deleted file mode 100644 index a70436cbc7..0000000000 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Base/CountryNames/LocalizationTestCountryNamesResource.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Volo.Abp.Localization.TestResources.Base.CountryNames; - -public sealed class LocalizationTestCountryNamesResource -{ - -} diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs index bc32e98bcc..95a1bbd32f 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs @@ -1,11 +1,9 @@ -using Volo.Abp.Localization.TestResources.Base.CountryNames; -using Volo.Abp.Localization.TestResources.Base.Validation; +using Volo.Abp.Localization.TestResources.Base.Validation; namespace Volo.Abp.Localization.TestResources.Source; [InheritResource( - typeof(LocalizationTestValidationResource), - typeof(LocalizationTestCountryNamesResource) + typeof(LocalizationTestValidationResource) )] [LocalizationResourceName("Test")] public sealed class LocalizationTestResource From 0c4f43f3ccc309d5edbacd289a9fd6f3cdaf03ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:08:18 +0300 Subject: [PATCH 13/61] Change signature of IExternalLocalizationStore.GetResourceOrNull --- .../Volo/Abp/Localization/IExternalLocalizationStore.cs | 2 +- .../Volo/Abp/Localization/NullExternalLocalizationStore.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs index 420bab414f..10d411bb4a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.Localization; public interface IExternalLocalizationStore { [CanBeNull] - LocalizationResource GetResourceOrNull([NotNull] string resourceName); + LocalizationResourceBase GetResourceOrNull([NotNull] string resourceName); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs index f44174d1d3..7597d6c2a0 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Localization; public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency { - public LocalizationResource GetResourceOrNull(string resourceName) + public LocalizationResourceBase GetResourceOrNull(string resourceName) { return null; } From d21c20b84b841d9aca92d18a7108560d16c00baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:17:41 +0300 Subject: [PATCH 14/61] Refactor: Move type into new namespace: IExternalLocalizationStore --- .../Volo/Abp/Localization/AbpStringLocalizerFactory.cs | 1 + .../Localization/{ => External}/IExternalLocalizationStore.cs | 2 +- .../{ => External}/NullExternalLocalizationStore.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) rename framework/src/Volo.Abp.Localization/Volo/Abp/Localization/{ => External}/IExternalLocalizationStore.cs (80%) rename framework/src/Volo.Abp.Localization/Volo/Abp/Localization/{ => External}/NullExternalLocalizationStore.cs (84%) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 0712fe567c..92fa771d64 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; +using Volo.Abp.Localization.External; namespace Volo.Abp.Localization; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs similarity index 80% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index 10d411bb4a..ecce4a86e0 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -1,6 +1,6 @@ using JetBrains.Annotations; -namespace Volo.Abp.Localization; +namespace Volo.Abp.Localization.External; public interface IExternalLocalizationStore { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs similarity index 84% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index 7597d6c2a0..3a2b63a617 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -1,6 +1,6 @@ using Volo.Abp.DependencyInjection; -namespace Volo.Abp.Localization; +namespace Volo.Abp.Localization.External; public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency { From 66238da304ce9dcd3168e117f1ffbdc3afce049b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:22:43 +0300 Subject: [PATCH 15/61] Merge IDistributedLocalizationStore into IExternalLocalizationStore --- .../AbpApplicationConfigurationAppService.cs | 11 ++++---- .../Abp/Localization/AbpLocalizationModule.cs | 7 +++--- .../DistributedLocalizationData.cs | 18 ------------- .../IDistributedLocalizationStore.cs | 12 --------- .../NullDistributedLocalizationStore.cs | 25 ------------------- .../AbpExternalLocalizationOptions.cs} | 6 ++--- .../External/ExternalLocalizationData.cs | 18 +++++++++++++ .../ExternalLocalizationResourceData.cs} | 6 ++--- .../External/IExternalLocalizationStore.cs | 8 ++++++ .../External/NullExternalLocalizationStore.cs | 20 +++++++++++++++ 10 files changed, 62 insertions(+), 69 deletions(-) delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs rename framework/src/Volo.Abp.Localization/Volo/Abp/Localization/{Distributed/AbpDistributedLocalizationOptions.cs => External/AbpExternalLocalizationOptions.cs} (51%) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs rename framework/src/Volo.Abp.Localization/Volo/Abp/Localization/{Distributed/DistributedLocalizationResourceData.cs => External/ExternalLocalizationResourceData.cs} (67%) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 97ae0c868d..bf797e3c7a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -18,6 +18,7 @@ using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; using Volo.Abp.Localization.Distributed; +using Volo.Abp.Localization.External; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Volo.Abp.Timing; @@ -43,7 +44,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp private readonly ITimezoneProvider _timezoneProvider; private readonly AbpClockOptions _abpClockOptions; private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; - private readonly AbpDistributedLocalizationOptions _distributedLocalizationOptions; + private readonly AbpExternalLocalizationOptions _externalLocalizationOptions; private readonly AbpApplicationConfigurationOptions _options; public AbpApplicationConfigurationAppService( @@ -64,7 +65,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp IOptions abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, IOptions options, - IOptions distributedLocalizationOptions) + IOptions distributedLocalizationOptions) { _serviceProvider = serviceProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; @@ -80,7 +81,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp _timezoneProvider = timezoneProvider; _abpClockOptions = abpClockOptions.Value; _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; - _distributedLocalizationOptions = distributedLocalizationOptions.Value; + _externalLocalizationOptions = distributedLocalizationOptions.Value; _options = options.Value; _localizationOptions = localizationOptions.Value; _multiTenancyOptions = multiTenancyOptions.Value; @@ -230,11 +231,11 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp localizationConfig.Values[resource.ResourceName] = dictionary; } - if (_distributedLocalizationOptions.GetFromDistributedStore) + if (_externalLocalizationOptions.GetFromExternalStore) { var distributedLocalizationData = await this .LazyServiceProvider - .LazyGetRequiredService() + .LazyGetRequiredService() .GetAsync(); foreach (var resource in distributedLocalizationData.Resources) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 6508976d85..90bec99212 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Options; using Polly; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization.Distributed; +using Volo.Abp.Localization.External; using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; using Volo.Abp.Settings; @@ -63,10 +64,10 @@ public class AbpLocalizationModule : AbpModule { var options = context .ServiceProvider - .GetRequiredService>() + .GetRequiredService>() .Value; - if (!options.SaveToDistributedStore) + if (!options.SaveToExternalStore) { return; } @@ -99,7 +100,7 @@ public class AbpLocalizationModule : AbpModule // ReSharper disable once AccessToDisposedClosure await scope .ServiceProvider - .GetRequiredService() + .GetRequiredService() .SaveAsync(); } catch (Exception ex) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs deleted file mode 100644 index b8374f7119..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationData.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.Localization.Distributed; - -public class DistributedLocalizationData -{ - public List Resources { get; } - - public DistributedLocalizationData() - { - Resources = new(); - } - - public DistributedLocalizationData(List resources) - { - Resources = Check.NotNull(resources, nameof(resources)); - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs deleted file mode 100644 index 52f2b52cdb..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/IDistributedLocalizationStore.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; - -namespace Volo.Abp.Localization.Distributed; - -public interface IDistributedLocalizationStore -{ - Task SaveAsync(); - - Task GetAsync(); - - Task GetResourceNames(); -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs deleted file mode 100644 index 579b434a33..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/NullDistributedLocalizationStore.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.Localization.Distributed; - -public class NullDistributedLocalizationStore : IDistributedLocalizationStore, ISingletonDependency -{ - private readonly DistributedLocalizationData _data = new(); - - public Task SaveAsync() - { - return Task.CompletedTask; - } - - public Task GetAsync() - { - return Task.FromResult(_data); - } - - public Task GetResourceNames() - { - return Task.FromResult(Array.Empty()); - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs similarity index 51% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs index 802bc15a06..2058e8b693 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/AbpDistributedLocalizationOptions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs @@ -1,14 +1,14 @@ namespace Volo.Abp.Localization.Distributed; -public class AbpDistributedLocalizationOptions +public class AbpExternalLocalizationOptions { /// /// Default: true. /// - public bool SaveToDistributedStore { get; set; } = true; + public bool SaveToExternalStore { get; set; } = true; /// /// Default: false. /// - public bool GetFromDistributedStore { get; set; } + public bool GetFromExternalStore { get; set; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs new file mode 100644 index 0000000000..3a894bbfca --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Localization.Distributed; + +public class ExternalLocalizationData +{ + public List Resources { get; } + + public ExternalLocalizationData() + { + Resources = new(); + } + + public ExternalLocalizationData(List resources) + { + Resources = Check.NotNull(resources, nameof(resources)); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs similarity index 67% rename from framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs rename to framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs index bbb449a380..48eefe05af 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/Distributed/DistributedLocalizationResourceData.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs @@ -2,19 +2,19 @@ using System.Collections.Generic; namespace Volo.Abp.Localization.Distributed; -public class DistributedLocalizationResourceData +public class ExternalLocalizationResourceData { public string ResourceName { get; } public Dictionary Texts { get; } - public DistributedLocalizationResourceData(string resourceName) + public ExternalLocalizationResourceData(string resourceName) { ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); Texts = new(); } - public DistributedLocalizationResourceData(string resourceName, Dictionary texts) + public ExternalLocalizationResourceData(string resourceName, Dictionary texts) { ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); Texts = Check.NotNull(texts, nameof(texts)); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index ecce4a86e0..3f3fcdd9ca 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -1,9 +1,17 @@ +using System.Threading.Tasks; using JetBrains.Annotations; +using Volo.Abp.Localization.Distributed; namespace Volo.Abp.Localization.External; public interface IExternalLocalizationStore { + Task SaveAsync(); + [CanBeNull] LocalizationResourceBase GetResourceOrNull([NotNull] string resourceName); + + Task GetAsync(); + + Task GetResourceNames(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index 3a2b63a617..4f1f8edd0d 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -1,11 +1,31 @@ +using System; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization.Distributed; namespace Volo.Abp.Localization.External; public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency { + private readonly ExternalLocalizationData _data = new(); + + public Task SaveAsync() + { + return Task.CompletedTask; + } + public LocalizationResourceBase GetResourceOrNull(string resourceName) { return null; } + + public Task GetAsync() + { + return Task.FromResult(_data); + } + + public Task GetResourceNames() + { + return Task.FromResult(Array.Empty()); + } } \ No newline at end of file From 95f6b288a83ba722766b42e1cebe82805fc9b913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:23:36 +0300 Subject: [PATCH 16/61] Refactor: Adjust namespaces. --- .../AbpApplicationConfigurationAppService.cs | 1 - .../Volo/Abp/Localization/AbpLocalizationModule.cs | 1 - .../Abp/Localization/External/AbpExternalLocalizationOptions.cs | 2 +- .../Volo/Abp/Localization/External/ExternalLocalizationData.cs | 2 +- .../Localization/External/ExternalLocalizationResourceData.cs | 2 +- .../Abp/Localization/External/IExternalLocalizationStore.cs | 1 - .../Abp/Localization/External/NullExternalLocalizationStore.cs | 1 - 7 files changed, 3 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index bf797e3c7a..b9374cf2fd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -17,7 +17,6 @@ using Volo.Abp.Data; using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; -using Volo.Abp.Localization.Distributed; using Volo.Abp.Localization.External; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 90bec99212..8371f1be24 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Polly; using Volo.Abp.DependencyInjection; -using Volo.Abp.Localization.Distributed; using Volo.Abp.Localization.External; using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs index 2058e8b693..bc2a19a26c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.Localization.Distributed; +namespace Volo.Abp.Localization.External; public class AbpExternalLocalizationOptions { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs index 3a894bbfca..2796972c58 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Volo.Abp.Localization.Distributed; +namespace Volo.Abp.Localization.External; public class ExternalLocalizationData { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs index 48eefe05af..320334a730 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Volo.Abp.Localization.Distributed; +namespace Volo.Abp.Localization.External; public class ExternalLocalizationResourceData { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index 3f3fcdd9ca..9924d41d3c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using JetBrains.Annotations; -using Volo.Abp.Localization.Distributed; namespace Volo.Abp.Localization.External; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index 4f1f8edd0d..feceb8d522 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -using Volo.Abp.Localization.Distributed; namespace Volo.Abp.Localization.External; From f35e7903600e7b0f5ed852d970dbd43eff8fc972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 14:31:54 +0300 Subject: [PATCH 17/61] Revise IExternalLocalizationStore usage. --- .../AbpApplicationConfigurationAppService.cs | 30 +++++++++---------- .../External/ExternalLocalizationData.cs | 18 ----------- .../ExternalLocalizationResourceData.cs | 22 -------------- .../External/IExternalLocalizationStore.cs | 4 +-- .../External/NullExternalLocalizationStore.cs | 9 +----- 5 files changed, 16 insertions(+), 67 deletions(-) delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index b9374cf2fd..e2557aac0c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -215,10 +215,21 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync()); - foreach (var resource in _localizationOptions.Resources.Values) + var resourceNames = _localizationOptions.Resources.Values.Select(x => x.ResourceName); + + if (_externalLocalizationOptions.GetFromExternalStore) + { + var externalResourceNames = await LazyServiceProvider + .LazyGetRequiredService() + .GetResourceNamesAsync(); + resourceNames = resourceNames.Union(externalResourceNames); + } + + foreach (var resourceName in resourceNames) { var dictionary = new Dictionary(); - var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resource.ResourceName); + + var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resourceName); if (localizer != null) { foreach (var localizedString in localizer.GetAllStrings()) @@ -227,20 +238,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp } } - localizationConfig.Values[resource.ResourceName] = dictionary; - } - - if (_externalLocalizationOptions.GetFromExternalStore) - { - var distributedLocalizationData = await this - .LazyServiceProvider - .LazyGetRequiredService() - .GetAsync(); - - foreach (var resource in distributedLocalizationData.Resources) - { - localizationConfig.Values[resource.ResourceName] = resource.Texts; - } + localizationConfig.Values[resourceName] = dictionary; } localizationConfig.CurrentCulture = GetCurrentCultureInfo(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs deleted file mode 100644 index 2796972c58..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationData.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.Localization.External; - -public class ExternalLocalizationData -{ - public List Resources { get; } - - public ExternalLocalizationData() - { - Resources = new(); - } - - public ExternalLocalizationData(List resources) - { - Resources = Check.NotNull(resources, nameof(resources)); - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs deleted file mode 100644 index 320334a730..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/ExternalLocalizationResourceData.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.Localization.External; - -public class ExternalLocalizationResourceData -{ - public string ResourceName { get; } - - public Dictionary Texts { get; } - - public ExternalLocalizationResourceData(string resourceName) - { - ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); - Texts = new(); - } - - public ExternalLocalizationResourceData(string resourceName, Dictionary texts) - { - ResourceName = Check.NotNullOrWhiteSpace(resourceName, nameof(resourceName)); - Texts = Check.NotNull(texts, nameof(texts)); - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index 9924d41d3c..d863024721 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -10,7 +10,5 @@ public interface IExternalLocalizationStore [CanBeNull] LocalizationResourceBase GetResourceOrNull([NotNull] string resourceName); - Task GetAsync(); - - Task GetResourceNames(); + Task GetResourceNamesAsync(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index feceb8d522..bdbac6ddb9 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -6,8 +6,6 @@ namespace Volo.Abp.Localization.External; public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency { - private readonly ExternalLocalizationData _data = new(); - public Task SaveAsync() { return Task.CompletedTask; @@ -18,12 +16,7 @@ public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingle return null; } - public Task GetAsync() - { - return Task.FromResult(_data); - } - - public Task GetResourceNames() + public Task GetResourceNamesAsync() { return Task.FromResult(Array.Empty()); } From 99b9b3032340b453b5065c5d237a1ca74e91d1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 16:21:40 +0300 Subject: [PATCH 18/61] Moved IExternalLocalizationStore.SaveAsync to the language management module. --- .../Abp/Localization/AbpLocalizationModule.cs | 85 +------------------ .../External/IExternalLocalizationStore.cs | 2 - .../External/NullExternalLocalizationStore.cs | 5 -- 3 files changed, 1 insertion(+), 91 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 8371f1be24..85be669593 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -1,14 +1,4 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Polly; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Localization.External; -using Volo.Abp.Localization.Resources.AbpLocalization; +using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; using Volo.Abp.Settings; using Volo.Abp.Threading; @@ -24,8 +14,6 @@ namespace Volo.Abp.Localization; )] public class AbpLocalizationModule : AbpModule { - private readonly CancellationTokenSource _cancellationTokenSource = new(); - public override void ConfigureServices(ServiceConfigurationContext context) { AbpStringLocalizerFactory.Replace(context.Services); @@ -47,75 +35,4 @@ public class AbpLocalizationModule : AbpModule .AddVirtualJson("/Localization/Resources/AbpLocalization"); }); } - - public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) - { - await SaveLocalizationsAsync(context); - } - - public override Task OnApplicationShutdownAsync(ApplicationShutdownContext context) - { - _cancellationTokenSource.Cancel(); - return Task.CompletedTask; - } - - private async Task SaveLocalizationsAsync(ApplicationInitializationContext context) - { - var options = context - .ServiceProvider - .GetRequiredService>() - .Value; - - if (!options.SaveToExternalStore) - { - return; - } - - var rootServiceProvider = context.ServiceProvider.GetRequiredService(); - - Task.Run(async () => - { - using var scope = rootServiceProvider.CreateScope(); - var applicationLifetime = scope.ServiceProvider.GetService(); - var cancellationTokenProvider = scope.ServiceProvider.GetRequiredService(); - var cancellationToken = applicationLifetime?.ApplicationStopping ?? _cancellationTokenSource.Token; - - try - { - using (cancellationTokenProvider.Use(cancellationToken)) - { - if (cancellationTokenProvider.Token.IsCancellationRequested) - { - return; - } - - await Policy - .Handle() - .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) - .ExecuteAsync(async _ => - { - try - { - // ReSharper disable once AccessToDisposedClosure - await scope - .ServiceProvider - .GetRequiredService() - .SaveAsync(); - } - catch (Exception ex) - { - // ReSharper disable once AccessToDisposedClosure - scope.ServiceProvider - .GetService>()? - .LogException(ex); - - throw; // Polly will catch it - } - }, cancellationTokenProvider.Token); - } - } - // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) - catch { } - }); - } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index d863024721..fa03a6bbff 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -5,8 +5,6 @@ namespace Volo.Abp.Localization.External; public interface IExternalLocalizationStore { - Task SaveAsync(); - [CanBeNull] LocalizationResourceBase GetResourceOrNull([NotNull] string resourceName); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index bdbac6ddb9..0c55919db2 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -6,11 +6,6 @@ namespace Volo.Abp.Localization.External; public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingletonDependency { - public Task SaveAsync() - { - return Task.CompletedTask; - } - public LocalizationResourceBase GetResourceOrNull(string resourceName) { return null; From 1945ae7c2be4986843a2af288a1276840ae95342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 16:37:19 +0300 Subject: [PATCH 19/61] Fix feature management module for localization changes. --- .../Components/FeatureManagementModal.razor.cs | 4 ++-- .../FeatureSettingManagementComponent.razor.cs | 13 +++++-------- .../FeatureSettingGroup/FeatureSettingViewModel.cs | 6 ++++++ .../FeatureManagement/FeatureManagementModal.cshtml | 11 +++++------ 4 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingViewModel.cs diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs index e2cb9c160c..f63dc6f37f 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureManagementModal.razor.cs @@ -194,8 +194,8 @@ public partial class FeatureManagementModal protected virtual IStringLocalizer CreateStringLocalizer(string resourceName) { - var resource = LocalizationOptions.Value.Resources.Values.FirstOrDefault(x => x.ResourceName == resourceName); - return HtmlLocalizerFactory.Create(resource != null ? resource.ResourceType : LocalizationOptions.Value.DefaultResourceType); + return StringLocalizerFactory.CreateByResourceNameOrNull(resourceName) ?? + StringLocalizerFactory.CreateDefaultOrNull(); } protected virtual Task ClosingModal(ModalClosingEventArgs eventArgs) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingManagementComponent.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingManagementComponent.razor.cs index 09b31b9609..2b5bee083d 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingManagementComponent.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingManagementComponent.razor.cs @@ -10,9 +10,6 @@ namespace Volo.Abp.FeatureManagement.Blazor.Components.FeatureSettingGroup; public partial class FeatureSettingManagementComponent : AbpComponentBase { - [Inject] - protected IStringLocalizer L { get; set; } - [Inject] protected PermissionChecker PermissionChecker { get; set; } @@ -20,6 +17,11 @@ public partial class FeatureSettingManagementComponent : AbpComponentBase protected FeatureSettingViewModel Settings; + public FeatureSettingManagementComponent() + { + LocalizationResource = typeof(AbpFeatureManagementResource); + } + protected async override Task OnInitializedAsync() { Settings = new FeatureSettingViewModel @@ -32,9 +34,4 @@ public partial class FeatureSettingManagementComponent : AbpComponentBase { await FeatureManagementModal.OpenAsync(TenantFeatureValueProvider.ProviderName); } -} - -public class FeatureSettingViewModel -{ - public bool HasManageHostFeaturesPermission { get; set; } } \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingViewModel.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingViewModel.cs new file mode 100644 index 0000000000..eaef1a96f3 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor/Components/FeatureSettingGroup/FeatureSettingViewModel.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.FeatureManagement.Blazor.Components.FeatureSettingGroup; + +public class FeatureSettingViewModel +{ + public bool HasManageHostFeaturesPermission { get; set; } +} \ No newline at end of file diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml index 868211adcf..4ed0012a89 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Web/Pages/FeatureManagement/FeatureManagementModal.cshtml @@ -1,22 +1,21 @@ @page @using Microsoft.AspNetCore.Mvc.Localization -@using Microsoft.Extensions.Options +@using Microsoft.Extensions.Localization @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal @using Volo.Abp.FeatureManagement.Localization @using Volo.Abp.Validation.StringValues @using Volo.Abp.FeatureManagement.Web.Pages.FeatureManagement -@using Volo.Abp.Localization @model FeatureManagementModal @inject IHtmlLocalizer L -@inject IHtmlLocalizerFactory HtmlLocalizerFactory -@inject IOptions LocalizationOptions +@inject IStringLocalizerFactory StringLocalizerFactory @{ Layout = null; IHtmlLocalizer CreateHtmlLocalizer(string resourceName) { - var resource = LocalizationOptions.Value.Resources.Values.FirstOrDefault(x => x.ResourceName == resourceName); - return HtmlLocalizerFactory.Create(resource != null ? resource.ResourceType : LocalizationOptions.Value.DefaultResourceType); + var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resourceName) ?? + StringLocalizerFactory.CreateDefaultOrNull(); + return new HtmlLocalizer(localizer); } }
From a1dd65cfdba3fc6084f9598f6ecbd54eec856416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 26 Aug 2022 17:28:03 +0300 Subject: [PATCH 20/61] Fix permission-management module for localization changes. --- .../Components/PermissionManagementModal.razor.cs | 4 ++-- .../PermissionManagementModal.cshtml.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs index 36358c1b95..364fd5c300 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs @@ -281,13 +281,13 @@ public partial class PermissionManagementModal return fallbackValue; } - var resource = LocalizationOptions.Value.Resources.GetOrNull(resourceName); + var resource = LocalizationOptions.Value.Resources.GetOrDefault(resourceName); if (resource == null) { return fallbackValue; } - var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + var result = new LocalizableString(key, resourceName).Localize(StringLocalizerFactory); if (result.ResourceNotFound) { return fallbackValue; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs index 30057eea82..feb8481f27 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs @@ -114,13 +114,13 @@ public class PermissionManagementModal : AbpPageModel return fallbackValue; } - var resource = LocalizationOptions.Resources.GetOrNull(resourceName); + var resource = LocalizationOptions.Resources.GetOrDefault(resourceName); if (resource == null) { return fallbackValue; } - var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + var result = new LocalizableString(key, resourceName).Localize(StringLocalizerFactory); if (result.ResourceNotFound) { return fallbackValue; From 2ccd779eb9dd73a2f01f3de4687b72c1926ed2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 27 Aug 2022 11:57:44 +0300 Subject: [PATCH 21/61] Rename IStringLocalizerSupportsInheritance to IAbpStringLocalizer and inherit from IStringLocalizer. --- .../AbpDictionaryBasedStringLocalizer.cs | 4 ++-- .../Abp/Localization/AbpStringLocalizerExtensions.cs | 2 +- .../Volo/Abp/Localization/IAbpStringLocalizer.cs | 12 ++++++++++++ .../IStringLocalizerSupportsInheritance.cs | 9 --------- 4 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IStringLocalizerSupportsInheritance.cs diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 3acafa833e..17db37e6af 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; -public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocalizerSupportsInheritance +public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer { public LocalizationResourceBase Resource { get; } @@ -184,7 +184,7 @@ public class AbpDictionaryBasedStringLocalizer : IStringLocalizer, IStringLocali return allStrings.Values.ToImmutableList(); } - public class CultureWrapperStringLocalizer : IStringLocalizer, IStringLocalizerSupportsInheritance + public class CultureWrapperStringLocalizer : IAbpStringLocalizer { private readonly string _cultureName; private readonly AbpDictionaryBasedStringLocalizer _innerLocalizer; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index 8201043c6e..ccbb12fd1f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -42,7 +42,7 @@ public static class AbpStringLocalizerExtensions bool includeBaseLocalizers) { var internalLocalizer = (ProxyHelper.UnProxy(stringLocalizer) as IStringLocalizer).GetInternalLocalizer(); - if (internalLocalizer is IStringLocalizerSupportsInheritance stringLocalizerSupportsInheritance) + if (internalLocalizer is IAbpStringLocalizer stringLocalizerSupportsInheritance) { return stringLocalizerSupportsInheritance.GetAllStrings( includeParentCultures, diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs new file mode 100644 index 0000000000..3b8c107199 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization; + +public interface IAbpStringLocalizer : IStringLocalizer +{ + IEnumerable GetAllStrings( + bool includeParentCultures, + bool includeBaseLocalizers + ); +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IStringLocalizerSupportsInheritance.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IStringLocalizerSupportsInheritance.cs deleted file mode 100644 index cf0bff3631..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IStringLocalizerSupportsInheritance.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; -using Microsoft.Extensions.Localization; - -namespace Volo.Abp.Localization; - -public interface IStringLocalizerSupportsInheritance -{ - IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers); -} From 1d33a612509c767ebb2eeda906d6d15dba3be6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 27 Aug 2022 13:11:25 +0300 Subject: [PATCH 22/61] Added GetSupportedCultures to IAbpStringLocalizer --- .../Client/RemoteLocalizationContributor.cs | 10 +++++++++- .../AbpDictionaryBasedStringLocalizer.cs | 10 ++++++++++ .../AbpStringLocalizerExtensions.cs | 20 +++++++++++++++---- .../Abp/Localization/IAbpStringLocalizer.cs | 4 +++- .../ILocalizationResourceContributor.cs | 2 ++ .../Localization/LocalizationResourceBase.cs | 5 +++++ .../LocalizationResourceContributorList.cs | 5 +++++ ...FileLocalizationResourceContributorBase.cs | 5 +++++ 8 files changed, 55 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index 319739dc09..3f4a038de4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; @@ -52,6 +53,13 @@ public class RemoteLocalizationContributor : ILocalizationResourceContributor } } + public IEnumerable GetSupportedCultures() + { + /* This contributor does not know all the supported cultures by the + remote localization resource, and it is not needed on the client side */ + return Array.Empty(); + } + private Dictionary GetResourceOrNull() { var applicationConfigurationDto = _applicationConfigurationClient.Get(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 17db37e6af..8467749943 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -47,6 +47,11 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer ); } + public IEnumerable GetSupportedCultures() + { + return Resource.Contributors.GetSupportedCultures(); + } + protected virtual LocalizedString GetLocalizedStringFormatted(string name, params object[] arguments) { return GetLocalizedStringFormatted(name, CultureInfo.CurrentUICulture.Name, arguments); @@ -208,5 +213,10 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer { return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers); } + + public IEnumerable GetSupportedCultures() + { + return _innerLocalizer.GetSupportedCultures(); + } } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index ccbb12fd1f..d77f6cf4af 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Reflection; using JetBrains.Annotations; using Microsoft.Extensions.Localization; @@ -41,10 +42,10 @@ public static class AbpStringLocalizerExtensions bool includeParentCultures, bool includeBaseLocalizers) { - var internalLocalizer = (ProxyHelper.UnProxy(stringLocalizer) as IStringLocalizer).GetInternalLocalizer(); - if (internalLocalizer is IAbpStringLocalizer stringLocalizerSupportsInheritance) + var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); + if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) { - return stringLocalizerSupportsInheritance.GetAllStrings( + return abpStringLocalizer.GetAllStrings( includeParentCultures, includeBaseLocalizers ); @@ -54,4 +55,15 @@ public static class AbpStringLocalizerExtensions includeParentCultures ); } + + public static IEnumerable GetSupportedCultures(this IStringLocalizer localizer) + { + var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(localizer)).GetInternalLocalizer(); + if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) + { + return abpStringLocalizer.GetSupportedCultures(); + } + + return Array.Empty(); + } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index 3b8c107199..15577164b8 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -9,4 +9,6 @@ public interface IAbpStringLocalizer : IStringLocalizer bool includeParentCultures, bool includeBaseLocalizers ); -} + + IEnumerable GetSupportedCultures(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs index bfccb660a0..ebeb57296c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs @@ -10,4 +10,6 @@ public interface ILocalizationResourceContributor LocalizedString GetOrNull(string cultureName, string name); void Fill(string cultureName, Dictionary dictionary); + + IEnumerable GetSupportedCultures(); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs index a7ec4fb93b..1d8fbf2542 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs @@ -32,4 +32,9 @@ public abstract class LocalizationResourceBase Contributors.Add(initialContributor); } } + + internal IEnumerable GetSupportedCultures() + { + return Contributors.GetSupportedCultures(); + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index d52fe78943..0f11333490 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -27,4 +27,9 @@ public class LocalizationResourceContributorList : List GetSupportedCultures() + { + return this.SelectMany(c => c.GetSupportedCultures()).Distinct(); + } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs index 1ac41dba06..54c1b9eb04 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs @@ -37,6 +37,11 @@ public abstract class VirtualFileLocalizationResourceContributorBase : ILocaliza GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); } + public IEnumerable GetSupportedCultures() + { + return GetDictionaries().Keys; + } + private Dictionary GetDictionaries() { var dictionaries = _dictionaries; From 37efcb0fc7044bd061a450422cdaafb22ab4cd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 27 Aug 2022 13:39:16 +0300 Subject: [PATCH 23/61] Add test for GetSupportedCultures. --- .../Volo/Abp/Localization/AbpLocalization_Tests.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index d643f163b9..ac848b67f2 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -359,4 +359,11 @@ public class AbpLocalization_Tests : AbpIntegratedTest Date: Sat, 27 Aug 2022 15:56:49 +0300 Subject: [PATCH 24/61] Helper method: CultureHelper.IsCompatibleCulture --- .../Volo/Abp/Localization/CultureHelper.cs | 28 +++++++++++++++++++ .../Abp/Localization/CultureHelper_Tests.cs | 20 +++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs index dded0d794e..a4e55e9ddd 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using JetBrains.Annotations; namespace Volo.Abp.Localization; @@ -59,4 +60,31 @@ public static class CultureHelper { return new CultureInfo(cultureName).Parent.Name; } + + public static bool IsCompatibleCulture( + string sourceCultureName, + string targetCultureName) + { + if (sourceCultureName == targetCultureName) + { + return true; + } + + if (sourceCultureName.Contains("-")) + { + return false; + } + + if (!targetCultureName.Contains("-")) + { + return false; + } + + if (sourceCultureName == GetBaseCultureName(targetCultureName)) + { + return true; + } + + return false; + } } diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs new file mode 100644 index 0000000000..f3bd4a49a7 --- /dev/null +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs @@ -0,0 +1,20 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.Localization; + +public class CultureHelper_Tests +{ + [Fact] + public void IsCompatibleCulture() + { + CultureHelper.IsCompatibleCulture("tr", "tr").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("tr", "tr-TR").ShouldBeTrue(); + + CultureHelper.IsCompatibleCulture("en", "tr").ShouldBeFalse(); + CultureHelper.IsCompatibleCulture("en", "tr-TR").ShouldBeFalse(); + + CultureHelper.IsCompatibleCulture("en-US", "en").ShouldBeFalse(); + CultureHelper.IsCompatibleCulture("en-US", "en-GB").ShouldBeFalse(); + } +} \ No newline at end of file From 1355904c52c43644ac84f40576f1648415c8f4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 27 Aug 2022 16:18:14 +0300 Subject: [PATCH 25/61] Allow to not get localizations from dynamic contributors --- .../Client/RemoteLocalizationContributor.cs | 2 ++ .../AbpDictionaryBasedStringLocalizer.cs | 28 +++++++++++++------ .../AbpStringLocalizerExtensions.cs | 6 ++-- .../Abp/Localization/IAbpStringLocalizer.cs | 3 +- .../ILocalizationResourceContributor.cs | 2 ++ .../LocalizationResourceContributorList.cs | 20 +++++++++++-- ...FileLocalizationResourceContributorBase.cs | 2 ++ .../Abp/Localization/AbpLocalization_Tests.cs | 4 +-- 8 files changed, 51 insertions(+), 16 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index 3f4a038de4..cd9aea88dc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -10,6 +10,8 @@ namespace Volo.Abp.AspNetCore.Mvc.Client; public class RemoteLocalizationContributor : ILocalizationResourceContributor { + public bool IsDynamic => true; + private LocalizationResourceBase _resource; private ICachedApplicationConfigurationClient _applicationConfigurationClient; private ILogger _logger; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 8467749943..f18da9d93e 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -38,12 +38,16 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer ); } - public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers) + public IEnumerable GetAllStrings( + bool includeParentCultures, + bool includeBaseLocalizers, + bool includeDynamicContributors) { return GetAllStrings( CultureInfo.CurrentUICulture.Name, includeParentCultures, - includeBaseLocalizers + includeBaseLocalizers, + includeDynamicContributors ); } @@ -139,7 +143,8 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer protected virtual IReadOnlyList GetAllStrings( string cultureName, bool includeParentCultures = true, - bool includeBaseLocalizers = true) + bool includeBaseLocalizers = true, + bool includeDynamicContributors = true) { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) @@ -154,7 +159,12 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer //TODO: Try/catch is a workaround here! try { - var baseLocalizedString = baseLocalizer.GetAllStrings(includeParentCultures); + var baseLocalizedString = baseLocalizer.GetAllStrings( + includeParentCultures, + includeBaseLocalizers, // Always true, I know! + includeDynamicContributors + ); + foreach (var localizedString in baseLocalizedString) { allStrings[localizedString.Name] = localizedString; @@ -173,18 +183,18 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer //Fill all strings from default culture if (!Resource.DefaultCultureName.IsNullOrEmpty()) { - Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings); + Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings, includeDynamicContributors); } //Overwrite all strings from the language based on country culture if (cultureName.Contains("-")) { - Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings); + Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings, includeDynamicContributors); } } //Overwrite all strings from the original culture - Resource.Contributors.Fill(cultureName, allStrings); + Resource.Contributors.Fill(cultureName, allStrings, includeDynamicContributors); return allStrings.Values.ToImmutableList(); } @@ -209,9 +219,9 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures); } - public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers) + public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) { - return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers); + return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, includeDynamicContributors); } public IEnumerable GetSupportedCultures() diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index d77f6cf4af..e9c839cdf8 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -40,14 +40,16 @@ public static class AbpStringLocalizerExtensions public static IEnumerable GetAllStrings( this IStringLocalizer stringLocalizer, bool includeParentCultures, - bool includeBaseLocalizers) + bool includeBaseLocalizers, + bool includeDynamicContributors) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) { return abpStringLocalizer.GetAllStrings( includeParentCultures, - includeBaseLocalizers + includeBaseLocalizers, + includeDynamicContributors ); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index 15577164b8..c94c943417 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -7,7 +7,8 @@ public interface IAbpStringLocalizer : IStringLocalizer { IEnumerable GetAllStrings( bool includeParentCultures, - bool includeBaseLocalizers + bool includeBaseLocalizers, + bool includeDynamicContributors ); IEnumerable GetSupportedCultures(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs index ebeb57296c..507d78dd18 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs @@ -5,6 +5,8 @@ namespace Volo.Abp.Localization; public interface ILocalizationResourceContributor { + bool IsDynamic { get; } + void Initialize(LocalizationResourceInitializationContext context); LocalizedString GetOrNull(string cultureName, string name); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index 0f11333490..98e63a9feb 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -6,10 +6,18 @@ namespace Volo.Abp.Localization; public class LocalizationResourceContributorList : List { - public LocalizedString GetOrNull(string cultureName, string name) + public LocalizedString GetOrNull( + string cultureName, + string name, + bool includeDynamicContributors = true) { foreach (var contributor in this.Select(x => x).Reverse()) { + if (!includeDynamicContributors && contributor.IsDynamic) + { + continue; + } + var localString = contributor.GetOrNull(cultureName, name); if (localString != null) { @@ -20,10 +28,18 @@ public class LocalizationResourceContributorList : List dictionary) + public void Fill( + string cultureName, + Dictionary dictionary, + bool includeDynamicContributors = true) { foreach (var contributor in this) { + if (!includeDynamicContributors && contributor.IsDynamic) + { + continue; + } + contributor.Fill(cultureName, dictionary); } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs index 54c1b9eb04..8eeb6da55f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs @@ -11,6 +11,8 @@ namespace Volo.Abp.Localization.VirtualFiles; public abstract class VirtualFileLocalizationResourceContributorBase : ILocalizationResourceContributor { + public bool IsDynamic => false; + private readonly string _virtualPath; private IVirtualFileProvider _virtualFileProvider; private Dictionary _dictionaries; diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index ac848b67f2..20823376ea 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -310,7 +310,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest Date: Tue, 30 Aug 2022 11:28:40 +0300 Subject: [PATCH 26/61] IAbpStringLocalizer.GetSupportedCultures method converted to async --- .../Mvc/Client/RemoteLocalizationContributor.cs | 5 +++-- .../AbpDictionaryBasedStringLocalizer.cs | 9 +++++---- .../Abp/Localization/AbpStringLocalizerExtensions.cs | 5 +++-- .../Volo/Abp/Localization/IAbpStringLocalizer.cs | 3 ++- .../Localization/ILocalizationResourceContributor.cs | 3 ++- .../Abp/Localization/LocalizationResourceBase.cs | 5 ----- .../LocalizationResourceContributorList.cs | 12 ++++++++++-- ...VirtualFileLocalizationResourceContributorBase.cs | 5 +++-- .../Volo/Abp/Localization/AbpLocalization_Tests.cs | 5 +++-- 9 files changed, 31 insertions(+), 21 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index cd9aea88dc..221ab4ab15 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; @@ -55,11 +56,11 @@ public class RemoteLocalizationContributor : ILocalizationResourceContributor } } - public IEnumerable GetSupportedCultures() + public Task> GetSupportedCulturesAsync() { /* This contributor does not know all the supported cultures by the remote localization resource, and it is not needed on the client side */ - return Array.Empty(); + return Task.FromResult((IEnumerable)Array.Empty()); } private Dictionary GetResourceOrNull() diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index f18da9d93e..b8bb9f11f7 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Resources; +using System.Threading.Tasks; using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; @@ -51,9 +52,9 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer ); } - public IEnumerable GetSupportedCultures() + public Task> GetSupportedCulturesAsync() { - return Resource.Contributors.GetSupportedCultures(); + return Resource.Contributors.GetSupportedCulturesAsync(); } protected virtual LocalizedString GetLocalizedStringFormatted(string name, params object[] arguments) @@ -224,9 +225,9 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, includeDynamicContributors); } - public IEnumerable GetSupportedCultures() + public Task> GetSupportedCulturesAsync() { - return _innerLocalizer.GetSupportedCultures(); + return _innerLocalizer.GetSupportedCulturesAsync(); } } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index e9c839cdf8..7c4045ffac 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.Localization; using Volo.Abp.DynamicProxy; @@ -58,12 +59,12 @@ public static class AbpStringLocalizerExtensions ); } - public static IEnumerable GetSupportedCultures(this IStringLocalizer localizer) + public static async Task> GetSupportedCulturesAsync(this IStringLocalizer localizer) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(localizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) { - return abpStringLocalizer.GetSupportedCultures(); + return await abpStringLocalizer.GetSupportedCulturesAsync(); } return Array.Empty(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index c94c943417..0cbbb3ea74 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; @@ -11,5 +12,5 @@ public interface IAbpStringLocalizer : IStringLocalizer bool includeDynamicContributors ); - IEnumerable GetSupportedCultures(); + Task> GetSupportedCulturesAsync(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs index 507d78dd18..67236b38ac 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; @@ -13,5 +14,5 @@ public interface ILocalizationResourceContributor void Fill(string cultureName, Dictionary dictionary); - IEnumerable GetSupportedCultures(); + Task> GetSupportedCulturesAsync(); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs index 1d8fbf2542..a7ec4fb93b 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceBase.cs @@ -32,9 +32,4 @@ public abstract class LocalizationResourceBase Contributors.Add(initialContributor); } } - - internal IEnumerable GetSupportedCultures() - { - return Contributors.GetSupportedCultures(); - } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index 98e63a9feb..3a2fb25d5b 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; @@ -44,8 +45,15 @@ public class LocalizationResourceContributorList : List GetSupportedCultures() + internal async Task> GetSupportedCulturesAsync() { - return this.SelectMany(c => c.GetSupportedCultures()).Distinct(); + var cultures = new List(); + + foreach (var contributor in this) + { + cultures.AddRange(await contributor.GetSupportedCulturesAsync()); + } + + return cultures; } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs index 8eeb6da55f..4eb9de34c4 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Localization; @@ -39,9 +40,9 @@ public abstract class VirtualFileLocalizationResourceContributorBase : ILocaliza GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); } - public IEnumerable GetSupportedCultures() + public Task> GetSupportedCulturesAsync() { - return GetDictionaries().Keys; + return Task.FromResult((IEnumerable)GetDictionaries().Keys); } private Dictionary GetDictionaries() diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index 20823376ea..ee0e929e32 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -1,5 +1,6 @@ using System.Globalization; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Localization; using Shouldly; using Volo.Abp.Localization.TestResources.Source; @@ -361,9 +362,9 @@ public class AbpLocalization_Tests : AbpIntegratedTest Date: Tue, 30 Aug 2022 12:22:54 +0300 Subject: [PATCH 27/61] Introduce IStringLocalizer.GetAllStrings and overloads. --- .../Client/RemoteLocalizationContributor.cs | 30 +++++ .../AbpDictionaryBasedStringLocalizer.cs | 106 ++++++++++++++++++ .../AbpStringLocalizerExtensions.cs | 44 ++++++++ .../Abp/Localization/IAbpStringLocalizer.cs | 10 ++ .../ILocalizationResourceContributor.cs | 4 +- .../LocalizationResourceContributorList.cs | 16 +++ ...FileLocalizationResourceContributorBase.cs | 6 + 7 files changed, 215 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index 221ab4ab15..dc116d114d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -56,6 +56,20 @@ public class RemoteLocalizationContributor : ILocalizationResourceContributor } } + public async Task FillAsync(string cultureName, Dictionary dictionary) + { + var resource = await GetResourceOrNullAsync(); + if (resource == null) + { + return; + } + + foreach (var keyValue in resource) + { + dictionary[keyValue.Key] = new LocalizedString(keyValue.Key, keyValue.Value); + } + } + public Task> GetSupportedCulturesAsync() { /* This contributor does not know all the supported cultures by the @@ -78,4 +92,20 @@ public class RemoteLocalizationContributor : ILocalizationResourceContributor return resource; } + + private async Task> GetResourceOrNullAsync() + { + var applicationConfigurationDto = await _applicationConfigurationClient.GetAsync(); + + var resource = applicationConfigurationDto + .Localization.Values + .GetOrDefault(_resource.ResourceName); + + if (resource == null) + { + _logger.LogWarning($"Could not find the localization resource {_resource.ResourceName} on the remote server!"); + } + + return resource; + } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index b8bb9f11f7..d6bf1460d6 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -38,6 +38,14 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer includeParentCultures ); } + + public async Task> GetAllStringsAsync(bool includeParentCultures) + { + return await GetAllStringsAsync( + CultureInfo.CurrentUICulture.Name, + includeParentCultures + ); + } public IEnumerable GetAllStrings( bool includeParentCultures, @@ -52,6 +60,19 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer ); } + public async Task> GetAllStringsAsync( + bool includeParentCultures, + bool includeBaseLocalizers, + bool includeDynamicContributors) + { + return await GetAllStringsAsync( + CultureInfo.CurrentUICulture.Name, + includeParentCultures, + includeBaseLocalizers, + includeDynamicContributors + ); + } + public Task> GetSupportedCulturesAsync() { return Resource.Contributors.GetSupportedCulturesAsync(); @@ -200,6 +221,77 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return allStrings.Values.ToImmutableList(); } + protected virtual async Task> GetAllStringsAsync( + string cultureName, + bool includeParentCultures = true, + bool includeBaseLocalizers = true, + bool includeDynamicContributors = true) + { + //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) + + var allStrings = new Dictionary(); + + if (includeBaseLocalizers) + { + foreach (var baseLocalizer in BaseLocalizers.Select(l => l)) + { + using (CultureHelper.Use(CultureInfo.GetCultureInfo(cultureName))) + { + //TODO: Try/catch is a workaround here! + try + { + var baseLocalizedString = await baseLocalizer.GetAllStringsAsync( + includeParentCultures, + includeBaseLocalizers, // Always true, I know! + includeDynamicContributors + ); + + foreach (var localizedString in baseLocalizedString) + { + allStrings[localizedString.Name] = localizedString; + } + } + catch (MissingManifestResourceException) + { + + } + } + } + } + + if (includeParentCultures) + { + //Fill all strings from default culture + if (!Resource.DefaultCultureName.IsNullOrEmpty()) + { + await Resource.Contributors.FillAsync( + Resource.DefaultCultureName, + allStrings, + includeDynamicContributors + ); + } + + //Overwrite all strings from the language based on country culture + if (cultureName.Contains("-")) + { + await Resource.Contributors.FillAsync( + CultureHelper.GetBaseCultureName(cultureName), + allStrings, + includeDynamicContributors + ); + } + } + + //Overwrite all strings from the original culture + await Resource.Contributors.FillAsync( + cultureName, + allStrings, + includeDynamicContributors + ); + + return allStrings.Values.ToImmutableList(); + } + public class CultureWrapperStringLocalizer : IAbpStringLocalizer { private readonly string _cultureName; @@ -225,6 +317,20 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, includeDynamicContributors); } + public Task> GetAllStringsAsync(bool includeParentCultures) + { + return _innerLocalizer.GetAllStringsAsync(includeParentCultures); + } + + public Task> GetAllStringsAsync(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) + { + return _innerLocalizer.GetAllStringsAsync( + includeParentCultures, + includeBaseLocalizers, + includeDynamicContributors + ); + } + public Task> GetSupportedCulturesAsync() { return _innerLocalizer.GetSupportedCulturesAsync(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index 7c4045ffac..9b3bb2c201 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -58,6 +58,27 @@ public static class AbpStringLocalizerExtensions includeParentCultures ); } + + public static async Task> GetAllStringsAsync( + this IStringLocalizer stringLocalizer, + bool includeParentCultures, + bool includeBaseLocalizers, + bool includeDynamicContributors) + { + var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); + if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) + { + return await abpStringLocalizer.GetAllStringsAsync( + includeParentCultures, + includeBaseLocalizers, + includeDynamicContributors + ); + } + + return stringLocalizer.GetAllStrings( + includeParentCultures + ); + } public static async Task> GetSupportedCulturesAsync(this IStringLocalizer localizer) { @@ -69,4 +90,27 @@ public static class AbpStringLocalizerExtensions return Array.Empty(); } + + public static Task> GetAllStringsAsync( + this IStringLocalizer localizer) + { + return localizer.GetAllStringsAsync(includeParentCultures: true); + } + + public static Task> GetAllStringsAsync( + this IStringLocalizer localizer, + bool includeParentCultures) + { + Check.NotNull(localizer, nameof(localizer)); + + var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(localizer)).GetInternalLocalizer(); + if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) + { + return abpStringLocalizer.GetAllStringsAsync(includeParentCultures: includeParentCultures); + } + + return Task.FromResult( + localizer.GetAllStrings(includeParentCultures: true) + ); + } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index 0cbbb3ea74..59fbbcb7b4 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -12,5 +12,15 @@ public interface IAbpStringLocalizer : IStringLocalizer bool includeDynamicContributors ); + Task> GetAllStringsAsync( + bool includeParentCultures + ); + + Task> GetAllStringsAsync( + bool includeParentCultures, + bool includeBaseLocalizers, + bool includeDynamicContributors + ); + Task> GetSupportedCulturesAsync(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs index 67236b38ac..2a79d20821 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs @@ -13,6 +13,8 @@ public interface ILocalizationResourceContributor LocalizedString GetOrNull(string cultureName, string name); void Fill(string cultureName, Dictionary dictionary); - + + Task FillAsync(string cultureName, Dictionary dictionary); + Task> GetSupportedCulturesAsync(); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index 3a2fb25d5b..6df15920da 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -44,6 +44,22 @@ public class LocalizationResourceContributorList : List dictionary, + bool includeDynamicContributors = true) + { + foreach (var contributor in this) + { + if (!includeDynamicContributors && contributor.IsDynamic) + { + continue; + } + + await contributor.FillAsync(cultureName, dictionary); + } + } internal async Task> GetSupportedCulturesAsync() { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs index 4eb9de34c4..15b45efaff 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs @@ -40,6 +40,12 @@ public abstract class VirtualFileLocalizationResourceContributorBase : ILocaliza GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); } + public Task FillAsync(string cultureName, Dictionary dictionary) + { + Fill(cultureName, dictionary); + return Task.CompletedTask; + } + public Task> GetSupportedCulturesAsync() { return Task.FromResult((IEnumerable)GetDictionaries().Keys); From c0a8fdac1922b8fdae56cd05e5911e49cfd76fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 30 Aug 2022 12:27:20 +0300 Subject: [PATCH 28/61] Use GetAllStringsAsync in AbpApplicationConfigurationAppService Also removed body of AbpLocalizationScriptController.GetAsync since it was not implemented yet. --- .../AbpApplicationConfigurationAppService.cs | 2 +- .../Localization/AbpLocalizationScriptController.cs | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index e2557aac0c..6d58172a16 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -232,7 +232,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resourceName); if (localizer != null) { - foreach (var localizedString in localizer.GetAllStrings()) + foreach (var localizedString in await localizer.GetAllStringsAsync()) { dictionary[localizedString.Name] = localizedString.Value; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs index f4e22e0f41..7b1b26ec71 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; @@ -29,14 +30,6 @@ public class AbpLocalizationScriptController [Route("{culture}")] public async Task GetAsync(string culture) { - // TODO: Should not get dynamic overloads, but how? What if we do? (Can be switched to host?) - using (CultureHelper.Use(culture)) - { - foreach (var resource in LocalizationOptions.Resources.Values) - { - var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resource.ResourceName); - localizer?.GetAllStrings(); - } - } + throw new NotImplementedException(); } } \ No newline at end of file From 7e36b9e911f3f6376ed39398bf2ee9dcd8c471ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 30 Aug 2022 12:59:22 +0300 Subject: [PATCH 29/61] Remove old TODOs --- .../Volo/Abp/Localization/AbpStringLocalizerFactory.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 92fa771d64..c346d9ee51 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -18,7 +18,6 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca protected IExternalLocalizationStore ExternalLocalizationStore { get; } protected ConcurrentDictionary LocalizerCache { get; } - //TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency. public AbpStringLocalizerFactory( ResourceManagerStringLocalizerFactory innerFactory, IOptions abpLocalizationOptions, @@ -108,8 +107,6 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca public virtual IStringLocalizer Create(string baseName, string location) { - //TODO: Investigate when this is called? - return InnerFactory.Create(baseName, location); } From ccd13c95d55abaa12702a11b19d79ab2046cff2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 30 Aug 2022 16:13:17 +0300 Subject: [PATCH 30/61] Introduce async version of StringLocalizerFactory.CreateByResourceNameOrNull. --- .../AbpPageToolbarButtonViewComponent.cs | 9 +- .../AbpApplicationConfigurationAppService.cs | 2 +- .../Components/UiNotificationAlert.razor.cs | 13 +- .../AbpStringLocalizerFactoryExtensions.cs | 31 +++- .../IAbpStringLocalizerFactory.cs | 6 +- .../Localization/IAsyncLocalizableString.cs | 9 ++ .../Abp/Localization/ILocalizableString.cs | 2 +- .../Abp/Localization/LocalizableString.cs | 45 +++++- .../LocalizableStringExtensions.cs | 19 +++ .../Localization/AbpStringLocalizerFactory.cs | 143 +++++++++++++++++- .../External/IExternalLocalizationStore.cs | 3 + .../External/NullExternalLocalizationStore.cs | 5 + .../AbpStringLocalizerFactory_Tests.cs | 22 ++- 13 files changed, 289 insertions(+), 20 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/IAsyncLocalizableString.cs create mode 100644 framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableStringExtensions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageToolbar/Button/AbpPageToolbarButtonViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageToolbar/Button/AbpPageToolbarButtonViewComponent.cs index 097fad5f40..56ae47f0c8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageToolbar/Button/AbpPageToolbarButtonViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Pages/Shared/Components/AbpPageToolbar/Button/AbpPageToolbarButtonViewComponent.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; @@ -15,7 +16,7 @@ public class AbpPageToolbarButtonViewComponent : AbpViewComponent StringLocalizerFactory = stringLocalizerFactory; } - public IViewComponentResult Invoke( + public async Task InvokeAsync( ILocalizableString text, string name, string icon, @@ -31,11 +32,11 @@ public class AbpPageToolbarButtonViewComponent : AbpViewComponent return View( "~/Pages/Shared/Components/AbpPageToolbar/Button/Default.cshtml", new AbpPageToolbarButtonViewModel( - text.Localize(StringLocalizerFactory), + await text.LocalizeAsync(StringLocalizerFactory), name, icon, id, - busyText?.Localize(StringLocalizerFactory), + busyText == null ? null : await busyText.LocalizeAsync(StringLocalizerFactory), iconType, type, size, diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 6d58172a16..37c509a285 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -229,7 +229,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp { var dictionary = new Dictionary(); - var localizer = StringLocalizerFactory.CreateByResourceNameOrNull(resourceName); + var localizer = await StringLocalizerFactory.CreateByResourceNameOrNullAsync(resourceName); if (localizer != null) { foreach (var localizedString in await localizer.GetAllStringsAsync()) diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/UiNotificationAlert.razor.cs b/framework/src/Volo.Abp.BlazoriseUI/Components/UiNotificationAlert.razor.cs index a1a079fe27..359ea1a422 100644 --- a/framework/src/Volo.Abp.BlazoriseUI/Components/UiNotificationAlert.razor.cs +++ b/framework/src/Volo.Abp.BlazoriseUI/Components/UiNotificationAlert.razor.cs @@ -5,6 +5,7 @@ using Blazorise.Snackbar; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Components.Notifications; +using Volo.Abp.Localization; namespace Volo.Abp.BlazoriseUI.Components; @@ -54,13 +55,15 @@ public partial class UiNotificationAlert : ComponentBase, IDisposable Title = e.Title; Options = e.Options; - var okButtonText = Options?.OkButtonText?.Localize(StringLocalizerFactory); + var okButtonText = Options?.OkButtonText == null + ? null + : await Options.OkButtonText.LocalizeAsync(StringLocalizerFactory); await SnackbarStack.PushAsync(Message, Title, GetSnackbarColor(e.NotificationType), (options) => - { - options.CloseButtonIcon = IconName.Times; - options.ActionButtonText = okButtonText; - }); + { + options.CloseButtonIcon = IconName.Times; + options.ActionButtonText = okButtonText; + }); } public virtual void Dispose() diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs index ccd9718de9..8aa2515a54 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -1,4 +1,5 @@ -using JetBrains.Annotations; +using System.Threading.Tasks; +using JetBrains.Annotations; using Volo.Abp; namespace Microsoft.Extensions.Localization; @@ -34,4 +35,32 @@ public static class AbpStringLocalizerFactoryExtensions return localizer; } + + [ItemCanBeNull] + public static async Task CreateByResourceNameOrNullAsync( + this IStringLocalizerFactory localizerFactory, + string resourceName) + { + var abpLocalizerFactory = localizerFactory as IAbpStringLocalizerFactory; + if (abpLocalizerFactory == null) + { + return null; + } + + return await abpLocalizerFactory.CreateByResourceNameOrNullAsync(resourceName); + } + + [NotNull] + public async static Task CreateByResourceNameAsync( + this IStringLocalizerFactory localizerFactory, + string resourceName) + { + var localizer = await localizerFactory.CreateByResourceNameOrNullAsync(resourceName); + if (localizer == null) + { + throw new AbpException("Couldn't find a localizer with given resource name: " + resourceName); + } + + return localizer; + } } diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs index d9ae96c324..8f6699a13d 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactory.cs @@ -1,4 +1,5 @@ -using JetBrains.Annotations; +using System.Threading.Tasks; +using JetBrains.Annotations; namespace Microsoft.Extensions.Localization; @@ -9,4 +10,7 @@ public interface IAbpStringLocalizerFactory [CanBeNull] IStringLocalizer CreateByResourceNameOrNull([NotNull] string resourceName); + + [ItemCanBeNull] + Task CreateByResourceNameOrNullAsync([NotNull] string resourceName); } diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/IAsyncLocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/IAsyncLocalizableString.cs new file mode 100644 index 0000000000..b8389d546f --- /dev/null +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/IAsyncLocalizableString.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization; + +public interface IAsyncLocalizableString +{ + Task LocalizeAsync(IStringLocalizerFactory stringLocalizerFactory); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/ILocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/ILocalizableString.cs index 2aecd696ac..d04e61a257 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/ILocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/ILocalizableString.cs @@ -5,4 +5,4 @@ namespace Volo.Abp.Localization; public interface ILocalizableString { LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index ef2027b415..009e4ec445 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -1,10 +1,11 @@ using System; +using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.Extensions.Localization; namespace Volo.Abp.Localization; -public class LocalizableString : ILocalizableString +public class LocalizableString : ILocalizableString, IAsyncLocalizableString { [CanBeNull] public string ResourceName { get; } @@ -54,6 +55,29 @@ public class LocalizableString : ILocalizableString return result; } + + public async Task LocalizeAsync(IStringLocalizerFactory stringLocalizerFactory) + { + var localizer = await CreateStringLocalizerOrNullAsync(stringLocalizerFactory); + if (localizer == null) + { + throw new AbpException($"Set {nameof(ResourceName)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); + } + + var result = localizer[Name]; + + if (result.ResourceNotFound && ResourceName != null) + { + /* Search in the default resource if not found in the provided resource */ + localizer = stringLocalizerFactory.CreateDefaultOrNull(); + if (localizer != null) + { + result = localizer[Name]; + } + } + + return result; + } private IStringLocalizer CreateStringLocalizerOrNull(IStringLocalizerFactory stringLocalizerFactory) { @@ -73,6 +97,25 @@ public class LocalizableString : ILocalizableString return stringLocalizerFactory.CreateDefaultOrNull(); } + + private async Task CreateStringLocalizerOrNullAsync(IStringLocalizerFactory stringLocalizerFactory) + { + if (ResourceType != null) + { + return stringLocalizerFactory.Create(ResourceType); + } + + if (ResourceName != null) + { + var localizerByName = await stringLocalizerFactory.CreateByResourceNameOrNullAsync(ResourceName); + if (localizerByName != null) + { + return localizerByName; + } + } + + return stringLocalizerFactory.CreateDefaultOrNull(); + } public static LocalizableString Create([NotNull] string name) { diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableStringExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableStringExtensions.cs new file mode 100644 index 0000000000..b7cff0819f --- /dev/null +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableStringExtensions.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; + +namespace Volo.Abp.Localization; + +public static class LocalizableStringExtensions +{ + public static async Task LocalizeAsync( + this ILocalizableString localizableString, + IStringLocalizerFactory stringLocalizerFactory) + { + if (localizableString is IAsyncLocalizableString asyncLocalizableString) + { + return await asyncLocalizableString.LocalizeAsync(stringLocalizerFactory); + } + + return localizableString.Localize(stringLocalizerFactory); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index c346d9ee51..b89a54abd9 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -2,11 +2,14 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Volo.Abp.Localization.External; +using Volo.Abp.Threading; namespace Volo.Abp.Localization; @@ -17,6 +20,7 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca protected IServiceProvider ServiceProvider { get; } protected IExternalLocalizationStore ExternalLocalizationStore { get; } protected ConcurrentDictionary LocalizerCache { get; } + protected SemaphoreSlim LocalizerCacheSemaphore { get; } = new(1, 1); public AbpStringLocalizerFactory( ResourceManagerStringLocalizerFactory innerFactory, @@ -33,6 +37,11 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca } public virtual IStringLocalizer Create(Type resourceType) + { + return Create(resourceType, lockCache: true); + } + + private IStringLocalizer Create(Type resourceType, bool lockCache) { var resource = AbpLocalizationOptions.Resources.GetOrNull(resourceType); if (resource == null) @@ -40,10 +49,17 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca return InnerFactory.Create(resourceType); } - return CreateInternal(resource.ResourceName, resource); + return CreateInternal(resource.ResourceName, resource, lockCache); } public IStringLocalizer CreateByResourceNameOrNull(string resourceName) + { + return CreateByResourceNameOrNullInternal(resourceName, lockCache: true); + } + + private IStringLocalizer CreateByResourceNameOrNullInternal( + string resourceName, + bool lockCache) { var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceName); if (resource == null) @@ -55,23 +71,102 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca } } - return CreateInternal(resourceName, resource); + return CreateInternal(resourceName, resource, lockCache); + } + + public Task CreateByResourceNameOrNullAsync(string resourceName) + { + return CreateByResourceNameOrNullInternalAsync(resourceName, lockCache: true); } - private IStringLocalizer CreateInternal(string resourceName, LocalizationResourceBase resource) + private async Task CreateByResourceNameOrNullInternalAsync( + string resourceName, + bool lockCache) + { + var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceName); + if (resource == null) + { + resource = await ExternalLocalizationStore.GetResourceOrNullAsync(resourceName); + if (resource == null) + { + return null; + } + } + + return await CreateInternalAsync(resourceName, resource, lockCache); + } + + private IStringLocalizer CreateInternal( + string resourceName, + LocalizationResourceBase resource, + bool lockCache) { if (LocalizerCache.TryGetValue(resourceName, out var cacheItem)) { return cacheItem.Localizer; } - lock (LocalizerCache) + IStringLocalizer GetOrCreateLocalizer() { + // Double check + if (LocalizerCache.TryGetValue(resourceName, out var cacheItem2)) + { + return cacheItem2.Localizer; + } + return LocalizerCache.GetOrAdd( resourceName, _ => CreateStringLocalizerCacheItem(resource) ).Localizer; } + + if (lockCache) + { + using (LocalizerCacheSemaphore.Lock()) + { + return GetOrCreateLocalizer(); + } + } + else + { + return GetOrCreateLocalizer(); + } + } + + private async Task CreateInternalAsync( + string resourceName, + LocalizationResourceBase resource, + bool lockCache) + { + if (LocalizerCache.TryGetValue(resourceName, out var cacheItem)) + { + return cacheItem.Localizer; + } + + async Task GetOrCreateLocalizerAsync() + { + // Double check + if (LocalizerCache.TryGetValue(resourceName, out var cacheItem2)) + { + return cacheItem2.Localizer; + } + + var newCacheItem = await CreateStringLocalizerCacheItemAsync(resource); + LocalizerCache[resourceName] = newCacheItem; + return newCacheItem.Localizer; + } + + if (lockCache) + { + using (await LocalizerCacheSemaphore.LockAsync()) + { + return await GetOrCreateLocalizerAsync(); + } + } + else + { + return await GetOrCreateLocalizerAsync(); + } } private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResourceBase resource) @@ -97,13 +192,51 @@ public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLoca resource, resource .BaseResourceNames - .Select(CreateByResourceNameOrNull) + .Select(x => CreateByResourceNameOrNullInternal(x, lockCache: false)) .Where(x => x != null) .ToList(), AbpLocalizationOptions ) ); } + + private async Task CreateStringLocalizerCacheItemAsync(LocalizationResourceBase resource) + { + foreach (var globalContributorType in AbpLocalizationOptions.GlobalContributors) + { + resource.Contributors.Add( + Activator + .CreateInstance(globalContributorType) + .As() + ); + } + + var context = new LocalizationResourceInitializationContext(resource, ServiceProvider); + + foreach (var contributor in resource.Contributors) + { + contributor.Initialize(context); + } + + var baseLocalizers = new List(); + + foreach (var baseResourceName in resource.BaseResourceNames) + { + var baseLocalizer = await CreateByResourceNameOrNullInternalAsync(baseResourceName, lockCache: false); + if (baseLocalizer != null) + { + baseLocalizers.Add(baseLocalizer); + } + } + + return new StringLocalizerCacheItem( + new AbpDictionaryBasedStringLocalizer( + resource, + baseLocalizers, + AbpLocalizationOptions + ) + ); + } public virtual IStringLocalizer Create(string baseName, string location) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index fa03a6bbff..c04160eea1 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -8,5 +8,8 @@ public interface IExternalLocalizationStore [CanBeNull] LocalizationResourceBase GetResourceOrNull([NotNull] string resourceName); + [ItemCanBeNull] + Task GetResourceOrNullAsync([NotNull] string resourceName); + Task GetResourceNamesAsync(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index 0c55919db2..a87bf74d71 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -11,6 +11,11 @@ public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingle return null; } + public Task GetResourceOrNullAsync(string resourceName) + { + return Task.FromResult(null); + } + public Task GetResourceNamesAsync() { return Task.FromResult(Array.Empty()); diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs index 352a7ea3a3..8cb0fcb833 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpStringLocalizerFactory_Tests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Localization; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; using Shouldly; using Volo.Abp.DynamicProxy; using Volo.Abp.Testing; @@ -32,6 +33,17 @@ public class AbpStringLocalizerFactory_Tests : AbpIntegratedTest _factory.CreateByResourceName("UnknownResourceName") ); } + + [Fact] + public async Task Should_Throw_Exception_For_Unknown_Resource_Names_Async() + { + await Assert.ThrowsAsync( + async () => await _factory.CreateByResourceNameAsync("UnknownResourceName") + ); + } } \ No newline at end of file From af39e55416097b21b51ec9fcfa190bb0660d2f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 10:23:46 +0300 Subject: [PATCH 31/61] Remove option: GetFromExternalStore --- .../AbpApplicationConfigurationAppService.cs | 18 +++++++++--------- .../External/AbpExternalLocalizationOptions.cs | 5 ----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 37c509a285..8a3a004d63 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -215,15 +215,15 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync()); - var resourceNames = _localizationOptions.Resources.Values.Select(x => x.ResourceName); - - if (_externalLocalizationOptions.GetFromExternalStore) - { - var externalResourceNames = await LazyServiceProvider - .LazyGetRequiredService() - .GetResourceNamesAsync(); - resourceNames = resourceNames.Union(externalResourceNames); - } + var externalResourceNames = await LazyServiceProvider + .LazyGetRequiredService() + .GetResourceNamesAsync(); + + var resourceNames = _localizationOptions + .Resources + .Values + .Select(x => x.ResourceName) + .Union(externalResourceNames); foreach (var resourceName in resourceNames) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs index bc2a19a26c..617ca3cf4e 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs @@ -6,9 +6,4 @@ public class AbpExternalLocalizationOptions /// Default: true. /// public bool SaveToExternalStore { get; set; } = true; - - /// - /// Default: false. - /// - public bool GetFromExternalStore { get; set; } } \ No newline at end of file From b82d93a4abe89302d25bdd002f324dd05546ff7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 11:07:09 +0300 Subject: [PATCH 32/61] Introduce IAbpApplicationLocalizationAppService --- .../ApplicationLocalizationDto.cs | 8 +++ .../ApplicationLocalizationResourceDto.cs | 10 +++ .../IAbpApplicationConfigurationAppService.cs | 2 +- .../IAbpApplicationLocalizationAppService.cs | 9 +++ .../AbpApplicationLocalizationAppService.cs | 69 +++++++++++++++++++ .../AbpApplicationLocalizationController.cs | 24 +++++++ ...ApplicationLocalizationScriptController.cs | 35 ++++++++++ .../AbpLocalizationScriptController.cs | 35 ---------- .../External/IExternalLocalizationStore.cs | 2 + .../External/NullExternalLocalizationStore.cs | 5 ++ 10 files changed, 163 insertions(+), 36 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs new file mode 100644 index 0000000000..79e31bb712 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public class ApplicationLocalizationDto +{ + public Dictionary Resources { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs new file mode 100644 index 0000000000..9c1256ec95 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public class ApplicationLocalizationResourceDto +{ + public Dictionary Texts { get; set; } + + public List BaseResources { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs index 9c8fd3d414..1f56d97e42 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs @@ -6,4 +6,4 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; public interface IAbpApplicationConfigurationAppService : IApplicationService { Task GetAsync(); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs new file mode 100644 index 0000000000..bebbcdd987 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public interface IAbpApplicationLocalizationAppService : IApplicationService +{ + Task GetAsync(string culture); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs new file mode 100644 index 0000000000..8aa949a8b8 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.Application.Services; +using Volo.Abp.Localization; +using Volo.Abp.Localization.External; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public class AbpApplicationLocalizationAppService : + ApplicationService, + IAbpApplicationLocalizationAppService +{ + protected IExternalLocalizationStore ExternalLocalizationStore { get; } + protected AbpLocalizationOptions LocalizationOptions { get; } + + public AbpApplicationLocalizationAppService( + IExternalLocalizationStore externalLocalizationStore, + IOptions localizationOptions) + { + ExternalLocalizationStore = externalLocalizationStore; + LocalizationOptions = localizationOptions.Value; + } + + public async Task GetAsync(string culture) + { + using (CultureHelper.Use(culture)) + { + var localizationConfig = new ApplicationLocalizationDto(); + + var resources = LocalizationOptions + .Resources + .Values + .Union( + await ExternalLocalizationStore.GetResourcesAsync() + ); + + foreach (var resource in resources) + { + var dictionary = new Dictionary(); + + var localizer = await StringLocalizerFactory.CreateByResourceNameOrNullAsync(resource.ResourceName); + if (localizer != null) + { + var localizedStrings = await localizer.GetAllStringsAsync( + includeParentCultures: true, + includeBaseLocalizers: false, //TODO: Test this! + includeDynamicContributors: false + ); + + foreach (var localizedString in localizedStrings) + { + dictionary[localizedString.Name] = localizedString.Value; + } + } + + localizationConfig.Resources[resource.ResourceName] = + new ApplicationLocalizationResourceDto { + Texts = dictionary, + BaseResources = resource.BaseResourceNames + }; + } + + return localizationConfig; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs new file mode 100644 index 0000000000..4b5c6de034 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +[Area("abp")] +[RemoteService(Name = "abp")] +[Route("api/abp/application-localization")] +public class AbpApplicationLocalizationController: AbpControllerBase, IAbpApplicationLocalizationAppService +{ + private readonly IAbpApplicationLocalizationAppService _localizationAppService; + + public AbpApplicationLocalizationController(IAbpApplicationLocalizationAppService localizationAppService) + { + _localizationAppService = localizationAppService; + } + + [HttpGet] + [Route("{culture}")] + public virtual async Task GetAsync(string culture) + { + return await _localizationAppService.GetAsync(culture); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs new file mode 100644 index 0000000000..550d29e2c4 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using Volo.Abp.Auditing; +using Volo.Abp.Http; +using Volo.Abp.Localization; + +namespace Volo.Abp.AspNetCore.Mvc.Localization; + +[Area("Abp")] +[Route("Abp/ApplicationLocalizationScript")] +[DisableAuditing] +[RemoteService(false)] +[ApiExplorerSettings(IgnoreApi = true)] +public class AbpApplicationLocalizationScriptController : AbpController +{ + protected IAbpApplicationLocalizationAppService LocalizationAppService { get; } + + public AbpApplicationLocalizationScriptController( + IAbpApplicationLocalizationAppService localizationAppService) + { + LocalizationAppService = localizationAppService; + } + + [HttpGet] + [Route("{culture}")] + [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] + public async Task GetAsync(string culture) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs deleted file mode 100644 index 7b1b26ec71..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpLocalizationScriptController.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Options; -using Volo.Abp.Auditing; -using Volo.Abp.Localization; - -namespace Volo.Abp.AspNetCore.Mvc.Localization; - -[Area("Abp")] -[Route("Abp/LocalizationScript")] -[DisableAuditing] -[RemoteService(false)] -[ApiExplorerSettings(IgnoreApi = true)] -public class AbpLocalizationScriptController -{ - protected AbpLocalizationOptions LocalizationOptions { get; } - protected IStringLocalizerFactory StringLocalizerFactory { get; } - - public AbpLocalizationScriptController( - IOptions localizationOptions, - IStringLocalizerFactory stringLocalizerFactory) - { - StringLocalizerFactory = stringLocalizerFactory; - LocalizationOptions = localizationOptions.Value; - } - - [HttpGet] - [Route("{culture}")] - public async Task GetAsync(string culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs index c04160eea1..cd48bb1bd9 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/IExternalLocalizationStore.cs @@ -12,4 +12,6 @@ public interface IExternalLocalizationStore Task GetResourceOrNullAsync([NotNull] string resourceName); Task GetResourceNamesAsync(); + + Task GetResourcesAsync(); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs index a87bf74d71..508f947981 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/NullExternalLocalizationStore.cs @@ -20,4 +20,9 @@ public class NullExternalLocalizationStore : IExternalLocalizationStore, ISingle { return Task.FromResult(Array.Empty()); } + + public Task GetResourcesAsync() + { + return Task.FromResult(Array.Empty()); + } } \ No newline at end of file From dd3e0c94411892c978f39f8dee70324852517752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 11:59:30 +0300 Subject: [PATCH 33/61] Update AbpApplicationLocalizationAppService.cs --- .../AbpApplicationLocalizationAppService.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 8aa949a8b8..404186c254 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -28,14 +28,16 @@ public class AbpApplicationLocalizationAppService : { using (CultureHelper.Use(culture)) { - var localizationConfig = new ApplicationLocalizationDto(); - var resources = LocalizationOptions .Resources .Values .Union( await ExternalLocalizationStore.GetResourcesAsync() - ); + ).ToArray(); + + var localizationConfig = new ApplicationLocalizationDto { + Resources = new Dictionary(resources.Length) + }; foreach (var resource in resources) { @@ -46,7 +48,7 @@ public class AbpApplicationLocalizationAppService : { var localizedStrings = await localizer.GetAllStringsAsync( includeParentCultures: true, - includeBaseLocalizers: false, //TODO: Test this! + includeBaseLocalizers: true, //TODO: Test this! includeDynamicContributors: false ); From 01824061d318cea7ae9555be8ffc186f14506653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 14:08:02 +0300 Subject: [PATCH 34/61] Added AbpApplicationLocalizationClientProxy --- ...cationLocalizationClientProxy.Generated.cs | 25 ++++++++ .../AbpApplicationLocalizationClientProxy.cs | 7 +++ .../ClientProxies/abp-generate-proxy.json | 57 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs new file mode 100644 index 0000000000..fae18f7d2f --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs @@ -0,0 +1,25 @@ +// This file is automatically generated by ABP framework to use MVC Controllers from CSharp +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Http.Client; +using Volo.Abp.Http.Modeling; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Http.Client.ClientProxying; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +// ReSharper disable once CheckNamespace +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; + +[Dependency(ReplaceServices = true)] +[ExposeServices(typeof(IAbpApplicationLocalizationAppService), typeof(AbpApplicationLocalizationClientProxy))] +public partial class AbpApplicationLocalizationClientProxy : ClientProxyBase, IAbpApplicationLocalizationAppService +{ + public virtual async Task GetAsync(string culture) + { + return await RequestAsync(nameof(GetAsync), new ClientProxyRequestTypeValue + { + { typeof(string), culture } + }); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.cs new file mode 100644 index 0000000000..11bef4cecf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.cs @@ -0,0 +1,7 @@ +// This file is part of AbpApplicationLocalizationClientProxy, you can customize it here +// ReSharper disable once CheckNamespace +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; + +public partial class AbpApplicationLocalizationClientProxy +{ +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json index bf15515078..fcc79ecc89 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json @@ -7,6 +7,8 @@ "Pages.Abp.MultiTenancy.AbpTenantController": { "controllerName": "AbpTenant", "controllerGroupName": "AbpTenant", + "isRemoteService": true, + "apiVersion": null, "type": "Pages.Abp.MultiTenancy.AbpTenantController", "interfaces": [ { @@ -93,6 +95,8 @@ "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController": { "controllerName": "AbpApplicationConfiguration", "controllerGroupName": "AbpApplicationConfiguration", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController", "interfaces": [ { @@ -117,9 +121,62 @@ } } }, + "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationLocalizationController": { + "controllerName": "AbpApplicationLocalization", + "controllerGroupName": "AbpApplicationLocalization", + "isRemoteService": true, + "apiVersion": null, + "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationLocalizationController", + "interfaces": [ + { + "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.IAbpApplicationLocalizationAppService" + } + ], + "actions": { + "GetAsyncByCulture": { + "uniqueName": "GetAsyncByCulture", + "name": "GetAsync", + "httpMethod": "GET", + "url": "api/abp/application-localization/{culture}", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "culture", + "typeAsString": "System.String, System.Private.CoreLib", + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "culture", + "name": "culture", + "jsonName": null, + "type": "System.String", + "typeSimple": "string", + "isOptional": false, + "defaultValue": null, + "constraintTypes": [], + "bindingSourceId": "Path", + "descriptorName": "" + } + ], + "returnValue": { + "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationDto", + "typeSimple": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationDto" + }, + "allowAnonymous": null, + "implementFrom": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.IAbpApplicationLocalizationAppService" + } + } + }, "Volo.Abp.AspNetCore.Mvc.ApiExploring.AbpApiDefinitionController": { "controllerName": "AbpApiDefinition", "controllerGroupName": "AbpApiDefinition", + "isRemoteService": true, + "apiVersion": null, "type": "Volo.Abp.AspNetCore.Mvc.ApiExploring.AbpApiDefinitionController", "interfaces": [], "actions": { From 411ce8156003dfae5be199e607b70964941c4c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 14:37:12 +0300 Subject: [PATCH 35/61] Added ApplicationConfigurationRequestOptions. --- ...ationConfigurationClientProxy.Generated.cs | 7 ++- .../ClientProxies/abp-generate-proxy.json | 30 ++++++++-- ...MvcCachedApplicationConfigurationClient.cs | 6 +- .../ApplicationConfigurationRequestOptions.cs | 6 ++ .../IAbpApplicationConfigurationAppService.cs | 2 +- .../AbpApplicationConfigurationAppService.cs | 55 ++++++++++--------- .../AbpApplicationConfigurationController.cs | 5 +- ...pplicationConfigurationScriptController.cs | 6 +- .../AbpDictionaryBasedStringLocalizer.cs | 5 +- .../ApplicationConfigurationBuilder_Tests.cs | 2 +- 10 files changed, 85 insertions(+), 39 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.Generated.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.Generated.cs index 198cfce711..2d57dc66ab 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.Generated.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationConfigurationClientProxy.Generated.cs @@ -15,8 +15,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; [ExposeServices(typeof(IAbpApplicationConfigurationAppService), typeof(AbpApplicationConfigurationClientProxy))] public partial class AbpApplicationConfigurationClientProxy : ClientProxyBase, IAbpApplicationConfigurationAppService { - public virtual async Task GetAsync() + public virtual async Task GetAsync(ApplicationConfigurationRequestOptions options) { - return await RequestAsync(nameof(GetAsync)); + return await RequestAsync(nameof(GetAsync), new ClientProxyRequestTypeValue + { + { typeof(ApplicationConfigurationRequestOptions), options } + }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json index fcc79ecc89..018e1c4b3b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json @@ -104,14 +104,36 @@ } ], "actions": { - "GetAsync": { - "uniqueName": "GetAsync", + "GetAsyncByOptions": { + "uniqueName": "GetAsyncByOptions", "name": "GetAsync", "httpMethod": "GET", "url": "api/abp/application-configuration", "supportedVersions": [], - "parametersOnMethod": [], - "parameters": [], + "parametersOnMethod": [ + { + "name": "options", + "typeAsString": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationRequestOptions, Volo.Abp.AspNetCore.Mvc.Contracts", + "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationRequestOptions", + "typeSimple": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationRequestOptions", + "isOptional": false, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "options", + "name": "IncludeLocalizationResources", + "jsonName": null, + "type": "System.Boolean", + "typeSimple": "boolean", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "options" + } + ], "returnValue": { "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto", "typeSimple": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto" diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index 59690b2d03..5f43726455 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -48,7 +48,11 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu configuration = await Cache.GetOrAddAsync( cacheKey, - async () => await ApplicationConfigurationAppService.GetAsync(), + async () => await ApplicationConfigurationAppService.GetAsync( + new ApplicationConfigurationRequestOptions + { + IncludeLocalizationResources = false + }), () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300) //TODO: Should be configurable. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs new file mode 100644 index 0000000000..796f6ef4b1 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public class ApplicationConfigurationRequestOptions +{ + public bool IncludeLocalizationResources { get; set; } = true; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs index 1f56d97e42..ae4f22cc06 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationConfigurationAppService.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; public interface IAbpApplicationConfigurationAppService : IApplicationService { - Task GetAsync(); + Task GetAsync(ApplicationConfigurationRequestOptions options); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 8a3a004d63..85c9b86a3d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -43,7 +43,6 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp private readonly ITimezoneProvider _timezoneProvider; private readonly AbpClockOptions _abpClockOptions; private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; - private readonly AbpExternalLocalizationOptions _externalLocalizationOptions; private readonly AbpApplicationConfigurationOptions _options; public AbpApplicationConfigurationAppService( @@ -63,8 +62,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp ITimezoneProvider timezoneProvider, IOptions abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, - IOptions options, - IOptions distributedLocalizationOptions) + IOptions options) { _serviceProvider = serviceProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; @@ -80,13 +78,12 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp _timezoneProvider = timezoneProvider; _abpClockOptions = abpClockOptions.Value; _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; - _externalLocalizationOptions = distributedLocalizationOptions.Value; _options = options.Value; _localizationOptions = localizationOptions.Value; _multiTenancyOptions = multiTenancyOptions.Value; } - public virtual async Task GetAsync() + public virtual async Task GetAsync(ApplicationConfigurationRequestOptions options) { //TODO: Optimize & cache..? @@ -97,7 +94,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp Auth = await GetAuthConfigAsync(), Features = await GetFeaturesConfigAsync(), GlobalFeatures = await GetGlobalFeaturesConfigAsync(), - Localization = await GetLocalizationConfigAsync(), + Localization = await GetLocalizationConfigAsync(options), CurrentUser = GetCurrentUser(), Setting = await GetSettingConfigAsync(), MultiTenancy = GetMultiTenancy(), @@ -209,36 +206,42 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp return authConfig; } - protected virtual async Task GetLocalizationConfigAsync() + protected virtual async Task GetLocalizationConfigAsync( + ApplicationConfigurationRequestOptions options) { var localizationConfig = new ApplicationLocalizationConfigurationDto(); localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync()); - var externalResourceNames = await LazyServiceProvider - .LazyGetRequiredService() - .GetResourceNamesAsync(); - - var resourceNames = _localizationOptions - .Resources - .Values - .Select(x => x.ResourceName) - .Union(externalResourceNames); - - foreach (var resourceName in resourceNames) + if (options.IncludeLocalizationResources) { - var dictionary = new Dictionary(); - - var localizer = await StringLocalizerFactory.CreateByResourceNameOrNullAsync(resourceName); - if (localizer != null) + var resourceNames = _localizationOptions + .Resources + .Values + .Select(x => x.ResourceName) + .Union( + await LazyServiceProvider + .LazyGetRequiredService() + .GetResourceNamesAsync() + ); + + foreach (var resourceName in resourceNames) { - foreach (var localizedString in await localizer.GetAllStringsAsync()) + var dictionary = new Dictionary(); + + var localizer = await StringLocalizerFactory + .CreateByResourceNameOrNullAsync(resourceName); + + if (localizer != null) { - dictionary[localizedString.Name] = localizedString.Value; + foreach (var localizedString in await localizer.GetAllStringsAsync()) + { + dictionary[localizedString.Name] = localizedString.Value; + } } - } - localizationConfig.Values[resourceName] = dictionary; + localizationConfig.Values[resourceName] = dictionary; + } } localizationConfig.CurrentCulture = GetCurrentCultureInfo(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs index 6c410a8a7b..427aaf65a6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationController.cs @@ -21,9 +21,10 @@ public class AbpApplicationConfigurationController : AbpControllerBase, IAbpAppl } [HttpGet] - public virtual async Task GetAsync() + public virtual async Task GetAsync( + ApplicationConfigurationRequestOptions options) { _antiForgeryManager.SetCookie(); - return await _applicationConfigurationAppService.GetAsync(); + return await _applicationConfigurationAppService.GetAsync(options); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs index 92a4bdef0d..645da03b56 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs @@ -41,7 +41,11 @@ public class AbpApplicationConfigurationScriptController : AbpController [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] public async Task Get() { - var script = CreateAbpExtendScript(await _configurationAppService.GetAsync()); + var script = CreateAbpExtendScript(await _configurationAppService.GetAsync( + new ApplicationConfigurationRequestOptions { + IncludeLocalizationResources = false + } + )); _antiForgeryManager.SetCookie(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index d6bf1460d6..cf5c1ebb82 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -118,7 +118,10 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return value; } - protected virtual LocalizedString GetLocalizedStringOrNull(string name, string cultureName, bool tryDefaults = true) + protected virtual LocalizedString GetLocalizedStringOrNull( + string name, + string cultureName, + bool tryDefaults = true) { //Try to get from original dictionary (with country code) var strOriginal = Resource.Contributors.GetOrNull(cultureName, name); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs index 5d3cb09749..56fc8a583a 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder_Tests.cs @@ -12,7 +12,7 @@ public class ApplicationConfigurationBuilder_Tests : AspNetCoreMvcTestBase { var applicationConfigurationBuilder = GetRequiredService(); - var config = await applicationConfigurationBuilder.GetAsync(); + var config = await applicationConfigurationBuilder.GetAsync(new ApplicationConfigurationRequestOptions()); config.Auth.ShouldNotBeNull(); config.Localization.ShouldNotBeNull(); From e3e16ffa0fd5f6455ea4ee09c45f564d16bde9c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 16:02:05 +0300 Subject: [PATCH 36/61] MVC UI: Get localization from the new endpoint. Handle base resources in MVC UI. --- ...blyCachedApplicationConfigurationClient.cs | 6 +- ...pplicationConfigurationScriptController.cs | 12 +-- .../AbpApplicationLocalizationAppService.cs | 4 +- ...ApplicationLocalizationScriptController.cs | 45 ++++++++-- .../Themes/Basic/Layouts/Account.cshtml | 1 + .../Themes/Basic/Layouts/Application.cshtml | 1 + .../Themes/Basic/Layouts/Empty.cshtml | 1 + npm/packs/core/src/abp.js | 90 ++++++++++++------- 8 files changed, 116 insertions(+), 44 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index 523a770a17..b362d70bd0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -27,7 +27,11 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio public virtual async Task InitializeAsync() { - var configurationDto = await ApplicationConfigurationAppService.GetAsync(); + var configurationDto = await ApplicationConfigurationAppService.GetAsync( + new ApplicationConfigurationRequestOptions { + IncludeLocalizationResources = false + } + ); Cache.Set(configurationDto); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs index 645da03b56..791f5ca262 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs @@ -41,11 +41,13 @@ public class AbpApplicationConfigurationScriptController : AbpController [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] public async Task Get() { - var script = CreateAbpExtendScript(await _configurationAppService.GetAsync( - new ApplicationConfigurationRequestOptions { - IncludeLocalizationResources = false - } - )); + var script = CreateAbpExtendScript( + await _configurationAppService.GetAsync( + new ApplicationConfigurationRequestOptions { + IncludeLocalizationResources = false + } + ) + ); _antiForgeryManager.SetCookie(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 404186c254..5cfc96d8af 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -48,8 +48,8 @@ public class AbpApplicationLocalizationAppService : { var localizedStrings = await localizer.GetAllStringsAsync( includeParentCultures: true, - includeBaseLocalizers: true, //TODO: Test this! - includeDynamicContributors: false + includeBaseLocalizers: false, + includeDynamicContributors: true ); foreach (var localizedString in localizedStrings) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs index 550d29e2c4..30a10b03ab 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Localization; @@ -6,7 +7,9 @@ using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.Auditing; using Volo.Abp.Http; +using Volo.Abp.Json; using Volo.Abp.Localization; +using Volo.Abp.Minify.Scripts; namespace Volo.Abp.AspNetCore.Mvc.Localization; @@ -17,19 +20,51 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization; [ApiExplorerSettings(IgnoreApi = true)] public class AbpApplicationLocalizationScriptController : AbpController { - protected IAbpApplicationLocalizationAppService LocalizationAppService { get; } + protected IAbpApplicationLocalizationAppService LocalizationAppService { get; } + protected AbpAspNetCoreMvcOptions Options { get; } + protected IJsonSerializer JsonSerializer { get; } + protected IJavascriptMinifier JavascriptMinifier { get; } public AbpApplicationLocalizationScriptController( - IAbpApplicationLocalizationAppService localizationAppService) + IAbpApplicationLocalizationAppService localizationAppService, + IOptions options, + IJsonSerializer jsonSerializer, + IJavascriptMinifier javascriptMinifier) { LocalizationAppService = localizationAppService; + JsonSerializer = jsonSerializer; + JavascriptMinifier = javascriptMinifier; + Options = options.Value; } - + [HttpGet] [Route("{culture}")] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] - public async Task GetAsync(string culture) + public async Task GetAsync(string culture) { - throw new NotImplementedException(); + var script = CreateScript( + await LocalizationAppService.GetAsync(culture) + ); + + return Content( + Options.MinifyGeneratedScript == true + ? JavascriptMinifier.Minify(script) + : script, + MimeTypes.Application.Javascript + ); + } + + private string CreateScript(ApplicationLocalizationDto localizationDto) + { + var script = new StringBuilder(); + + script.AppendLine("(function(){"); + script.AppendLine(); + script.AppendLine( + $"$.extend(true, abp.localization, {JsonSerializer.Serialize(localizationDto, indented: true)})"); + script.AppendLine(); + script.Append("})();"); + + return script.ToString(); } } \ No newline at end of file diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index f71171912c..a4e73620b6 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -95,6 +95,7 @@ + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 539873ce4b..a29dea32dd 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -68,6 +68,7 @@ + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 70c7d5e1e8..9dd3cb4a21 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -63,6 +63,7 @@ + diff --git a/npm/packs/core/src/abp.js b/npm/packs/core/src/abp.js index 0348069bec..074d4f0f50 100644 --- a/npm/packs/core/src/abp.js +++ b/npm/packs/core/src/abp.js @@ -72,8 +72,61 @@ var abp = abp || {}; /* LOCALIZATION ***********************************************/ abp.localization = abp.localization || {}; - + abp.localization.internal = abp.localization.internal || {}; abp.localization.values = abp.localization.values || {}; + abp.localization.resources = abp.localization.resources || {}; + + abp.localization.internal.getResource = function (resourceName) { + var resource = abp.localization.resources[resourceName]; + if (resource) { + return resource; + } + + var legacySource = abp.localization.values[resourceName]; + if (legacySource) { + return { + texts: abp.localization.values[resourceName], + baseResources: [] + }; + } + + abp.log.warn('Could not find localization source: ' + resourceName); + return null; + }; + + abp.localization.internal.localize = function (key, sourceName) { + var resource = abp.localization.internal.getResource(sourceName); + if (!resource){ + return { + value: key, + found: false + }; + } + + var value = resource.texts[key]; + if (value === undefined) { + for (var i = 0; i < resource.baseResources.length; i++){ + var result = abp.localization.internal.localize(key, resource.baseResources[i]); + if (result.found){ + return result; + } + } + + return { + value: key, + found: false + }; + } + + var copiedArguments = Array.prototype.slice.call(arguments, 0); + copiedArguments.splice(1, 1); + copiedArguments[0] = value; + + return { + value: abp.utils.formatString.apply(this, copiedArguments), + found: true + }; + }; abp.localization.localize = function (key, sourceName) { if (sourceName === '_') { //A convention to suppress the localization @@ -86,22 +139,7 @@ var abp = abp || {}; return key; } - var source = abp.localization.values[sourceName]; - if (!source) { - abp.log.warn('Could not find localization source: ' + sourceName); - return key; - } - - var value = source[key]; - if (value == undefined) { - return key; - } - - var copiedArguments = Array.prototype.slice.call(arguments, 0); - copiedArguments.splice(1, 1); - copiedArguments[0] = value; - - return abp.utils.formatString.apply(this, copiedArguments); + return abp.localization.internal.localize(key, sourceName).value; }; abp.localization.isLocalized = function (key, sourceName) { @@ -114,17 +152,7 @@ var abp = abp || {}; return false; } - var source = abp.localization.values[sourceName]; - if (!source) { - return false; - } - - var value = source[key]; - if (value === undefined) { - return false; - } - - return true; + return abp.localization.internal.localize(key, sourceName).found; }; abp.localization.getResource = function (name) { @@ -687,7 +715,7 @@ var abp = abp || {}; } /** - * Escape HTML to help prevent XSS attacks. + * Escape HTML to help prevent XSS attacks. */ abp.utils.htmlEscape = function (html) { return typeof html === 'string' ? html.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') : html; @@ -759,7 +787,7 @@ var abp = abp || {}; return toUtc(date); } }; - + /* FEATURES *************************************************/ abp.features = abp.features || {}; @@ -774,7 +802,7 @@ var abp = abp || {}; abp.features.get = function (name) { return abp.features.values[name]; }; - + /* GLOBAL FEATURES *************************************************/ abp.globalFeatures = abp.globalFeatures || {}; From f6a3530eaf2f48bcb39ec532e46ab807c0955569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 16:35:23 +0300 Subject: [PATCH 37/61] remove initialize in AbpAspNetCoreMvcClientModule --- .../Mvc/Client/AbpAspNetCoreMvcClientModule.cs | 13 +------------ .../MvcCachedApplicationConfigurationClient.cs | 6 ------ 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs index 7c21b9fe09..ae5421d947 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/AbpAspNetCoreMvcClientModule.cs @@ -1,8 +1,5 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EventBus; using Volo.Abp.Modularity; -using Volo.Abp.Threading; namespace Volo.Abp.AspNetCore.Mvc.Client; @@ -12,13 +9,5 @@ namespace Volo.Abp.AspNetCore.Mvc.Client; )] public class AbpAspNetCoreMvcClientModule : AbpModule { - public override void OnApplicationInitialization(ApplicationInitializationContext context) - { - AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context)); - } - - public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) - { - await context.ServiceProvider.GetRequiredService().InitializeAsync(); - } + } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index 5f43726455..0e6ef517da 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -30,11 +30,6 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu Cache = cache; } - public async Task InitializeAsync() - { - await GetAsync(); - } - public async Task GetAsync() { var cacheKey = CreateCacheKey(); @@ -45,7 +40,6 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu return configuration; } - configuration = await Cache.GetOrAddAsync( cacheKey, async () => await ApplicationConfigurationAppService.GetAsync( From a63b2dfc4534f47f3e66efd513a66a0e741db507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 31 Aug 2022 18:14:15 +0300 Subject: [PATCH 38/61] Implement changes for RemoteLocalizationContributor. --- ...blyCachedApplicationConfigurationClient.cs | 18 ++- .../Client/RemoteLocalizationContributor.cs | 113 +++++++++++++----- ...MvcCachedApplicationConfigurationClient.cs | 29 ++++- .../ApplicationConfigurationRequestOptions.cs | 3 + ...ApplicationLocalizationConfigurationDto.cs | 15 +++ .../ApplicationLocalizationDto.cs | 2 + .../ApplicationLocalizationResourceDto.cs | 4 +- .../CurrentCultureDto.cs | 5 +- .../AbpApplicationLocalizationAppService.cs | 2 +- 9 files changed, 146 insertions(+), 45 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index b362d70bd0..9b1d21eb82 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -9,30 +9,38 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly; public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicationConfigurationClient, ITransientDependency { - protected AbpApplicationConfigurationClientProxy ApplicationConfigurationAppService { get; } + protected AbpApplicationConfigurationClientProxy ApplicationConfigurationClientProxy { get; } + + protected AbpApplicationLocalizationClientProxy ApplicationLocalizationClientProxy { get; } protected ApplicationConfigurationCache Cache { get; } protected ICurrentTenantAccessor CurrentTenantAccessor { get; } public WebAssemblyCachedApplicationConfigurationClient( - AbpApplicationConfigurationClientProxy applicationConfigurationAppService, + AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy, ApplicationConfigurationCache cache, - ICurrentTenantAccessor currentTenantAccessor) + ICurrentTenantAccessor currentTenantAccessor, + AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy) { - ApplicationConfigurationAppService = applicationConfigurationAppService; + ApplicationConfigurationClientProxy = applicationConfigurationClientProxy; Cache = cache; CurrentTenantAccessor = currentTenantAccessor; + ApplicationLocalizationClientProxy = applicationLocalizationClientProxy; } public virtual async Task InitializeAsync() { - var configurationDto = await ApplicationConfigurationAppService.GetAsync( + var configurationDto = await ApplicationConfigurationClientProxy.GetAsync( new ApplicationConfigurationRequestOptions { IncludeLocalizationResources = false } ); + var localizationDto = await ApplicationLocalizationClientProxy.GetAsync(configurationDto.Localization.CurrentCulture.Name); + + configurationDto.Localization.Resources = localizationDto.Resources; + Cache.Set(configurationDto); CurrentTenantAccessor.Current = new BasicTenantInfo( diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs index dc116d114d..e6e180c5f2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteLocalizationContributor.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.Client; @@ -25,87 +26,137 @@ public class RemoteLocalizationContributor : ILocalizationResourceContributor ?? NullLogger.Instance; } - public LocalizedString GetOrNull(string cultureName, string name) + public virtual LocalizedString GetOrNull(string cultureName, string name) { - var resource = GetResourceOrNull(); + /* cultureName is not used because remote localization can only + * be done in the current culture. */ + + return GetOrNullInternal(_resource.ResourceName, name); + } + + protected virtual LocalizedString GetOrNullInternal(string resourceName, string name) + { + var resource = GetResourceOrNull(resourceName); if (resource == null) { return null; } - var value = resource.GetOrDefault(name); - if (value == null) + var value = resource.Texts.GetOrDefault(name); + if (value != null) { - return null; + return new LocalizedString(name, value); } - return new LocalizedString(name, value); + foreach (var baseResource in resource.BaseResources) + { + value = GetOrNullInternal(baseResource, name); + if (value != null) + { + return new LocalizedString(name, value); + } + } + + return null; } - public void Fill(string cultureName, Dictionary dictionary) + public virtual void Fill(string cultureName, Dictionary dictionary) + { + /* cultureName is not used because remote localization can only + * be done in the current culture. */ + + FillInternal(_resource.ResourceName, dictionary); + } + + protected virtual void FillInternal(string resourceName, Dictionary dictionary) { - var resource = GetResourceOrNull(); + var resource = GetResourceOrNull(resourceName); if (resource == null) { return; } - foreach (var keyValue in resource) + foreach (var baseResource in resource.BaseResources) + { + FillInternal(baseResource, dictionary); + } + + foreach (var keyValue in resource.Texts) { dictionary[keyValue.Key] = new LocalizedString(keyValue.Key, keyValue.Value); } } - public async Task FillAsync(string cultureName, Dictionary dictionary) + public virtual async Task FillAsync(string cultureName, Dictionary dictionary) + { + /* cultureName is not used because remote localization can only + * be done in the current culture. */ + + await FillInternalAsync(_resource.ResourceName, dictionary); + } + + protected virtual async Task FillInternalAsync(string resourceName, Dictionary dictionary) { - var resource = await GetResourceOrNullAsync(); + var resource = await GetResourceOrNullAsync(resourceName); if (resource == null) { return; } + + foreach (var baseResource in resource.BaseResources) + { + await FillInternalAsync(baseResource, dictionary); + } - foreach (var keyValue in resource) + foreach (var keyValue in resource.Texts) { dictionary[keyValue.Key] = new LocalizedString(keyValue.Key, keyValue.Value); } } - public Task> GetSupportedCulturesAsync() + public virtual Task> GetSupportedCulturesAsync() { /* This contributor does not know all the supported cultures by the remote localization resource, and it is not needed on the client side */ return Task.FromResult((IEnumerable)Array.Empty()); } - private Dictionary GetResourceOrNull() + protected virtual ApplicationLocalizationResourceDto GetResourceOrNull(string resourceName) { var applicationConfigurationDto = _applicationConfigurationClient.Get(); - - var resource = applicationConfigurationDto - .Localization.Values - .GetOrDefault(_resource.ResourceName); - - if (resource == null) - { - _logger.LogWarning($"Could not find the localization resource {_resource.ResourceName} on the remote server!"); - } - - return resource; + return GetResourceOrNull(applicationConfigurationDto, resourceName); } - private async Task> GetResourceOrNullAsync() + protected virtual async Task GetResourceOrNullAsync(string resourceName) { var applicationConfigurationDto = await _applicationConfigurationClient.GetAsync(); + return GetResourceOrNull(applicationConfigurationDto, resourceName); + } - var resource = applicationConfigurationDto + protected virtual ApplicationLocalizationResourceDto GetResourceOrNull( + ApplicationConfigurationDto applicationConfigurationDto, + string resourceName) + { + var resource = applicationConfigurationDto.Localization.Resources.GetOrDefault(resourceName); + if (resource != null) + { + return resource; + } + + var legacyResource = applicationConfigurationDto .Localization.Values - .GetOrDefault(_resource.ResourceName); + .GetOrDefault(resourceName); - if (resource == null) + if (legacyResource != null) { - _logger.LogWarning($"Could not find the localization resource {_resource.ResourceName} on the remote server!"); + return new ApplicationLocalizationResourceDto + { + Texts = legacyResource, + BaseResources = Array.Empty() + }; } - return resource; + _logger.LogWarning($"Could not find the localization resource {resourceName} on the remote server!"); + return null; } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index 0e6ef517da..edfbbeeff5 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -15,6 +15,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu { protected IHttpContextAccessor HttpContextAccessor { get; } protected AbpApplicationConfigurationClientProxy ApplicationConfigurationAppService { get; } + protected AbpApplicationLocalizationClientProxy ApplicationLocalizationClientProxy { get; } protected ICurrentUser CurrentUser { get; } protected IDistributedCache Cache { get; } @@ -22,11 +23,13 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu IDistributedCache cache, AbpApplicationConfigurationClientProxy applicationConfigurationAppService, ICurrentUser currentUser, - IHttpContextAccessor httpContextAccessor) + IHttpContextAccessor httpContextAccessor, + AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy) { ApplicationConfigurationAppService = applicationConfigurationAppService; CurrentUser = currentUser; HttpContextAccessor = httpContextAccessor; + ApplicationLocalizationClientProxy = applicationLocalizationClientProxy; Cache = cache; } @@ -42,11 +45,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu configuration = await Cache.GetOrAddAsync( cacheKey, - async () => await ApplicationConfigurationAppService.GetAsync( - new ApplicationConfigurationRequestOptions - { - IncludeLocalizationResources = false - }), + async () => await GetRemoteConfigurationAsync(), () => new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(300) //TODO: Should be configurable. @@ -61,6 +60,24 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu return configuration; } + private async Task GetRemoteConfigurationAsync() + { + var config = await ApplicationConfigurationAppService.GetAsync( + new ApplicationConfigurationRequestOptions + { + IncludeLocalizationResources = false + } + ); + + var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( + config.Localization.CurrentCulture.Name + ); + + config.Localization.Resources = localizationDto.Resources; + + return config; + } + public ApplicationConfigurationDto Get() { var cacheKey = CreateCacheKey(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs index 796f6ef4b1..a01534775a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationRequestOptions.cs @@ -2,5 +2,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; public class ApplicationConfigurationRequestOptions { + /// + /// Set to true to fill the Values property in . + /// public bool IncludeLocalizationResources { get; set; } = true; } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs index f92c9d7bb9..b1c0c16e76 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs @@ -7,8 +7,23 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; [Serializable] public class ApplicationLocalizationConfigurationDto { + /// + /// This is not filled if is false. + /// public Dictionary> Values { get; set; } + /// + /// This property will never be filled by the application configuration endpoint + /// (by AbpApplicationConfigurationAppService). However, it is here to be filled + /// using the application localization endpoint (AbpApplicationLocalizationAppService). + /// This is an ugly design, but it is the best solution for backward-compability and + /// simple implementation. + /// + /// It's client's responsibility to fill this property + /// using the application localization endpoint. + /// + public Dictionary Resources { get; set; } = new(); + public List Languages { get; set; } public CurrentCultureDto CurrentCulture { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs index 79e31bb712..d301490bed 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationDto.cs @@ -1,7 +1,9 @@ +using System; using System.Collections.Generic; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +[Serializable] public class ApplicationLocalizationDto { public Dictionary Resources { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs index 9c1256ec95..a7200423d2 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationResourceDto.cs @@ -1,10 +1,12 @@ +using System; using System.Collections.Generic; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +[Serializable] public class ApplicationLocalizationResourceDto { public Dictionary Texts { get; set; } - public List BaseResources { get; set; } + public string[] BaseResources { get; set; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs index 8f1896e31f..83f1e0c803 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs @@ -1,5 +1,8 @@ -namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using System; +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +[Serializable] public class CurrentCultureDto { public string DisplayName { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 5cfc96d8af..0625bd55f1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -61,7 +61,7 @@ public class AbpApplicationLocalizationAppService : localizationConfig.Resources[resource.ResourceName] = new ApplicationLocalizationResourceDto { Texts = dictionary, - BaseResources = resource.BaseResourceNames + BaseResources = resource.BaseResourceNames.ToArray() }; } From f9892c00b40860e4454e366a7a948d146cdc0bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 2 Sep 2022 09:55:08 +0300 Subject: [PATCH 39/61] Resolved #13322: DistributedCache should be an adapter instead of inheriting from DistributedCache --- .../Volo/Abp/Caching/DistributedCache.cs | 121 +++++++++++++++--- .../Volo/Abp/Caching/IDistributedCache.cs | 1 + .../DistributedCache_ConfigureOptions_Test.cs | 14 +- 3 files changed, 119 insertions(+), 17 deletions(-) diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index c51ec76fc1..a72a369655 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -21,26 +21,115 @@ namespace Volo.Abp.Caching; /// /// The type of cache item being cached. public class DistributedCache : - DistributedCache, IDistributedCache where TCacheItem : class { - public DistributedCache( - IOptions distributedCacheOption, - IDistributedCache cache, - ICancellationTokenProvider cancellationTokenProvider, - IDistributedCacheSerializer serializer, - IDistributedCacheKeyNormalizer keyNormalizer, - IServiceScopeFactory serviceScopeFactory, - IUnitOfWorkManager unitOfWorkManager) : base( - distributedCacheOption: distributedCacheOption, - cache: cache, - cancellationTokenProvider: cancellationTokenProvider, - serializer: serializer, - keyNormalizer: keyNormalizer, - serviceScopeFactory: serviceScopeFactory, - unitOfWorkManager: unitOfWorkManager) + public IDistributedCache InternalCache { get; } + + public DistributedCache(IDistributedCache internalCache) + { + InternalCache = internalCache; + } + + public TCacheItem Get(string key, bool? hideErrors = null, bool considerUow = false) + { + return InternalCache.Get(key, hideErrors, considerUow); + } + + public KeyValuePair[] GetMany(IEnumerable keys, bool? hideErrors = null, bool considerUow = false) + { + return InternalCache.GetMany(keys, hideErrors, considerUow); + } + + public Task[]> GetManyAsync(IEnumerable keys, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.GetManyAsync(keys, hideErrors, considerUow, token); + } + + public Task GetAsync(string key, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.GetAsync(key, hideErrors, considerUow, token); + } + + public TCacheItem GetOrAdd(string key, Func factory, Func optionsFactory = null, bool? hideErrors = null, bool considerUow = false) + { + return InternalCache.GetOrAdd(key, factory, optionsFactory, hideErrors, considerUow); + } + + public Task GetOrAddAsync(string key, Func> factory, Func optionsFactory = null, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.GetOrAddAsync(key, factory, optionsFactory, hideErrors, considerUow, token); + } + + public KeyValuePair[] GetOrAddMany(IEnumerable keys, Func, List>> factory, Func optionsFactory = null, bool? hideErrors = null, bool considerUow = false) + { + return InternalCache.GetOrAddMany(keys, factory, optionsFactory, hideErrors, considerUow); + } + + public Task[]> GetOrAddManyAsync(IEnumerable keys, Func, Task>>> factory, Func optionsFactory = null, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.GetOrAddManyAsync(keys, factory, optionsFactory, hideErrors, considerUow, token); + } + + public void Set(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, bool considerUow = false) + { + InternalCache.Set(key, value, options, hideErrors, considerUow); + } + + public Task SetAsync(string key, TCacheItem value, DistributedCacheEntryOptions options = null, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.SetAsync(key, value, options, hideErrors, considerUow, token); + } + + public void SetMany(IEnumerable> items, DistributedCacheEntryOptions options = null, bool? hideErrors = null, bool considerUow = false) + { + InternalCache.SetMany(items, options, hideErrors, considerUow); + } + + public Task SetManyAsync(IEnumerable> items, DistributedCacheEntryOptions options = null, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.SetManyAsync(items, options, hideErrors, considerUow, token); + } + + public void Refresh(string key, bool? hideErrors = null) + { + InternalCache.Refresh(key, hideErrors); + } + + public Task RefreshAsync(string key, bool? hideErrors = null, CancellationToken token = default) + { + return InternalCache.RefreshAsync(key, hideErrors, token); + } + + public void RefreshMany(IEnumerable keys, bool? hideErrors = null) + { + InternalCache.RefreshMany(keys, hideErrors); + } + + public Task RefreshManyAsync(IEnumerable keys, bool? hideErrors = null, CancellationToken token = default) + { + return InternalCache.RefreshManyAsync(keys, hideErrors, token); + } + + public void Remove(string key, bool? hideErrors = null, bool considerUow = false) + { + InternalCache.Remove(key, hideErrors, considerUow); + } + + public Task RemoveAsync(string key, bool? hideErrors = null, bool considerUow = false, CancellationToken token = default) + { + return InternalCache.RemoveAsync(key, hideErrors, considerUow, token); + } + + public void RemoveMany(IEnumerable keys, bool? hideErrors = null, bool considerUow = false) + { + InternalCache.RemoveMany(keys, hideErrors, considerUow); + } + + public Task RemoveManyAsync(IEnumerable keys, bool? hideErrors = null, bool considerUow = false, + CancellationToken token = default) { + return InternalCache.RemoveManyAsync(keys, hideErrors, considerUow, token); } } diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs index 21a2842e15..ab3ca560a8 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/IDistributedCache.cs @@ -14,6 +14,7 @@ namespace Volo.Abp.Caching; public interface IDistributedCache : IDistributedCache where TCacheItem : class { + IDistributedCache InternalCache { get; } } /// diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs index 12c8a16833..513423a781 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_ConfigureOptions_Test.cs @@ -34,7 +34,19 @@ public class DistributedCache_ConfigureOptions_Test : AbpIntegratedTest Date: Fri, 2 Sep 2022 10:00:07 +0300 Subject: [PATCH 40/61] Added test for #13322 --- .../Volo/Abp/Caching/DistributedCache_Tests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs index 7908dd3d96..c76f5be9ea 100644 --- a/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs +++ b/framework/test/Volo.Abp.Caching.Tests/Volo/Abp/Caching/DistributedCache_Tests.cs @@ -953,7 +953,9 @@ public class DistributedCache_Tests : AbpIntegratedTest { var cache1 = GetRequiredService>(); var cache2 = GetRequiredService>(); - + + cache1.InternalCache.ShouldBe(cache2); + await cache1.SetAsync("john", new PersonCacheItem("John Doe")); var item1 = await cache1.GetAsync("john"); From 80be834fcbd939197de3cc62fbe5756935e33bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 09:33:28 +0300 Subject: [PATCH 41/61] Update LocalizationResource.cs --- .../Volo/Abp/Localization/LocalizationResource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs index 8158cb77b1..7a55f1f8a3 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Localization; public class LocalizationResource : LocalizationResourceBase { [NotNull] - private Type ResourceType { get; } + public Type ResourceType { get; } public LocalizationResource( [NotNull] Type resourceType, From d892218c358626fde292127ea960f6f6c2a55045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 17:02:07 +0300 Subject: [PATCH 42/61] Introduce ApplicationLocalizationRequestDto --- .../AbpApplicationLocalizationClientProxy.Generated.cs | 4 ++-- .../ApplicationLocalizationRequestDto.cs | 9 +++++++++ .../IAbpApplicationLocalizationAppService.cs | 2 +- .../AbpApplicationLocalizationAppService.cs | 4 ++-- .../AbpApplicationLocalizationController.cs | 4 ++-- .../AbpApplicationLocalizationScriptController.cs | 4 ++-- 6 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs index fae18f7d2f..74db054d18 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/AbpApplicationLocalizationClientProxy.Generated.cs @@ -15,11 +15,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; [ExposeServices(typeof(IAbpApplicationLocalizationAppService), typeof(AbpApplicationLocalizationClientProxy))] public partial class AbpApplicationLocalizationClientProxy : ClientProxyBase, IAbpApplicationLocalizationAppService { - public virtual async Task GetAsync(string culture) + public virtual async Task GetAsync(ApplicationLocalizationRequestDto input) { return await RequestAsync(nameof(GetAsync), new ClientProxyRequestTypeValue { - { typeof(string), culture } + { typeof(ApplicationLocalizationRequestDto), input } }); } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs new file mode 100644 index 0000000000..29b2874d87 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; + +public class ApplicationLocalizationRequestDto +{ + [Required] + public string Culture { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs index bebbcdd987..af72c8f7ee 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/IAbpApplicationLocalizationAppService.cs @@ -5,5 +5,5 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; public interface IAbpApplicationLocalizationAppService : IApplicationService { - Task GetAsync(string culture); + Task GetAsync(ApplicationLocalizationRequestDto input); } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 0625bd55f1..77d3269ad7 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -24,9 +24,9 @@ public class AbpApplicationLocalizationAppService : LocalizationOptions = localizationOptions.Value; } - public async Task GetAsync(string culture) + public async Task GetAsync(ApplicationLocalizationRequestDto input) { - using (CultureHelper.Use(culture)) + using (CultureHelper.Use(input.Culture)) { var resources = LocalizationOptions .Resources diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs index 4b5c6de034..c140ec5029 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs @@ -17,8 +17,8 @@ public class AbpApplicationLocalizationController: AbpControllerBase, IAbpApplic [HttpGet] [Route("{culture}")] - public virtual async Task GetAsync(string culture) + public virtual async Task GetAsync(ApplicationLocalizationRequestDto input) { - return await _localizationAppService.GetAsync(culture); + return await _localizationAppService.GetAsync(input); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs index 30a10b03ab..8147540e73 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -40,10 +40,10 @@ public class AbpApplicationLocalizationScriptController : AbpController [HttpGet] [Route("{culture}")] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] - public async Task GetAsync(string culture) + public async Task GetAsync(ApplicationLocalizationRequestDto input) { var script = CreateScript( - await LocalizationAppService.GetAsync(culture) + await LocalizationAppService.GetAsync(input) ); return Content( From bf912d62ca89ef2d9608f9413012380e651460a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 17:05:40 +0300 Subject: [PATCH 43/61] Use ApplicationLocalizationRequestDto instead of string parameter --- .../WebAssemblyCachedApplicationConfigurationClient.cs | 6 +++++- .../Mvc/Client/MvcCachedApplicationConfigurationClient.cs | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index 9b1d21eb82..5b484a1b36 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -37,7 +37,11 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio } ); - var localizationDto = await ApplicationLocalizationClientProxy.GetAsync(configurationDto.Localization.CurrentCulture.Name); + var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( + new ApplicationLocalizationRequestDto { + Culture = configurationDto.Localization.CurrentCulture.Name + } + ); configurationDto.Localization.Resources = localizationDto.Resources; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index edfbbeeff5..647501f6d3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -70,7 +70,9 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu ); var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( - config.Localization.CurrentCulture.Name + new ApplicationLocalizationRequestDto { + Culture = config.Localization.CurrentCulture.Name + } ); config.Localization.Resources = localizationDto.Resources; From 43510eb9f4a897a9c4ebb313ba623c413baeb3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 17:23:02 +0300 Subject: [PATCH 44/61] Introduce DynamicLocalizationPreference --- .../AbpApplicationLocalizationAppService.cs | 2 +- .../AbpDictionaryBasedStringLocalizer.cs | 36 +++++++++---------- .../DynamicLocalizationPreference.cs | 8 +++++ .../Abp/Localization/IAbpStringLocalizer.cs | 4 +-- .../LocalizationResourceContributorList.cs | 8 ++--- .../Abp/Localization/AbpLocalization_Tests.cs | 4 +-- 6 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 77d3269ad7..407308f846 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -49,7 +49,7 @@ public class AbpApplicationLocalizationAppService : var localizedStrings = await localizer.GetAllStringsAsync( includeParentCultures: true, includeBaseLocalizers: false, - includeDynamicContributors: true + dynamicLocalizationPreference: DynamicLocalizationPreference.Include ); foreach (var localizedString in localizedStrings) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index cf5c1ebb82..13a635c27d 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -50,26 +50,26 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer public IEnumerable GetAllStrings( bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors) + DynamicLocalizationPreference dynamicLocalizationPreference) { return GetAllStrings( CultureInfo.CurrentUICulture.Name, includeParentCultures, includeBaseLocalizers, - includeDynamicContributors + dynamicLocalizationPreference ); } public async Task> GetAllStringsAsync( bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors) + DynamicLocalizationPreference dynamicLocalizationPreference) { return await GetAllStringsAsync( CultureInfo.CurrentUICulture.Name, includeParentCultures, includeBaseLocalizers, - includeDynamicContributors + dynamicLocalizationPreference ); } @@ -169,7 +169,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer string cultureName, bool includeParentCultures = true, bool includeBaseLocalizers = true, - bool includeDynamicContributors = true) + DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) @@ -187,7 +187,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer var baseLocalizedString = baseLocalizer.GetAllStrings( includeParentCultures, includeBaseLocalizers, // Always true, I know! - includeDynamicContributors + dynamicLocalizationPreference ); foreach (var localizedString in baseLocalizedString) @@ -208,18 +208,18 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer //Fill all strings from default culture if (!Resource.DefaultCultureName.IsNullOrEmpty()) { - Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings, includeDynamicContributors); + Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings, dynamicLocalizationPreference); } //Overwrite all strings from the language based on country culture if (cultureName.Contains("-")) { - Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings, includeDynamicContributors); + Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings, dynamicLocalizationPreference); } } //Overwrite all strings from the original culture - Resource.Contributors.Fill(cultureName, allStrings, includeDynamicContributors); + Resource.Contributors.Fill(cultureName, allStrings, dynamicLocalizationPreference); return allStrings.Values.ToImmutableList(); } @@ -228,7 +228,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer string cultureName, bool includeParentCultures = true, bool includeBaseLocalizers = true, - bool includeDynamicContributors = true) + DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) @@ -246,7 +246,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer var baseLocalizedString = await baseLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, // Always true, I know! - includeDynamicContributors + dynamicLocalizationPreference ); foreach (var localizedString in baseLocalizedString) @@ -270,7 +270,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( Resource.DefaultCultureName, allStrings, - includeDynamicContributors + dynamicLocalizationPreference ); } @@ -280,7 +280,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( CultureHelper.GetBaseCultureName(cultureName), allStrings, - includeDynamicContributors + dynamicLocalizationPreference ); } } @@ -289,7 +289,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( cultureName, allStrings, - includeDynamicContributors + dynamicLocalizationPreference ); return allStrings.Values.ToImmutableList(); @@ -315,9 +315,9 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures); } - public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) + public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers, DynamicLocalizationPreference dynamicLocalizationPreference) { - return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, includeDynamicContributors); + return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, dynamicLocalizationPreference); } public Task> GetAllStringsAsync(bool includeParentCultures) @@ -325,12 +325,12 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStringsAsync(includeParentCultures); } - public Task> GetAllStringsAsync(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) + public Task> GetAllStringsAsync(bool includeParentCultures, bool includeBaseLocalizers, DynamicLocalizationPreference dynamicLocalizationPreference) { return _innerLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, - includeDynamicContributors + dynamicLocalizationPreference ); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs new file mode 100644 index 0000000000..ae3ceb3a5a --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.Localization; + +public enum DynamicLocalizationPreference : byte +{ + Include = 0, + Exclude = 1, + Only = 2 +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index 59fbbcb7b4..e69ef01d0f 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -9,7 +9,7 @@ public interface IAbpStringLocalizer : IStringLocalizer IEnumerable GetAllStrings( bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors + DynamicLocalizationPreference dynamicLocalizationPreference ); Task> GetAllStringsAsync( @@ -19,7 +19,7 @@ public interface IAbpStringLocalizer : IStringLocalizer Task> GetAllStringsAsync( bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors + DynamicLocalizationPreference dynamicLocalizationPreference ); Task> GetSupportedCulturesAsync(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index 6df15920da..8d575ed75c 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -32,11 +32,11 @@ public class LocalizationResourceContributorList : List dictionary, - bool includeDynamicContributors = true) + DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) { foreach (var contributor in this) { - if (!includeDynamicContributors && contributor.IsDynamic) + if (dynamicLocalizationPreference == DynamicLocalizationPreference.Exclude && contributor.IsDynamic) { continue; } @@ -48,11 +48,11 @@ public class LocalizationResourceContributorList : List dictionary, - bool includeDynamicContributors = true) + DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) { foreach (var contributor in this) { - if (!includeDynamicContributors && contributor.IsDynamic) + if (dynamicLocalizationPreference == DynamicLocalizationPreference.Exclude && contributor.IsDynamic) { continue; } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index ee0e929e32..342e6d8708 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -311,7 +311,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest Date: Mon, 5 Sep 2022 17:23:09 +0300 Subject: [PATCH 45/61] Update AbpStringLocalizerExtensions.cs --- .../Abp/Localization/AbpStringLocalizerExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index 9b3bb2c201..29fa60b3d9 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -42,7 +42,7 @@ public static class AbpStringLocalizerExtensions this IStringLocalizer stringLocalizer, bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors) + DynamicLocalizationPreference dynamicLocalizationPreference) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) @@ -50,7 +50,7 @@ public static class AbpStringLocalizerExtensions return abpStringLocalizer.GetAllStrings( includeParentCultures, includeBaseLocalizers, - includeDynamicContributors + dynamicLocalizationPreference ); } @@ -63,7 +63,7 @@ public static class AbpStringLocalizerExtensions this IStringLocalizer stringLocalizer, bool includeParentCultures, bool includeBaseLocalizers, - bool includeDynamicContributors) + DynamicLocalizationPreference dynamicLocalizationPreference) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) @@ -71,7 +71,7 @@ public static class AbpStringLocalizerExtensions return await abpStringLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, - includeDynamicContributors + dynamicLocalizationPreference ); } @@ -113,4 +113,4 @@ public static class AbpStringLocalizerExtensions localizer.GetAllStrings(includeParentCultures: true) ); } -} +} \ No newline at end of file From 702589380b0bb76407befff94043b3a8faa077d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 18:50:40 +0300 Subject: [PATCH 46/61] Introduce ApplicationLocalizationRequestDto.OnlyDynamics --- ...blyCachedApplicationConfigurationClient.cs | 3 ++- ...MvcCachedApplicationConfigurationClient.cs | 3 ++- .../ApplicationLocalizationRequestDto.cs | 2 ++ .../AbpApplicationLocalizationAppService.cs | 26 ++++++++++++++++--- .../DynamicLocalizationPreference.cs | 3 +-- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index 5b484a1b36..d6067f2ba0 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -39,7 +39,8 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( new ApplicationLocalizationRequestDto { - Culture = configurationDto.Localization.CurrentCulture.Name + Culture = configurationDto.Localization.CurrentCulture.Name, + OnlyDynamics = true } ); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index 647501f6d3..edfed09708 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -71,7 +71,8 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( new ApplicationLocalizationRequestDto { - Culture = config.Localization.CurrentCulture.Name + Culture = config.Localization.CurrentCulture.Name, + OnlyDynamics = true } ); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs index 29b2874d87..d33346d149 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs @@ -6,4 +6,6 @@ public class ApplicationLocalizationRequestDto { [Required] public string Culture { get; set; } + + public bool OnlyDynamics { get; set; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 407308f846..e8b2a245bd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -42,18 +42,38 @@ public class AbpApplicationLocalizationAppService : foreach (var resource in resources) { var dictionary = new Dictionary(); - var localizer = await StringLocalizerFactory.CreateByResourceNameOrNullAsync(resource.ResourceName); if (localizer != null) { - var localizedStrings = await localizer.GetAllStringsAsync( + Dictionary staticLocalizedStrings = null; + + if (input.OnlyDynamics) + { + staticLocalizedStrings = (await localizer.GetAllStringsAsync( + includeParentCultures: true, + includeBaseLocalizers: false, + dynamicLocalizationPreference: DynamicLocalizationPreference.Exclude + )).ToDictionary(x => x.Name); + } + + var localizedStringsWithDynamics = await localizer.GetAllStringsAsync( includeParentCultures: true, includeBaseLocalizers: false, dynamicLocalizationPreference: DynamicLocalizationPreference.Include ); - foreach (var localizedString in localizedStrings) + foreach (var localizedString in localizedStringsWithDynamics) { + if (input.OnlyDynamics) + { + var staticLocalizedString = staticLocalizedStrings.GetOrDefault(localizedString.Name); + if (staticLocalizedString != null && + localizedString.Value == staticLocalizedString.Value) + { + continue; + } + } + dictionary[localizedString.Name] = localizedString.Value; } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs index ae3ceb3a5a..81b4d5b8f6 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs @@ -3,6 +3,5 @@ namespace Volo.Abp.Localization; public enum DynamicLocalizationPreference : byte { Include = 0, - Exclude = 1, - Only = 2 + Exclude = 1 } \ No newline at end of file From 5b78fa68a544eff4216cf9dba0fe0fa64915d1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 19:01:23 +0300 Subject: [PATCH 47/61] Revert DynamicLocalizationPreference --- .../AbpApplicationLocalizationAppService.cs | 2 +- .../AbpDictionaryBasedStringLocalizer.cs | 36 +++++++++---------- .../DynamicLocalizationPreference.cs | 7 ---- .../Abp/Localization/IAbpStringLocalizer.cs | 4 +-- .../LocalizationResourceContributorList.cs | 8 ++--- .../Abp/Localization/AbpLocalization_Tests.cs | 4 +-- 6 files changed, 27 insertions(+), 34 deletions(-) delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index e8b2a245bd..01d97ca34d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -59,7 +59,7 @@ public class AbpApplicationLocalizationAppService : var localizedStringsWithDynamics = await localizer.GetAllStringsAsync( includeParentCultures: true, includeBaseLocalizers: false, - dynamicLocalizationPreference: DynamicLocalizationPreference.Include + includeDynamicContributors: true ); foreach (var localizedString in localizedStringsWithDynamics) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index 13a635c27d..cf5c1ebb82 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -50,26 +50,26 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer public IEnumerable GetAllStrings( bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference) + bool includeDynamicContributors) { return GetAllStrings( CultureInfo.CurrentUICulture.Name, includeParentCultures, includeBaseLocalizers, - dynamicLocalizationPreference + includeDynamicContributors ); } public async Task> GetAllStringsAsync( bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference) + bool includeDynamicContributors) { return await GetAllStringsAsync( CultureInfo.CurrentUICulture.Name, includeParentCultures, includeBaseLocalizers, - dynamicLocalizationPreference + includeDynamicContributors ); } @@ -169,7 +169,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer string cultureName, bool includeParentCultures = true, bool includeBaseLocalizers = true, - DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) + bool includeDynamicContributors = true) { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) @@ -187,7 +187,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer var baseLocalizedString = baseLocalizer.GetAllStrings( includeParentCultures, includeBaseLocalizers, // Always true, I know! - dynamicLocalizationPreference + includeDynamicContributors ); foreach (var localizedString in baseLocalizedString) @@ -208,18 +208,18 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer //Fill all strings from default culture if (!Resource.DefaultCultureName.IsNullOrEmpty()) { - Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings, dynamicLocalizationPreference); + Resource.Contributors.Fill(Resource.DefaultCultureName, allStrings, includeDynamicContributors); } //Overwrite all strings from the language based on country culture if (cultureName.Contains("-")) { - Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings, dynamicLocalizationPreference); + Resource.Contributors.Fill(CultureHelper.GetBaseCultureName(cultureName), allStrings, includeDynamicContributors); } } //Overwrite all strings from the original culture - Resource.Contributors.Fill(cultureName, allStrings, dynamicLocalizationPreference); + Resource.Contributors.Fill(cultureName, allStrings, includeDynamicContributors); return allStrings.Values.ToImmutableList(); } @@ -228,7 +228,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer string cultureName, bool includeParentCultures = true, bool includeBaseLocalizers = true, - DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) + bool includeDynamicContributors = true) { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) @@ -246,7 +246,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer var baseLocalizedString = await baseLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, // Always true, I know! - dynamicLocalizationPreference + includeDynamicContributors ); foreach (var localizedString in baseLocalizedString) @@ -270,7 +270,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( Resource.DefaultCultureName, allStrings, - dynamicLocalizationPreference + includeDynamicContributors ); } @@ -280,7 +280,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( CultureHelper.GetBaseCultureName(cultureName), allStrings, - dynamicLocalizationPreference + includeDynamicContributors ); } } @@ -289,7 +289,7 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer await Resource.Contributors.FillAsync( cultureName, allStrings, - dynamicLocalizationPreference + includeDynamicContributors ); return allStrings.Values.ToImmutableList(); @@ -315,9 +315,9 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures); } - public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers, DynamicLocalizationPreference dynamicLocalizationPreference) + public IEnumerable GetAllStrings(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) { - return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, dynamicLocalizationPreference); + return _innerLocalizer.GetAllStrings(_cultureName, includeParentCultures, includeBaseLocalizers, includeDynamicContributors); } public Task> GetAllStringsAsync(bool includeParentCultures) @@ -325,12 +325,12 @@ public class AbpDictionaryBasedStringLocalizer : IAbpStringLocalizer return _innerLocalizer.GetAllStringsAsync(includeParentCultures); } - public Task> GetAllStringsAsync(bool includeParentCultures, bool includeBaseLocalizers, DynamicLocalizationPreference dynamicLocalizationPreference) + public Task> GetAllStringsAsync(bool includeParentCultures, bool includeBaseLocalizers, bool includeDynamicContributors) { return _innerLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, - dynamicLocalizationPreference + includeDynamicContributors ); } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs deleted file mode 100644 index 81b4d5b8f6..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DynamicLocalizationPreference.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Abp.Localization; - -public enum DynamicLocalizationPreference : byte -{ - Include = 0, - Exclude = 1 -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs index e69ef01d0f..59fbbcb7b4 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/IAbpStringLocalizer.cs @@ -9,7 +9,7 @@ public interface IAbpStringLocalizer : IStringLocalizer IEnumerable GetAllStrings( bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference + bool includeDynamicContributors ); Task> GetAllStringsAsync( @@ -19,7 +19,7 @@ public interface IAbpStringLocalizer : IStringLocalizer Task> GetAllStringsAsync( bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference + bool includeDynamicContributors ); Task> GetSupportedCulturesAsync(); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs index 8d575ed75c..6df15920da 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorList.cs @@ -32,11 +32,11 @@ public class LocalizationResourceContributorList : List dictionary, - DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) + bool includeDynamicContributors = true) { foreach (var contributor in this) { - if (dynamicLocalizationPreference == DynamicLocalizationPreference.Exclude && contributor.IsDynamic) + if (!includeDynamicContributors && contributor.IsDynamic) { continue; } @@ -48,11 +48,11 @@ public class LocalizationResourceContributorList : List dictionary, - DynamicLocalizationPreference dynamicLocalizationPreference = DynamicLocalizationPreference.Include) + bool includeDynamicContributors = true) { foreach (var contributor in this) { - if (dynamicLocalizationPreference == DynamicLocalizationPreference.Exclude && contributor.IsDynamic) + if (!includeDynamicContributors && contributor.IsDynamic) { continue; } diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index 342e6d8708..ee0e929e32 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -311,7 +311,7 @@ public class AbpLocalization_Tests : AbpIntegratedTest Date: Mon, 5 Sep 2022 19:01:32 +0300 Subject: [PATCH 48/61] Revert "Update AbpStringLocalizerExtensions.cs" This reverts commit 23fabb1fde8f685fdfada165487c1d7e9abc2291. --- .../Abp/Localization/AbpStringLocalizerExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs index 29fa60b3d9..9b3bb2c201 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerExtensions.cs @@ -42,7 +42,7 @@ public static class AbpStringLocalizerExtensions this IStringLocalizer stringLocalizer, bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference) + bool includeDynamicContributors) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) @@ -50,7 +50,7 @@ public static class AbpStringLocalizerExtensions return abpStringLocalizer.GetAllStrings( includeParentCultures, includeBaseLocalizers, - dynamicLocalizationPreference + includeDynamicContributors ); } @@ -63,7 +63,7 @@ public static class AbpStringLocalizerExtensions this IStringLocalizer stringLocalizer, bool includeParentCultures, bool includeBaseLocalizers, - DynamicLocalizationPreference dynamicLocalizationPreference) + bool includeDynamicContributors) { var internalLocalizer = ((IStringLocalizer)ProxyHelper.UnProxy(stringLocalizer)).GetInternalLocalizer(); if (internalLocalizer is IAbpStringLocalizer abpStringLocalizer) @@ -71,7 +71,7 @@ public static class AbpStringLocalizerExtensions return await abpStringLocalizer.GetAllStringsAsync( includeParentCultures, includeBaseLocalizers, - dynamicLocalizationPreference + includeDynamicContributors ); } @@ -113,4 +113,4 @@ public static class AbpStringLocalizerExtensions localizer.GetAllStrings(includeParentCultures: true) ); } -} \ No newline at end of file +} From 4ad86120d18a2f61f70c3909c935d0fa82da284a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 19:12:31 +0300 Subject: [PATCH 49/61] Revert AbpApplicationLocalizationAppService --- .../AbpApplicationLocalizationAppService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 01d97ca34d..0ca0f364cb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -52,7 +52,7 @@ public class AbpApplicationLocalizationAppService : staticLocalizedStrings = (await localizer.GetAllStringsAsync( includeParentCultures: true, includeBaseLocalizers: false, - dynamicLocalizationPreference: DynamicLocalizationPreference.Exclude + includeDynamicContributors: false )).ToDictionary(x => x.Name); } From 964d55146c5e9285c5685f3869414c5e2474b980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 19:23:58 +0300 Subject: [PATCH 50/61] Update abp-generate-proxy.json --- .../ClientProxies/abp-generate-proxy.json | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json index 018e1c4b3b..703bcc765a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json @@ -155,26 +155,26 @@ } ], "actions": { - "GetAsyncByCulture": { - "uniqueName": "GetAsyncByCulture", + "GetAsyncByInput": { + "uniqueName": "GetAsyncByInput", "name": "GetAsync", "httpMethod": "GET", "url": "api/abp/application-localization/{culture}", "supportedVersions": [], "parametersOnMethod": [ { - "name": "culture", - "typeAsString": "System.String, System.Private.CoreLib", - "type": "System.String", - "typeSimple": "string", + "name": "input", + "typeAsString": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationRequestDto, Volo.Abp.AspNetCore.Mvc.Contracts", + "type": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationRequestDto", + "typeSimple": "Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationRequestDto", "isOptional": false, "defaultValue": null } ], "parameters": [ { - "nameOnMethod": "culture", - "name": "culture", + "nameOnMethod": "input", + "name": "Culture", "jsonName": null, "type": "System.String", "typeSimple": "string", @@ -182,7 +182,19 @@ "defaultValue": null, "constraintTypes": [], "bindingSourceId": "Path", - "descriptorName": "" + "descriptorName": "input" + }, + { + "nameOnMethod": "input", + "name": "OnlyDynamics", + "jsonName": null, + "type": "System.Boolean", + "typeSimple": "boolean", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "input" } ], "returnValue": { From 7d1faaec5c953db15082e6cc4dcd6cec4d1dcd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 19:35:56 +0300 Subject: [PATCH 51/61] Fix client proxy --- .../ClientProxies/abp-generate-proxy.json | 6 +++--- .../AbpApplicationLocalizationController.cs | 1 - .../AbpApplicationLocalizationScriptController.cs | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json index 703bcc765a..ece1021fce 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json @@ -159,7 +159,7 @@ "uniqueName": "GetAsyncByInput", "name": "GetAsync", "httpMethod": "GET", - "url": "api/abp/application-localization/{culture}", + "url": "api/abp/application-localization", "supportedVersions": [], "parametersOnMethod": [ { @@ -180,8 +180,8 @@ "typeSimple": "string", "isOptional": false, "defaultValue": null, - "constraintTypes": [], - "bindingSourceId": "Path", + "constraintTypes": null, + "bindingSourceId": "ModelBinding", "descriptorName": "input" }, { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs index c140ec5029..a056746022 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationController.cs @@ -16,7 +16,6 @@ public class AbpApplicationLocalizationController: AbpControllerBase, IAbpApplic } [HttpGet] - [Route("{culture}")] public virtual async Task GetAsync(ApplicationLocalizationRequestDto input) { return await _localizationAppService.GetAsync(input); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs index 8147540e73..fe7df42bf3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -38,7 +38,6 @@ public class AbpApplicationLocalizationScriptController : AbpController } [HttpGet] - [Route("{culture}")] [Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] public async Task GetAsync(ApplicationLocalizationRequestDto input) { From 9bb5ca57923e311bc2ab2cbb8c57035265828ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 5 Sep 2022 19:43:49 +0300 Subject: [PATCH 52/61] Fix basic theme for localization script URL. --- .../Themes/Basic/Layouts/Account.cshtml | 2 +- .../Themes/Basic/Layouts/Application.cshtml | 2 +- .../Themes/Basic/Layouts/Empty.cshtml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index c99ede98e5..66c0805e1d 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -96,7 +96,7 @@ - + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 4beff28030..5709c5748c 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -69,7 +69,7 @@ - + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 61910931cc..5139137417 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -64,7 +64,7 @@ - + From 3d5572d77635e5c71f09c3a0aa938e51a8d267da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 09:06:14 +0300 Subject: [PATCH 53/61] Implement RemoteExternalLocalizationStore --- .../Client/RemoteExternalLocalizationStore.cs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteExternalLocalizationStore.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteExternalLocalizationStore.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteExternalLocalizationStore.cs new file mode 100644 index 0000000000..c5548acc62 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteExternalLocalizationStore.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Localization.External; + +namespace Volo.Abp.AspNetCore.Mvc.Client; + +public class RemoteExternalLocalizationStore : IExternalLocalizationStore, ITransientDependency +{ + protected ICachedApplicationConfigurationClient ConfigurationClient { get; } + protected AbpLocalizationOptions LocalizationOptions { get; } + + public RemoteExternalLocalizationStore( + ICachedApplicationConfigurationClient configurationClient, + IOptions localizationOptions) + { + ConfigurationClient = configurationClient; + LocalizationOptions = localizationOptions.Value; + } + + public virtual LocalizationResourceBase GetResourceOrNull(string resourceName) + { + var configurationDto = ConfigurationClient.Get(); + return CreateLocalizationResourceFromConfigurationOrNull(resourceName, configurationDto); + } + + public virtual async Task GetResourceOrNullAsync(string resourceName) + { + var configurationDto = await ConfigurationClient.GetAsync(); + return CreateLocalizationResourceFromConfigurationOrNull(resourceName, configurationDto); + } + + public virtual async Task GetResourceNamesAsync() + { + var configurationDto = await ConfigurationClient.GetAsync(); + return configurationDto + .Localization + .Resources + .Keys + .Where(x => !LocalizationOptions.Resources.ContainsKey(x)) + .ToArray(); +; } + + public virtual async Task GetResourcesAsync() + { + var configurationDto = await ConfigurationClient.GetAsync(); + var resources = new List(); + + foreach (var resource in configurationDto.Localization.Resources) + { + if (LocalizationOptions.Resources.ContainsKey(resource.Key)) + { + continue; + } + + resources.Add(CreateNonTypedLocalizationResource(resource.Key, resource.Value)); + } + + return resources.ToArray(); + } + + protected virtual LocalizationResourceBase CreateLocalizationResourceFromConfigurationOrNull( + string resourceName, + ApplicationConfigurationDto configurationDto) + { + var resourceDto = configurationDto.Localization.Resources.GetOrDefault(resourceName); + + if (resourceDto == null) + { + return null; + } + + return CreateNonTypedLocalizationResource(resourceName, resourceDto); + } + + protected virtual NonTypedLocalizationResource CreateNonTypedLocalizationResource( + string resourceName, + ApplicationLocalizationResourceDto resourceDto) + { + return new NonTypedLocalizationResource(resourceName) + .AddBaseResources(resourceDto.BaseResources); + } +} \ No newline at end of file From 206642d412af7085494db47fdefa180ef4bbf87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 10:58:23 +0300 Subject: [PATCH 54/61] Do not use cookies for c# client proxies. --- .../ServiceCollectionHttpClientProxyExtensions.cs | 11 +++++++++++ .../Abp/Http/Client/AbpHttpClientBuilderOptions.cs | 3 +++ 2 files changed, 14 insertions(+) diff --git a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs index 7bc239813d..57233ac972 100644 --- a/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs +++ b/framework/src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionHttpClientProxyExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net.Http; using System.Reflection; using Castle.DynamicProxy; using JetBrains.Annotations; @@ -196,6 +197,16 @@ public static class ServiceCollectionHttpClientProxyExtensions { clientBuildAction(remoteServiceConfigurationName, provider, client); } + }).ConfigurePrimaryHttpMessageHandler((provider) => + { + var handler = new HttpClientHandler { UseCookies = false }; + + foreach (var handlerAction in preOptions.ProxyClientHandlerActions) + { + handlerAction(remoteServiceConfigurationName, provider, handler); + } + + return handler; }); foreach (var clientBuildAction in preOptions.ProxyClientBuildActions) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs index 240f35fe0a..b2ffae98a5 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/AbpHttpClientBuilderOptions.cs @@ -12,11 +12,14 @@ public class AbpHttpClientBuilderOptions internal HashSet ConfiguredProxyClients { get; } public List> ProxyClientActions { get; } + + public List> ProxyClientHandlerActions { get; } public AbpHttpClientBuilderOptions() { ProxyClientBuildActions = new List>(); ConfiguredProxyClients = new HashSet(); ProxyClientActions = new List>(); + ProxyClientHandlerActions = new List>(); } } From fef4d68eb390cbbd5026617152097e6426cd8eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 11:36:05 +0300 Subject: [PATCH 55/61] Moved AbpExternalLocalizationOptions to the language management module --- .../AbpRequestLocalizationMiddleware.cs | 4 +++- .../External/AbpExternalLocalizationOptions.cs | 9 --------- 2 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs index 1324df0865..6fd02a0470 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs @@ -27,7 +27,9 @@ public class AbpRequestLocalizationMiddleware : IMiddleware, ITransientDependenc { var middleware = new RequestLocalizationMiddleware( next, - new OptionsWrapper(await _requestLocalizationOptionsProvider.GetLocalizationOptionsAsync()), + new OptionsWrapper( + await _requestLocalizationOptionsProvider.GetLocalizationOptionsAsync() + ), _loggerFactory ); diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs deleted file mode 100644 index 617ca3cf4e..0000000000 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/External/AbpExternalLocalizationOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.Abp.Localization.External; - -public class AbpExternalLocalizationOptions -{ - /// - /// Default: true. - /// - public bool SaveToExternalStore { get; set; } = true; -} \ No newline at end of file From 6310b81c38dd3aab700d0006864cc4a62bd5558e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 11:58:17 +0300 Subject: [PATCH 56/61] LocalizableStringSerializer should support external localization resources. --- .../ObjectExtending/CachedObjectExtensionsDtoService.cs | 4 +--- .../Volo/Abp/Localization/LocalizableString.cs | 2 +- .../Volo/Abp/Localization/LocalizableStringSerializer.cs | 7 +------ 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index 8acfcefd3d..0f9b05830d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -204,9 +204,7 @@ public class CachedObjectExtensionsDtoService : ICachedObjectExtensionsDtoServic { return new LocalizableStringDto( localizableStringInstance.Name, - localizableStringInstance.ResourceType != null - ? LocalizationResourceNameAttribute.GetName(localizableStringInstance.ResourceType) - : null + localizableStringInstance.ResourceName ); } diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 009e4ec445..a98f207a55 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -38,7 +38,7 @@ public class LocalizableString : ILocalizableString, IAsyncLocalizableString var localizer = CreateStringLocalizerOrNull(stringLocalizerFactory); if (localizer == null) { - throw new AbpException($"Set {nameof(ResourceName)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); + return new LocalizedString(Name, Name, resourceNotFound: true); } var result = localizer[Name]; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs index a6181d0a61..da431bca65 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -17,7 +17,7 @@ public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransi { if (localizableString is LocalizableString realLocalizableString) { - return $"L:{LocalizationResourceNameAttribute.GetName(realLocalizableString.ResourceType)},{realLocalizableString.Name}"; + return $"L:{realLocalizableString.ResourceName},{realLocalizableString.Name}"; } if (localizableString is FixedLocalizableString fixedLocalizableString) @@ -56,11 +56,6 @@ public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransi throw new AbpException("Invalid LocalizableString value: " + value); } - if (!LocalizationOptions.Resources.ContainsKey(resourceName)) - { - resourceName = null; - } - return LocalizableString.Create(name, resourceName); default: return new FixedLocalizableString(value); From 49b05c5e7cf657d040bb27380d7f214ff4072edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 13:26:07 +0300 Subject: [PATCH 57/61] Remove DisplayNameKey and DisplayNameResource form PermissionGrantInfoDto Because localization can be properly done in the backend side now. --- .../PermissionGrantInfoDto.cs | 4 -- .../PermissionAppService.cs | 6 --- .../PermissionManagementModal.razor.cs | 45 ------------------ .../PermissionManagementModal.cshtml.cs | 46 ------------------- 4 files changed, 101 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs index 12e4010f99..b608a69b54 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs @@ -7,10 +7,6 @@ public class PermissionGrantInfoDto public string Name { get; set; } public string DisplayName { get; set; } - - public string DisplayNameKey { get; set; } - - public string DisplayNameResource { get; set; } public string ParentName { get; set; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index fd0ccf0246..8579fa28ac 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -101,15 +101,9 @@ public class PermissionAppService : ApplicationService, IPermissionAppService private PermissionGrantInfoDto CreatePermissionGrantInfoDto(PermissionDefinition permission) { - var localizableDisplayName = permission.DisplayName as LocalizableString; - return new PermissionGrantInfoDto { Name = permission.Name, DisplayName = permission.DisplayName.Localize(StringLocalizerFactory), - DisplayNameKey = localizableDisplayName?.Name, - DisplayNameResource = localizableDisplayName?.ResourceType != null - ? LocalizationResourceNameAttribute.GetName(localizableDisplayName.ResourceType) - : null, ParentName = permission.Parent?.Name, AllowedProviders = permission.Providers, GrantedProviders = new List() diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs index 364fd5c300..b96a1c9d4d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs @@ -84,8 +84,6 @@ public partial class PermissionManagementModal var result = await PermissionAppService.GetAsync(_providerName, _providerKey); - UpdateLocalizations(result); - _entityDisplayName = entityDisplayName ?? result.EntityDisplayName; _groups = result.Groups; @@ -252,47 +250,4 @@ public partial class PermissionManagementModal eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; return Task.CompletedTask; } - - protected virtual void UpdateLocalizations(GetPermissionListResultDto result) - { - foreach (var group in result.Groups) - { - group.DisplayName = Localize( - group.DisplayNameKey, - group.DisplayNameResource, - group.DisplayName - ); - - foreach (var permission in group.Permissions) - { - permission.DisplayName = Localize( - permission.DisplayNameKey, - permission.DisplayNameResource, - permission.DisplayName - ); - } - } - } - - protected virtual string Localize(string key, string resourceName, string fallbackValue) - { - if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) - { - return fallbackValue; - } - - var resource = LocalizationOptions.Value.Resources.GetOrDefault(resourceName); - if (resource == null) - { - return fallbackValue; - } - - var result = new LocalizableString(key, resourceName).Localize(StringLocalizerFactory); - if (result.ResourceNotFound) - { - return fallbackValue; - } - - return result.Value; - } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs index feb8481f27..9d91fc573e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; @@ -60,8 +59,6 @@ public class PermissionManagementModal : AbpPageModel var result = await PermissionAppService.GetAsync(ProviderName, ProviderKey); - UpdateLocalizations(result); - EntityDisplayName = !string.IsNullOrWhiteSpace(ProviderKeyDisplayName) ? ProviderKeyDisplayName : result.EntityDisplayName; @@ -86,49 +83,6 @@ public class PermissionManagementModal : AbpPageModel return Page(); } - private void UpdateLocalizations(GetPermissionListResultDto result) - { - foreach (var group in result.Groups) - { - group.DisplayName = Localize( - group.DisplayNameKey, - group.DisplayNameResource, - group.DisplayName - ); - - foreach (var permission in group.Permissions) - { - permission.DisplayName = Localize( - permission.DisplayNameKey, - permission.DisplayNameResource, - permission.DisplayName - ); - } - } - } - - private string Localize(string key, string resourceName, string fallbackValue) - { - if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) - { - return fallbackValue; - } - - var resource = LocalizationOptions.Resources.GetOrDefault(resourceName); - if (resource == null) - { - return fallbackValue; - } - - var result = new LocalizableString(key, resourceName).Localize(StringLocalizerFactory); - if (result.ResourceNotFound) - { - return fallbackValue; - } - - return result.Value; - } - public virtual async Task OnPostAsync() { ValidateModel(); From a9fcdf007422224b2596cb32f92fdb5bea68b531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 14:20:21 +0300 Subject: [PATCH 58/61] Change culture parameter to cultureName. --- .../WebAssemblyCachedApplicationConfigurationClient.cs | 2 +- .../ClientProxies/abp-generate-proxy.json | 2 +- .../Mvc/Client/MvcCachedApplicationConfigurationClient.cs | 2 +- .../ApplicationLocalizationRequestDto.cs | 2 +- .../AbpApplicationLocalizationAppService.cs | 2 +- .../Themes/Basic/Layouts/Account.cshtml | 2 +- .../Themes/Basic/Layouts/Application.cshtml | 2 +- .../Themes/Basic/Layouts/Empty.cshtml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs index d6067f2ba0..c3ba260a88 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs @@ -39,7 +39,7 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( new ApplicationLocalizationRequestDto { - Culture = configurationDto.Localization.CurrentCulture.Name, + CultureName = configurationDto.Localization.CurrentCulture.Name, OnlyDynamics = true } ); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json index ece1021fce..ce18e3eefd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/ClientProxies/abp-generate-proxy.json @@ -174,7 +174,7 @@ "parameters": [ { "nameOnMethod": "input", - "name": "Culture", + "name": "CultureName", "jsonName": null, "type": "System.String", "typeSimple": "string", diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs index edfed09708..405d43906d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client/Volo/Abp/AspNetCore/Mvc/Client/MvcCachedApplicationConfigurationClient.cs @@ -71,7 +71,7 @@ public class MvcCachedApplicationConfigurationClient : ICachedApplicationConfigu var localizationDto = await ApplicationLocalizationClientProxy.GetAsync( new ApplicationLocalizationRequestDto { - Culture = config.Localization.CurrentCulture.Name, + CultureName = config.Localization.CurrentCulture.Name, OnlyDynamics = true } ); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs index d33346d149..535d572b3f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationRequestDto.cs @@ -5,7 +5,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; public class ApplicationLocalizationRequestDto { [Required] - public string Culture { get; set; } + public string CultureName { get; set; } public bool OnlyDynamics { get; set; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs index 0ca0f364cb..48d7f949c3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationLocalizationAppService.cs @@ -26,7 +26,7 @@ public class AbpApplicationLocalizationAppService : public async Task GetAsync(ApplicationLocalizationRequestDto input) { - using (CultureHelper.Use(input.Culture)) + using (CultureHelper.Use(input.CultureName)) { var resources = LocalizationOptions .Resources diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml index 66c0805e1d..02adac253b 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml @@ -96,7 +96,7 @@ - + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml index 5709c5748c..4c91b8edfb 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Application.cshtml @@ -69,7 +69,7 @@ - + diff --git a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml index 5139137417..aaef7898c3 100644 --- a/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml +++ b/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Empty.cshtml @@ -64,7 +64,7 @@ - + From 058cd3765713e8ee22429d9854cb02499084d17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 6 Sep 2022 19:40:18 +0300 Subject: [PATCH 59/61] Remove unnecessary Polly dependency from Volo.Abp.Localization.csproj --- .../src/Volo.Abp.Localization/Volo.Abp.Localization.csproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj index 2aefa76caa..53e71d1c38 100644 --- a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj +++ b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj @@ -25,8 +25,5 @@ - - - - + From 9c524467305f27bc227b42633229652449d109a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 7 Sep 2022 15:31:43 +0300 Subject: [PATCH 60/61] MVC JavaScript APIs should generate script in the UI side They should not get the configuration from backend (for a tiered / microservice scenario). For tiered, this has a better pefrormance. For microservice, UI will know more than the service that returns the configuration and localizations. --- .../AbpApplicationConfigurationScriptController.cs | 4 ++-- .../AbpApplicationLocalizationScriptController.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs index 791f5ca262..7fafee261c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationScriptController.cs @@ -17,14 +17,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; [ApiExplorerSettings(IgnoreApi = true)] public class AbpApplicationConfigurationScriptController : AbpController { - private readonly IAbpApplicationConfigurationAppService _configurationAppService; + private readonly AbpApplicationConfigurationAppService _configurationAppService; private readonly IJsonSerializer _jsonSerializer; private readonly AbpAspNetCoreMvcOptions _options; private readonly IJavascriptMinifier _javascriptMinifier; private readonly IAbpAntiForgeryManager _antiForgeryManager; public AbpApplicationConfigurationScriptController( - IAbpApplicationConfigurationAppService configurationAppService, + AbpApplicationConfigurationAppService configurationAppService, IJsonSerializer jsonSerializer, IOptions options, IJavascriptMinifier javascriptMinifier, diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs index fe7df42bf3..d8da85f871 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpApplicationLocalizationScriptController.cs @@ -20,13 +20,13 @@ namespace Volo.Abp.AspNetCore.Mvc.Localization; [ApiExplorerSettings(IgnoreApi = true)] public class AbpApplicationLocalizationScriptController : AbpController { - protected IAbpApplicationLocalizationAppService LocalizationAppService { get; } + protected AbpApplicationLocalizationAppService LocalizationAppService { get; } protected AbpAspNetCoreMvcOptions Options { get; } protected IJsonSerializer JsonSerializer { get; } protected IJavascriptMinifier JavascriptMinifier { get; } public AbpApplicationLocalizationScriptController( - IAbpApplicationLocalizationAppService localizationAppService, + AbpApplicationLocalizationAppService localizationAppService, IOptions options, IJsonSerializer jsonSerializer, IJavascriptMinifier javascriptMinifier) From cfc7007cec32e9b60192cbf116b9b0ed418fbd0b Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 8 Sep 2022 10:59:22 +0800 Subject: [PATCH 61/61] Handle zh culture in `IsCompatibleCulture` method. --- .../Volo/Abp/Localization/CultureHelper.cs | 16 ++++++++++++++- .../Abp/Localization/CultureHelper_Tests.cs | 20 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs index a4e55e9ddd..74a62116a4 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Localization/CultureHelper.cs @@ -60,7 +60,7 @@ public static class CultureHelper { return new CultureInfo(cultureName).Parent.Name; } - + public static bool IsCompatibleCulture( string sourceCultureName, string targetCultureName) @@ -70,6 +70,20 @@ public static class CultureHelper return true; } + if (sourceCultureName.StartsWith("zh") && targetCultureName.StartsWith("zh")) + { + var culture = new CultureInfo(targetCultureName); + do + { + if (culture.Name == sourceCultureName) + { + return true; + } + + culture = new CultureInfo(culture.Name).Parent; + } while (!culture.Equals(CultureInfo.InvariantCulture)); + } + if (sourceCultureName.Contains("-")) { return false; diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs index f3bd4a49a7..d55df57800 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Localization/CultureHelper_Tests.cs @@ -13,8 +13,24 @@ public class CultureHelper_Tests CultureHelper.IsCompatibleCulture("en", "tr").ShouldBeFalse(); CultureHelper.IsCompatibleCulture("en", "tr-TR").ShouldBeFalse(); - + CultureHelper.IsCompatibleCulture("en-US", "en").ShouldBeFalse(); CultureHelper.IsCompatibleCulture("en-US", "en-GB").ShouldBeFalse(); + + CultureHelper.IsCompatibleCulture("zh", "zh-CN").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-HK").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-MO").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-SG").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-TW").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-Hans").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh", "zh-Hant").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh-Hans", "zh-CN").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh-Hans", "zh-SG").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh-Hant", "zh-HK").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh-Hant", "zh-MO").ShouldBeTrue(); + CultureHelper.IsCompatibleCulture("zh-Hant", "zh-TW").ShouldBeTrue(); + + CultureHelper.IsCompatibleCulture("zh-Hans", "zh-HK").ShouldBeFalse(); + CultureHelper.IsCompatibleCulture("zh-Hant", "zh-SG").ShouldBeFalse(); } -} \ No newline at end of file +}