diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln index 05a94bccc..6f95fc248 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln @@ -664,6 +664,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Identity.AspNet EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.AspNetCore", "framework\wechat\LINGYUN.Abp.WeChat.Work.AspNetCore\LINGYUN.Abp.WeChat.Work.AspNetCore.csproj", "{40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Identity.WeChat.Work", "framework\wechat\LINGYUN.Abp.Identity.WeChat.Work\LINGYUN.Abp.Identity.WeChat.Work.csproj", "{CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1762,6 +1764,10 @@ Global {40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E}.Debug|Any CPU.Build.0 = Debug|Any CPU {40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E}.Release|Any CPU.Build.0 = Release|Any CPU + {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2085,6 +2091,7 @@ Global {4C7594CE-FB2F-4309-B95C-D4460892CF6E} = {7C714185-D3D9-4D94-B5CB-D857A0091F04} {C9266D5D-3860-09C3-F566-489BBB57A534} = {D94D6AFE-20BD-4F21-8708-03F5E34F49FC} {40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E} = {91867618-0D86-4410-91C6-B1166A9ACDF9} + {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5} = {91867618-0D86-4410-91C6-B1166A9ACDF9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1} diff --git a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj index 753f85c89..0b01d2d85 100644 --- a/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj +++ b/aspnet-core/framework/auditing/LINGYUN.Abp.AuditLogging.IP.Location/LINGYUN.Abp.AuditLogging.IP.Location.csproj @@ -14,9 +14,6 @@ false - - netstandard2.0 - diff --git a/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/TextAppService.cs b/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/TextAppService.cs index a5cf04a00..754915b66 100644 --- a/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/TextAppService.cs +++ b/aspnet-core/framework/localization/LINGYUN.Abp.AspNetCore.Mvc.Localization/LINGYUN/Abp/AspNetCore/Mvc/Localization/TextAppService.cs @@ -99,7 +99,7 @@ public class TextAppService : ApplicationService, ITextAppService using (CultureHelper.Use(cultureName, cultureName)) { - localizedStrings = (await localizer.GetAllStringsAsync(true)) + localizedStrings = (await localizer.GetAllStringsAsync(true, false, true)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter)) .OrderBy(l => l.Name); } @@ -112,7 +112,7 @@ public class TextAppService : ApplicationService, ITextAppService { using (CultureHelper.Use(targetCultureName, targetCultureName)) { - targetLocalizedStrings = (await localizer.GetAllStringsAsync(true)) + targetLocalizedStrings = (await localizer.GetAllStringsAsync(false, false, true)) .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Name.Contains(filter)) .OrderBy(l => l.Name); } diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs index e719a51e6..6bb3ae3e9 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application.Contracts/LINGYUN/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs @@ -1,5 +1,7 @@ -using LINGYUN.Abp.LocalizationManagement.Localization; +using LINGYUN.Abp.LocalizationManagement.Features; +using LINGYUN.Abp.LocalizationManagement.Localization; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Features; using Volo.Abp.Localization; namespace LINGYUN.Abp.LocalizationManagement.Permissions; @@ -15,53 +17,65 @@ public class LocalizationManagementPermissionDefinitionProvider : PermissionDefi var resourcePermission = permissionGroup.AddPermission( LocalizationManagementPermissions.Resource.Default, L("Permissions:Resource"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); resourcePermission.AddChild( LocalizationManagementPermissions.Resource.Create, L("Permissions:Create"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); resourcePermission.AddChild( LocalizationManagementPermissions.Resource.Update, L("Permissions:Update"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); resourcePermission.AddChild( LocalizationManagementPermissions.Resource.Delete, L("Permissions:Delete"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); var languagePermission = permissionGroup.AddPermission( LocalizationManagementPermissions.Language.Default, L("Permissions:Language"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); languagePermission.AddChild( LocalizationManagementPermissions.Language.Create, L("Permissions:Create"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); languagePermission.AddChild( LocalizationManagementPermissions.Language.Update, L("Permissions:Update"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); languagePermission.AddChild( LocalizationManagementPermissions.Language.Delete, L("Permissions:Delete"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); var textPermission = permissionGroup.AddPermission( LocalizationManagementPermissions.Text.Default, L("Permissions:Text"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); textPermission.AddChild( LocalizationManagementPermissions.Text.Create, L("Permissions:Create"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); textPermission.AddChild( LocalizationManagementPermissions.Text.Update, L("Permissions:Update"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); textPermission.AddChild( LocalizationManagementPermissions.Text.Delete, L("Permissions:Delete"), - Volo.Abp.MultiTenancy.MultiTenancySides.Host); + Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .RequireFeatures(LocalizationManagementFeatures.Enable); } private static LocalizableString L(string name) diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/LanguageAppService.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/LanguageAppService.cs index 90fae14c8..ac5220099 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/LanguageAppService.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/LanguageAppService.cs @@ -1,6 +1,8 @@ -using LINGYUN.Abp.LocalizationManagement.Permissions; +using LINGYUN.Abp.LocalizationManagement.Features; +using LINGYUN.Abp.LocalizationManagement.Permissions; using Microsoft.AspNetCore.Authorization; using System.Globalization; +using System.Runtime.Versioning; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Localization; @@ -8,6 +10,7 @@ using Volo.Abp.Localization; namespace LINGYUN.Abp.LocalizationManagement; [Authorize(LocalizationManagementPermissions.Language.Default)] +[RequiresPreviewFeatures(LocalizationManagementFeatures.Enable)] public class LanguageAppService : LocalizationAppServiceBase, ILanguageAppService { private readonly ILanguageRepository _repository; diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/ResourceAppService.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/ResourceAppService.cs index fde5b7baa..83d4b58aa 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/ResourceAppService.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/ResourceAppService.cs @@ -1,11 +1,14 @@ -using LINGYUN.Abp.LocalizationManagement.Permissions; +using LINGYUN.Abp.LocalizationManagement.Features; +using LINGYUN.Abp.LocalizationManagement.Permissions; using Microsoft.AspNetCore.Authorization; +using System.Runtime.Versioning; using System.Threading.Tasks; using Volo.Abp; namespace LINGYUN.Abp.LocalizationManagement; [Authorize(LocalizationManagementPermissions.Resource.Default)] +[RequiresPreviewFeatures(LocalizationManagementFeatures.Enable)] public class ResourceAppService : LocalizationAppServiceBase, IResourceAppService { private readonly IResourceRepository _repository; diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/TextAppService.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/TextAppService.cs index 54e32edba..90973a94b 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/TextAppService.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Application/LINGYUN/Abp/LocalizationManagement/TextAppService.cs @@ -1,10 +1,13 @@ -using LINGYUN.Abp.LocalizationManagement.Permissions; +using LINGYUN.Abp.LocalizationManagement.Features; +using LINGYUN.Abp.LocalizationManagement.Permissions; using Microsoft.AspNetCore.Authorization; +using System.Runtime.Versioning; using System.Threading.Tasks; namespace LINGYUN.Abp.LocalizationManagement; [Authorize(LocalizationManagementPermissions.Text.Default)] +[RequiresPreviewFeatures(LocalizationManagementFeatures.Enable)] public class TextAppService : LocalizationAppServiceBase, ITextAppService { private readonly ITextRepository _textRepository; diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj index f89f38827..88d1ce1b4 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj @@ -24,6 +24,7 @@ + diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs index ec03a92d7..0b0c57782 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.LocalizationManagement.Localization; +using Volo.Abp.Features; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; @@ -8,6 +9,7 @@ using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.LocalizationManagement; [DependsOn( + typeof(AbpFeaturesModule), typeof(AbpValidationModule), typeof(AbpLocalizationModule))] public class AbpLocalizationManagementDomainSharedModule : AbpModule diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatureDefinitionProvider.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatureDefinitionProvider.cs new file mode 100644 index 000000000..516c38d48 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatureDefinitionProvider.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.LocalizationManagement.Localization; +using Volo.Abp.Features; +using Volo.Abp.Localization; +using Volo.Abp.Validation.StringValues; + +namespace LINGYUN.Abp.LocalizationManagement.Features; + +public class LocalizationManagementFeatureDefinitionProvider : FeatureDefinitionProvider +{ + public override void Define(IFeatureDefinitionContext context) + { + var group = context.AddGroup(LocalizationManagementFeatures.GroupName, + L("Feature:LocalizationManagement")); + group.AddFeature(LocalizationManagementFeatures.Enable, + "true", + L("Feature:LocalizationManagementEnable"), + L("Feature:LocalizationManagementEnableDesc"), + new ToggleStringValueType()); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatures.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatures.cs new file mode 100644 index 000000000..95e4f6493 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Features/LocalizationManagementFeatures.cs @@ -0,0 +1,8 @@ +namespace LINGYUN.Abp.LocalizationManagement.Features; + +public static class LocalizationManagementFeatures +{ + public const string GroupName = "LocalizationManagement"; + + public const string Enable = GroupName + ".Enable"; +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/en.json b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/en.json index 70e9d1801..469b831aa 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/en.json @@ -6,6 +6,9 @@ "DisplayName:CreationTime": "Creation Time", "DisplayName:LastModificationTime": "Modification Time", "DisplayName:SaveAndNext": "Save & Next", + "Feature:LocalizationManagement": "Localization Management", + "Feature:LocalizationManagementEnable": "Enable Localization Management", + "Feature:LocalizationManagementEnableDesc": "Enable localization management in the application", "Permissions:LocalizationManagement": "Localization", "Permissions:Language": "Language", "Permissions:Resource": "Resource", diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json index 7bc476760..a78673b5c 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain.Shared/LINGYUN/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json @@ -6,6 +6,9 @@ "DisplayName:CreationTime": "创建时间", "DisplayName:LastModificationTime": "变更时间", "DisplayName:SaveAndNext": "保存并下一步", + "Feature:LocalizationManagement": "本地化管理", + "Feature:LocalizationManagementEnable": "启用本地化管理", + "Feature:LocalizationManagementEnableDesc": "在应用程序中启用本地化管理", "Permissions:LocalizationManagement": "本地化管理", "Permissions:Language": "语言管理", "Permissions:Resource": "资源管理", diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationResourceContributor.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationResourceContributor.cs new file mode 100644 index 000000000..02791a5e8 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationResourceContributor.cs @@ -0,0 +1,69 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public class ExternalLocalizationResourceContributor : ILocalizationResourceContributor +{ + public bool IsDynamic => false; + + protected LocalizationResourceBase Resource { get; private set; } + protected IExternalLocalizationStoreCache StoreCache { get; private set; } + protected IExternalLocalizationTextStoreCache TextStoreCache { get; private set; } + + public virtual void Fill(string cultureName, Dictionary dictionary) + { + var texts = TextStoreCache.GetTexts(Resource, cultureName); + + foreach (var text in texts) + { + dictionary[text.Key] = new LocalizedString(text.Key, text.Value); + } + } + + public async virtual Task FillAsync(string cultureName, Dictionary dictionary) + { + var texts = await TextStoreCache.GetTextsAsync(Resource, cultureName); + + foreach (var text in texts) + { + dictionary[text.Key] = new LocalizedString(text.Key, text.Value); + } + } + + public virtual LocalizedString GetOrNull(string cultureName, string name) + { + var texts = TextStoreCache.GetTexts(Resource, cultureName); + + var text = texts.GetOrDefault(name); + if (text == null) + { + return null; + } + + return new LocalizedString(name, text); + } + + public async virtual Task> GetSupportedCulturesAsync() + { + var cacheItem = await StoreCache.GetResourceOrNullAsync(Resource.ResourceName); + + if (cacheItem == null || !cacheItem.IsEnabled) + { + return Array.Empty(); + } + + return cacheItem.SupportedCultures; + } + + public void Initialize(LocalizationResourceInitializationContext context) + { + Resource = context.Resource; + StoreCache = context.ServiceProvider.GetRequiredService(); + TextStoreCache = context.ServiceProvider.GetRequiredService(); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStore.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStore.cs new file mode 100644 index 000000000..cff5a80a9 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStore.cs @@ -0,0 +1,90 @@ +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Localization.External; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +[Dependency(ReplaceServices = true)] +public class ExternalLocalizationStore : IExternalLocalizationStore, ITransientDependency +{ + protected AbpLocalizationOptions LocalizationOptions { get; } + protected IExternalLocalizationStoreCache StoreCache { get; } + + public ExternalLocalizationStore( + IOptions localizationOptions, + IExternalLocalizationStoreCache storeCache) + { + LocalizationOptions = localizationOptions.Value; + StoreCache = storeCache; + } + + public virtual LocalizationResourceBase GetResourceOrNull(string resourceName) + { + var cacheItem = StoreCache.GetResourceOrNull(resourceName); + + if (cacheItem == null || LocalizationOptions.Resources.ContainsKey(cacheItem.Name)) + { + return null; + } + + return CreateNonTypedLocalizationResource(cacheItem); + } + + public async virtual Task GetResourceOrNullAsync(string resourceName) + { + var cacheItem = await StoreCache.GetResourceOrNullAsync(resourceName); + + if (cacheItem == null || LocalizationOptions.Resources.ContainsKey(cacheItem.Name)) + { + return null; + } + + return CreateNonTypedLocalizationResource(cacheItem); + } + + public async virtual Task GetResourceNamesAsync() + { + var cacheNames = await StoreCache.GetResourceNamesAsync(); + + return cacheNames + .Where(name => !LocalizationOptions.Resources.ContainsKey(name)) + .ToArray(); + } + + public async virtual Task GetResourcesAsync() + { + var cacheItem = await StoreCache.GetResourcesAsync(); + + + if (cacheItem == null) + { + return Array.Empty(); + } + + return cacheItem + .Where(x => x.IsEnabled) + .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) + .Select(CreateNonTypedLocalizationResource) + .ToArray(); + } + + protected virtual NonTypedLocalizationResource CreateNonTypedLocalizationResource(LocalizationResourceCacheItem cacheItem) + { + var localizationResource = new NonTypedLocalizationResource( + cacheItem.Name, + cacheItem.DefaultCulture); + + if (cacheItem.BaseResources.Length > 0) + { + localizationResource.AddBaseResources(cacheItem.BaseResources); + } + + localizationResource.Contributors.Add(new ExternalLocalizationResourceContributor()); + + return localizationResource; + } +} \ No newline at end of file diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs new file mode 100644 index 000000000..1e726cb59 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationStoreCache.cs @@ -0,0 +1,146 @@ +using Microsoft.Extensions.Options; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public class ExternalLocalizationStoreCache : IExternalLocalizationStoreCache, ITransientDependency +{ + protected IDistributedCache ResourceCache { get; } + protected IDistributedCache ResourcesCache { get; } + protected AbpLocalizationOptions LocalizationOptions { get; } + protected IResourceRepository ResourceRepository { get; } + + public ExternalLocalizationStoreCache( + IDistributedCache resourcesCache, + IDistributedCache resourceCache, + IOptions localizationOptions, + IResourceRepository resourceRepository) + { + ResourceCache = resourceCache; + ResourcesCache = resourcesCache; + ResourceRepository = resourceRepository; + LocalizationOptions = localizationOptions.Value; + } + + public async virtual Task RemoveAsync(string resourceName) + { + await ResourceCache.RemoveAsync(resourceName); + await ResourcesCache.RemoveAsync(LocalizationResourcesCacheItem.CacheKey); + } + + public async virtual Task GetResourceNamesAsync() + { + var cacheItem = await GetResourcesCacheItemAsync(); + + return cacheItem.Resources + .Where(x => x.IsEnabled) + .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) + .Select(x => x.Name) + .ToArray(); + } + + public virtual LocalizationResourceCacheItem GetResourceOrNull(string resourceName) + { + var cacheItem = GetResourceCacheItem(resourceName); + + return cacheItem.IsEnabled ? cacheItem : null; + } + + public async virtual Task GetResourceOrNullAsync(string resourceName) + { + var cacheItem = await GetResourceCacheItemAsync(resourceName); + + return cacheItem.IsEnabled ? cacheItem : null; + } + + public async virtual Task GetResourcesAsync() + { + var cacheItem = await GetResourcesCacheItemAsync(); + + return cacheItem.Resources + .Where(x => x.IsEnabled) + .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) + .ToArray(); + } + + protected virtual LocalizationResourceCacheItem GetResourceCacheItem(string resourceName) + { + var cacheItem = ResourceCache.Get(resourceName); + if (cacheItem == null) + { + var resource = ResourceRepository.FindByName(resourceName); + + if (resource == null) + { + cacheItem = new LocalizationResourceCacheItem(resourceName) + { + IsEnabled = false + }; + } + else + { + cacheItem = new LocalizationResourceCacheItem(resource.Name, resource.DefaultCultureName) + { + IsEnabled = resource.Enable + }; + } + + ResourceCache.Set(resourceName, cacheItem); + } + + return cacheItem; + } + + protected async virtual Task GetResourceCacheItemAsync(string resourceName) + { + var cacheItem = await ResourceCache.GetAsync(resourceName); + if (cacheItem == null) + { + var resource = await ResourceRepository.FindByNameAsync(resourceName); + if (resource == null) + { + cacheItem = new LocalizationResourceCacheItem(resourceName) + { + IsEnabled = false + }; + } + else + { + cacheItem = new LocalizationResourceCacheItem(resource.Name, resource.DefaultCultureName) + { + IsEnabled = resource.Enable + }; + } + + await ResourceCache.SetAsync(resourceName, cacheItem); + } + + return cacheItem; + } + + protected async virtual Task GetResourcesCacheItemAsync() + { + var cacheItem = await ResourcesCache.GetAsync(LocalizationResourcesCacheItem.CacheKey); + if (cacheItem == null) + { + var resources = await ResourceRepository.GetListAsync(); + var resourceItems = resources + .Where(x => !LocalizationOptions.Resources.ContainsKey(x.Name)) + .Select(x => new LocalizationResourceCacheItem(x.Name, x.DefaultCultureName) + { + IsEnabled = x.Enable, + }) + .ToList(); + + cacheItem = new LocalizationResourcesCacheItem(resourceItems); + + await ResourcesCache.SetAsync(LocalizationResourcesCacheItem.CacheKey, cacheItem); + } + + return cacheItem; + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextCacheItem.cs new file mode 100644 index 000000000..c4e219ba9 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextCacheItem.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("AbpExternalLocalizationTexts")] +public class ExternalLocalizationTextCacheItem +{ + private const string CacheKeyFormat = "r:{0},c:{1}"; + + public Dictionary Texts { get; set; } + public ExternalLocalizationTextCacheItem() + { + Texts = new Dictionary(); + } + public ExternalLocalizationTextCacheItem(Dictionary texts) + { + Texts = texts; + } + + public static string CalculateCacheKey(string resourceName, string cultureName) + { + return string.Format(CacheKeyFormat, resourceName, cultureName); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStampCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStampCacheItem.cs new file mode 100644 index 000000000..434063dad --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStampCacheItem.cs @@ -0,0 +1,29 @@ +using System; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +[Serializable] +[IgnoreMultiTenancy] +[CacheName("AbpExternalLocalizationTextsStamp")] +public class ExternalLocalizationTextStampCacheItem +{ + private const string CacheKeyFormat = "r:{0},c:{1}"; + public string Stamp { get; set; } + + public ExternalLocalizationTextStampCacheItem() + { + + } + + public ExternalLocalizationTextStampCacheItem(string stamp) + { + Stamp = stamp; + } + + public static string CalculateCacheKey(string resourceName, string cultureName) + { + return string.Format(CacheKeyFormat, resourceName, cultureName); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs new file mode 100644 index 000000000..1a216363f --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/ExternalLocalizationTextStoreCache.cs @@ -0,0 +1,143 @@ +using AsyncKeyedLock; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Localization; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public class ExternalLocalizationTextStoreCache : IExternalLocalizationTextStoreCache, ISingletonDependency +{ + protected AsyncKeyedLocker AsyncKeyedLocker; + protected ConcurrentDictionary MemoryCache { get; } + + protected IAbpDistributedLock DistributedLock { get; } + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected IDistributedCache DistributedCache { get; } + protected IDistributedCache StampCache { get; } + + public ExternalLocalizationTextStoreCache( + IAbpDistributedLock distributedLock, + IServiceScopeFactory serviceScopeFactory, + IDistributedCache distributedCache, + IDistributedCache stampCache) + { + DistributedLock = distributedLock; + ServiceScopeFactory = serviceScopeFactory; + DistributedCache = distributedCache; + StampCache = stampCache; + + AsyncKeyedLocker = new AsyncKeyedLocker(o => + { + o.PoolSize = 20; + o.PoolInitialFill = 1; + }); + MemoryCache = new ConcurrentDictionary(); + } + + public async virtual Task RemoveAsync(string resourceName, string cultureName) + { + var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resourceName, cultureName); + var stampCacheKey = ExternalLocalizationTextStampCacheItem.CalculateCacheKey(resourceName, cultureName); + + await using var lockHandle = await DistributedLock.TryAcquireAsync(cacheKey, TimeSpan.FromMinutes(1d)); + + await DistributedCache.RemoveAsync(cacheKey); + + await StampCache.SetAsync(stampCacheKey, new ExternalLocalizationTextStampCacheItem(Guid.NewGuid().ToString())); + } + + public Dictionary GetTexts(LocalizationResourceBase resource, string cultureName) + { + var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); + var memoryCacheItem = MemoryCache.GetOrDefault(cacheKey); + if (memoryCacheItem != null && !IsShouldCheck(memoryCacheItem)) + { + return memoryCacheItem.Texts; + } + + return new Dictionary(); + } + + public async virtual Task> GetTextsAsync(LocalizationResourceBase resource, string cultureName) + { + var cacheKey = ExternalLocalizationTextCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); + var memoryCacheItem = MemoryCache.GetOrDefault(cacheKey); + if (memoryCacheItem != null && !IsShouldCheck(memoryCacheItem)) + { + return memoryCacheItem.Texts; + } + + using (await AsyncKeyedLocker.LockAsync(cacheKey)) + { + memoryCacheItem = MemoryCache.GetOrDefault(cacheKey); + if (memoryCacheItem != null && !IsShouldCheck(memoryCacheItem)) + { + return memoryCacheItem.Texts; + } + + var stampCacheKey = ExternalLocalizationTextStampCacheItem.CalculateCacheKey(resource.ResourceName, cultureName); + var stampCacheItem = await StampCache.GetAsync(stampCacheKey); + if (memoryCacheItem != null && memoryCacheItem.CacheStamp == stampCacheItem.Stamp) + { + memoryCacheItem.LastCheckTime = DateTime.Now; + return memoryCacheItem.Texts; + } + + var distributeCacheItem = await DistributedCache.GetAsync(cacheKey); + if (distributeCacheItem != null) + { + MemoryCache[cacheKey] = new LocalizationTextMemoryCacheItem(distributeCacheItem.Texts, stampCacheItem.Stamp); + + return distributeCacheItem.Texts; + } + + await using var lockHandle = await DistributedLock.TryAcquireAsync(cacheKey, TimeSpan.FromMinutes(1d)); + + if (lockHandle == null) + { + return new Dictionary(); + } + + distributeCacheItem = await CreateCacheItemAsync(resource, cultureName); + + await DistributedCache.SetAsync(cacheKey, distributeCacheItem); + + stampCacheItem = new ExternalLocalizationTextStampCacheItem(Guid.NewGuid().ToString()); + await StampCache.SetAsync(stampCacheKey, stampCacheItem); + + MemoryCache[cacheKey] = new LocalizationTextMemoryCacheItem(distributeCacheItem.Texts, stampCacheItem.Stamp); + + return distributeCacheItem.Texts; + } + } + private static bool IsShouldCheck(LocalizationTextMemoryCacheItem memoryCacheItem) + { + return DateTime.Now.Subtract(memoryCacheItem.LastCheckTime).TotalSeconds >= 30.0; + } + + protected async virtual Task CreateCacheItemAsync(LocalizationResourceBase resource, string cultureName) + { + using var scope = ServiceScopeFactory.CreateScope(); + var unitOfWorkManager = scope.ServiceProvider.GetRequiredService(); + using var unitOfWork = unitOfWorkManager.Begin(requiresNew: true); + var repo = scope.ServiceProvider.GetRequiredService(); + + var texts = await repo.GetListAsync(resource.ResourceName, cultureName); + + var fillTexts = new Dictionary(); + + foreach (var text in texts) + { + fillTexts[text.Key] = text.Value; + } + + return new ExternalLocalizationTextCacheItem(fillTexts); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs new file mode 100644 index 000000000..cc3825d69 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationStoreCache.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public interface IExternalLocalizationStoreCache +{ + LocalizationResourceCacheItem GetResourceOrNull(string resourceName); + + Task GetResourceOrNullAsync(string resourceName); + + Task GetResourceNamesAsync(); + + Task GetResourcesAsync(); + + Task RemoveAsync(string resourceName); +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs new file mode 100644 index 000000000..3ad00d885 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/IExternalLocalizationTextStoreCache.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public interface IExternalLocalizationTextStoreCache +{ + Dictionary GetTexts(LocalizationResourceBase resource, string cultureName); + + Task> GetTextsAsync(LocalizationResourceBase resource, string cultureName); + + Task RemoveAsync(string resourceName, string cultureName); +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs new file mode 100644 index 000000000..cb8cbe422 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheInvalidator.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public class LocalizationResourceCacheInvalidator : + ILocalEventHandler>, + ITransientDependency +{ + private readonly IExternalLocalizationTextStoreCache _externalLocalizationTextStoreCache; + private readonly ILocalizationLanguageStoreCache _localizationLanguageStoreCache; + private readonly IExternalLocalizationStoreCache _externalLocalizationStoreCache; + public LocalizationResourceCacheInvalidator( + IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache, + ILocalizationLanguageStoreCache localizationLanguageStoreCache, + IExternalLocalizationStoreCache externalLocalizationStoreCache) + { + _externalLocalizationTextStoreCache = externalLocalizationTextStoreCache; + _localizationLanguageStoreCache = localizationLanguageStoreCache; + _externalLocalizationStoreCache = externalLocalizationStoreCache; + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await _externalLocalizationStoreCache.RemoveAsync(eventData.Entity.Name); +; + var languages = await _localizationLanguageStoreCache.GetLanguagesAsync(); + + foreach (var language in languages) + { + await _externalLocalizationTextStoreCache.RemoveAsync(eventData.Entity.Name, language.CultureName); + } + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs new file mode 100644 index 000000000..1bd160c3a --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourceCacheItem.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +[IgnoreMultiTenancy] +[CacheName("AbpExternalLocalizationResource")] +public class LocalizationResourceCacheItem +{ + public virtual string Name { get; set; } + + public virtual string DefaultCulture { get; set; } + + public virtual string[] BaseResources { get; set; } + + public virtual string[] SupportedCultures { get; set; } + + public bool IsEnabled { get; set; } + + public LocalizationResourceCacheItem( + string name, + string defaultCulture = null, + string[] baseResources = null, + string[] supportedCultures = null) + { + Name = name; + DefaultCulture = defaultCulture; + BaseResources = baseResources ?? Array.Empty(); + SupportedCultures = supportedCultures ?? Array.Empty(); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourcesCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourcesCacheItem.cs new file mode 100644 index 000000000..91bbf3c5f --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationResourcesCacheItem.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Caching; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +[IgnoreMultiTenancy] +[CacheName("AbpExternalLocalizationResources")] +public class LocalizationResourcesCacheItem +{ + public const string CacheKey = "All"; + + public List Resources { get; set; } + + public LocalizationResourcesCacheItem() + { + Resources = new List(); + } + + public LocalizationResourcesCacheItem(List resources) + { + Resources = resources; + } + + public LocalizationResourceCacheItem GetResourceOrNull(string name) + { + return Resources?.FirstOrDefault(x => x.Name == name); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationTextMemoryCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationTextMemoryCacheItem.cs new file mode 100644 index 000000000..58fd8fb85 --- /dev/null +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/External/LocalizationTextMemoryCacheItem.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.LocalizationManagement.External; + +public class LocalizationTextMemoryCacheItem +{ + private const string CacheKeyFormat = "r:{0},c:{1}"; + + public string CacheStamp { get; } + + public DateTime LastCheckTime { get; set; } + + public Dictionary Texts { get; set; } + + public LocalizationTextMemoryCacheItem() + { + Texts = new Dictionary(); + } + public LocalizationTextMemoryCacheItem(Dictionary texts, string cacheStamp) + { + Texts = texts; + CacheStamp = cacheStamp; + LastCheckTime = DateTime.Now; + } + + public static string CalculateCacheKey(string resourceName, string cultureName) + { + return string.Format(CacheKeyFormat, resourceName, cultureName); + } +} diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs index 7bd96a387..29a82b9dc 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/IResourceRepository.cs @@ -11,6 +11,8 @@ public interface IResourceRepository : IRepository string name, CancellationToken cancellationToken = default); + Resource FindByName(string name); + Task FindByNameAsync( string name, CancellationToken cancellationToken = default); diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheItem.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheItem.cs index f2b25862c..3c19db655 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheItem.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationLanguageCacheItem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Volo.Abp.Caching; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; @@ -7,9 +8,10 @@ namespace LINGYUN.Abp.LocalizationManagement; [Serializable] [IgnoreMultiTenancy] +[CacheName("AbpLocalizationLanguages")] public class LocalizationLanguageCacheItem { - internal const string CacheKey = "Abp.Localization.Languages"; + public const string CacheKey = "All"; public List Languages { get; set; } public LocalizationLanguageCacheItem() diff --git a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs index 4ca3bb4ea..5d845e4f8 100644 --- a/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs +++ b/aspnet-core/modules/localization-management/LINGYUN.Abp.LocalizationManagement.Domain/LINGYUN/Abp/LocalizationManagement/LocalizationTextCacheInvalidator.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using LINGYUN.Abp.LocalizationManagement.External; +using System.Threading.Tasks; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events; @@ -9,8 +10,12 @@ namespace LINGYUN.Abp.LocalizationManagement; public class LocalizationTextCacheInvalidator : ILocalEventHandler>, ITransientDependency { private readonly IDistributedCache _localizationTextCache; - public LocalizationTextCacheInvalidator(IDistributedCache localizationTextCache) + private readonly IExternalLocalizationTextStoreCache _externalLocalizationTextStoreCache; + public LocalizationTextCacheInvalidator( + IDistributedCache localizationTextCache, + IExternalLocalizationTextStoreCache externalLocalizationTextStoreCache) { + _externalLocalizationTextStoreCache = externalLocalizationTextStoreCache; _localizationTextCache = localizationTextCache; } @@ -21,5 +26,7 @@ public class LocalizationTextCacheInvalidator : ILocalEventHandler x.Name.Equals(name)); } + [Obsolete("Use FindAsync() method.")] + public virtual Resource FindByName(string name) + { + using (Volo.Abp.Uow.UnitOfWorkManager.DisableObsoleteDbContextCreationWarning.SetScoped(true)) + { + return DbSet.FirstOrDefault(localizationResourceRecord => localizationResourceRecord.Name == name); + } + } + public async virtual Task FindByNameAsync( string name, CancellationToken cancellationToken = default)