From f54c10c8a5abfb993ad328c4a95beb7dfc06d80b Mon Sep 17 00:00:00 2001 From: wwwk <1265346495@qq.com> Date: Tue, 5 Apr 2022 23:06:31 +0800 Subject: [PATCH] LocalizationDynamic And Localization Management --- Sanhe.Abp.Framework.sln | 65 ++++++++- .../Redis/RedisRequiresLimitFeatureChecker.cs | 4 +- .../FodyWeavers.xml | 3 + .../Sanhe.Abp.Localization.Dynamic/README.md | 38 +++++ .../Sanhe.Abp.Localization.Dynamic.csproj | 15 ++ .../Dynamic/AbpLocalizationDynamicModule.cs | 17 +++ .../Dynamic/AbpLocalizationDynamicOptions.cs | 22 +++ .../Dynamic/DefaultLocalizationStore.cs | 30 ++++ .../Dynamic/DynamicLanguageProvider.cs | 41 ++++++ .../DynamicLocalizationInitializeService.cs | 47 +++++++ .../DynamicLocalizationResourceContributor.cs | 40 ++++++ .../Dynamic/ILocalizationStore.cs | 37 +++++ .../Dynamic/LanguageInfoComparer.cs | 22 +++ .../Dynamic/LocalizationCacheItem.cs | 58 ++++++++ .../Dynamic/LocalizationDictionary.cs | 12 ++ .../Dynamic/LocalizationResetSynchronizer.cs | 75 ++++++++++ .../LocalizedStringCacheResetEventData.cs | 44 ++++++ ...ocalizationResourceDictionaryExtensions.cs | 42 ++++++ .../LocalizationResourceExtensions.cs | 20 +++ modules/localization-management/README.md | 39 ++++++ .../FodyWeavers.xml | 3 + ...ionManagement.Application.Contracts.csproj | 20 +++ ...ionManagementApplicationContractsModule.cs | 12 ++ .../CreateOrUpdateLanguageInput.cs | 24 ++++ .../CreateOrUpdateResourceInput.cs | 19 +++ .../CreateOrUpdateTextInput.cs | 9 ++ .../LocalizationManagement/CreateTextInput.cs | 19 +++ .../GetLanguagesInput.cs | 8 ++ .../GetResourcesInput.cs | 8 ++ .../GetTextByKeyInput.cs | 19 +++ .../LocalizationManagement/GetTextsInput.cs | 23 +++ .../ILanguageAppService.cs | 17 +++ .../IResourceAppService.cs | 17 +++ .../LocalizationManagement/ITextAppService.cs | 16 +++ .../Abp/LocalizationManagement/LanguageDto.cs | 13 ++ .../LocalizationRemoteServiceConsts.cs | 6 + ...nManagementPermissionDefinitionProvider.cs | 72 ++++++++++ .../LocalizationManagementPermissions.cs | 39 ++++++ .../Abp/LocalizationManagement/ResourceDto.cs | 12 ++ .../TextDifferenceDto.cs | 13 ++ .../Abp/LocalizationManagement/TextDto.cs | 11 ++ .../LocalizationManagement/UpdateTextInput.cs | 5 + .../FodyWeavers.xml | 3 + ....LocalizationManagement.Application.csproj | 20 +++ ...LocalizationManagementApplicationModule.cs | 23 +++ .../LanguageAppService.cs | 70 ++++++++++ ...ationManagementApplicationMapperProfile.cs | 14 ++ .../ResourceAppService.cs | 75 ++++++++++ .../LocalizationManagement/TextAppService.cs | 71 ++++++++++ .../FodyWeavers.xml | 3 + ...ocalizationManagement.Domain.Shared.csproj | 25 ++++ ...ocalizationManagementDomainSharedModule.cs | 29 ++++ .../LocalizationManagement/LanguageConsts.cs | 10 ++ .../LocalizationManagementResource.cs | 8 ++ .../Localization/Resources/en.json | 45 ++++++ .../Localization/Resources/zh-Hans.json | 45 ++++++ .../LocalizationManagement/ResourceConsts.cs | 9 ++ .../Abp/LocalizationManagement/TextConsts.cs | 8 ++ .../LocalizationManagement/TextDifference.cs | 37 +++++ .../Abp/LocalizationManagement/TextEto.cs | 22 +++ .../FodyWeavers.xml | 3 + ...e.Abp.LocalizationManagement.Domain.csproj | 20 +++ .../AbpLocalizationManagementDomainModule.cs | 41 ++++++ .../ILanguageRepository.cs | 14 ++ .../IResourceRepository.cs | 17 +++ .../LocalizationManagement/ITextRepository.cs | 43 ++++++ .../Abp/LocalizationManagement/Language.cs | 53 +++++++ .../LocalizationDbProperties.cs | 10 ++ ...calizationManagementDomainMapperProfile.cs | 11 ++ .../LocalizationStore.cs | 85 +++++++++++ .../LocalizationSynchronizer.cs | 52 +++++++ .../Abp/LocalizationManagement/Resource.cs | 29 ++++ .../Sanhe/Abp/LocalizationManagement/Text.cs | 36 +++++ .../FodyWeavers.xml | 3 + ...ationManagement.EntityFrameworkCore.csproj | 19 +++ ...tionManagementEntityFrameworkCoreModule.cs | 23 +++ .../EfCoreLanguageRepository.cs | 32 +++++ .../EfCoreResourceRepository.cs | 31 ++++ .../EfCoreTextRepository.cs | 132 ++++++++++++++++++ .../ILocalizationDbContext.cs | 13 ++ .../LocalizationDbContext.cs | 25 ++++ ...lizationDbContextModelBuilderExtensions.cs | 98 +++++++++++++ ...izationModelBuilderConfigurationOptions.cs | 17 +++ .../FodyWeavers.xml | 3 + ....Abp.LocalizationManagement.HttpApi.csproj | 19 +++ .../AbpLocalizationManagementHttpApiModule.cs | 41 ++++++ .../LanguageController.cs | 61 ++++++++ .../ResourceController.cs | 61 ++++++++ .../LocalizationManagement/TextController.cs | 60 ++++++++ .../AbpExceptionPageWrapResultFilter.cs | 6 +- .../AbpExceptionWrapResultFilter.cs | 6 +- .../Wrapper/Filters/AbpWrapResultFilter.cs | 6 +- .../Data/IdentityServerDataSeedContributor.cs | 6 +- .../Localization/BookStoreResource.cs | 2 +- 94 files changed, 2631 insertions(+), 20 deletions(-) create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/FodyWeavers.xml create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/README.md create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe.Abp.Localization.Dynamic.csproj create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DefaultLocalizationStore.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLanguageProvider.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/ILocalizationStore.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LanguageInfoComparer.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationCacheItem.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationDictionary.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizedStringCacheResetEventData.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceDictionaryExtensions.cs create mode 100644 modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceExtensions.cs create mode 100644 modules/localization-management/README.md create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationContractsModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateLanguageInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateResourceInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateTextInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateTextInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetLanguagesInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetResourcesInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextByKeyInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextsInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ILanguageAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/IResourceAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ITextAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LanguageDto.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LocalizationRemoteServiceConsts.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissions.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ResourceDto.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDifferenceDto.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDto.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/UpdateTextInput.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe.Abp.LocalizationManagement.Application.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LanguageAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LocalizationManagementApplicationMapperProfile.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/ResourceAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/TextAppService.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/LanguageConsts.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/LocalizationManagementResource.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/en.json create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/ResourceConsts.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextConsts.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextDifference.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextEto.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe.Abp.LocalizationManagement.Domain.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ILanguageRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/IResourceRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ITextRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Language.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationDbProperties.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationManagementDomainMapperProfile.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationStore.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationSynchronizer.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Resource.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Text.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/AbpLocalizationManagementEntityFrameworkCoreModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreLanguageRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreTextRepository.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/ILocalizationDbContext.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContext.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContextModelBuilderExtensions.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationModelBuilderConfigurationOptions.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/FodyWeavers.xml create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe.Abp.LocalizationManagement.HttpApi.csproj create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementHttpApiModule.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/LanguageController.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/ResourceController.cs create mode 100644 modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/TextController.cs diff --git a/Sanhe.Abp.Framework.sln b/Sanhe.Abp.Framework.sln index 3758ae4..b0e7351 100644 --- a/Sanhe.Abp.Framework.sln +++ b/Sanhe.Abp.Framework.sln @@ -21,21 +21,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "book-store", "book-store", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BookStore", "services\book-store\BookStore.csproj", "{64178F61-A488-4182-A409-C32AE51E33A1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.ExceptionHandling", "modules\common\Sanhe.Abp.ExceptionHandling\Sanhe.Abp.ExceptionHandling.csproj", "{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.ExceptionHandling", "modules\common\Sanhe.Abp.ExceptionHandling\Sanhe.Abp.ExceptionHandling.csproj", "{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.ExceptionHandling.Emailing", "modules\common\Sanhe.Abp.ExceptionHandling.Emailing\Sanhe.Abp.ExceptionHandling.Emailing.csproj", "{0692C2EA-7119-4065-8504-D7FDA70135A9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.ExceptionHandling.Emailing", "modules\common\Sanhe.Abp.ExceptionHandling.Emailing\Sanhe.Abp.ExceptionHandling.Emailing.csproj", "{0692C2EA-7119-4065-8504-D7FDA70135A9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Features.LimitValidation", "modules\common\Sanhe.Abp.Features.LimitValidation\Sanhe.Abp.Features.LimitValidation.csproj", "{BE246DD7-2DDB-4064-9017-7E1DD2E67195}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Features.LimitValidation", "modules\common\Sanhe.Abp.Features.LimitValidation\Sanhe.Abp.Features.LimitValidation.csproj", "{BE246DD7-2DDB-4064-9017-7E1DD2E67195}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Features.LimitValidation.Redis", "modules\common\Sanhe.Abp.Features.LimitValidation.Redis\Sanhe.Abp.Features.LimitValidation.Redis.csproj", "{A2BD1C66-505E-48BB-A356-38D74AA3AE0F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Features.LimitValidation.Redis", "modules\common\Sanhe.Abp.Features.LimitValidation.Redis\Sanhe.Abp.Features.LimitValidation.Redis.csproj", "{A2BD1C66-505E-48BB-A356-38D74AA3AE0F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Features.LimitValidation.Redis.Client", "modules\common\Sanhe.Abp.Features.LimitValidation.Redis.Client\Sanhe.Abp.Features.LimitValidation.Redis.Client.csproj", "{97DDB479-946C-489D-9089-6EAEBFEE97C6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sanhe.Abp.Features.LimitValidation.Redis.Client", "modules\common\Sanhe.Abp.Features.LimitValidation.Redis.Client\Sanhe.Abp.Features.LimitValidation.Redis.Client.csproj", "{97DDB479-946C-489D-9089-6EAEBFEE97C6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution items", "{8DAEBF3C-8948-44EF-AB7C-8662CCACD2C6}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.Localization.Dynamic", "modules\common\Sanhe.Abp.Localization.Dynamic\Sanhe.Abp.Localization.Dynamic.csproj", "{4006EECE-A268-4B46-AA4B-743AFB82A1EC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization-management", "localization-management", "{13AA8858-C832-4AAD-8B7D-C8AF879F39A7}" + ProjectSection(SolutionItems) = preProject + modules\localization-management\README.md = modules\localization-management\README.md + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.Application", "modules\localization-management\Sanhe.Abp.LocalizationManagement.Application\Sanhe.Abp.LocalizationManagement.Application.csproj", "{B76B1A6D-D756-40ED-BD87-AD8B319D708C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.Domain.Shared", "modules\localization-management\Sanhe.Abp.LocalizationManagement.Domain.Shared\Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj", "{B6293F8F-5B03-49A0-94A5-0D6778201AAD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.Domain", "modules\localization-management\Sanhe.Abp.LocalizationManagement.Domain\Sanhe.Abp.LocalizationManagement.Domain.csproj", "{F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.Application.Contracts", "modules\localization-management\Sanhe.Abp.LocalizationManagement.Application.Contracts\Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj", "{53D8962F-E349-405D-831A-5E35B099F03B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.EntityFrameworkCore", "modules\localization-management\Sanhe.Abp.LocalizationManagement.EntityFrameworkCore\Sanhe.Abp.LocalizationManagement.EntityFrameworkCore.csproj", "{E727B749-D1CA-44CA-BD86-D553A05C444F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.LocalizationManagement.HttpApi", "modules\localization-management\Sanhe.Abp.LocalizationManagement.HttpApi\Sanhe.Abp.LocalizationManagement.HttpApi.csproj", "{50B3735E-750E-483F-9A9B-F4CAE1657390}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -74,6 +93,34 @@ Global {97DDB479-946C-489D-9089-6EAEBFEE97C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {97DDB479-946C-489D-9089-6EAEBFEE97C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {97DDB479-946C-489D-9089-6EAEBFEE97C6}.Release|Any CPU.Build.0 = Release|Any CPU + {4006EECE-A268-4B46-AA4B-743AFB82A1EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4006EECE-A268-4B46-AA4B-743AFB82A1EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4006EECE-A268-4B46-AA4B-743AFB82A1EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4006EECE-A268-4B46-AA4B-743AFB82A1EC}.Release|Any CPU.Build.0 = Release|Any CPU + {B76B1A6D-D756-40ED-BD87-AD8B319D708C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B76B1A6D-D756-40ED-BD87-AD8B319D708C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B76B1A6D-D756-40ED-BD87-AD8B319D708C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B76B1A6D-D756-40ED-BD87-AD8B319D708C}.Release|Any CPU.Build.0 = Release|Any CPU + {B6293F8F-5B03-49A0-94A5-0D6778201AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6293F8F-5B03-49A0-94A5-0D6778201AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6293F8F-5B03-49A0-94A5-0D6778201AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6293F8F-5B03-49A0-94A5-0D6778201AAD}.Release|Any CPU.Build.0 = Release|Any CPU + {F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1}.Release|Any CPU.Build.0 = Release|Any CPU + {53D8962F-E349-405D-831A-5E35B099F03B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53D8962F-E349-405D-831A-5E35B099F03B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53D8962F-E349-405D-831A-5E35B099F03B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53D8962F-E349-405D-831A-5E35B099F03B}.Release|Any CPU.Build.0 = Release|Any CPU + {E727B749-D1CA-44CA-BD86-D553A05C444F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E727B749-D1CA-44CA-BD86-D553A05C444F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E727B749-D1CA-44CA-BD86-D553A05C444F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E727B749-D1CA-44CA-BD86-D553A05C444F}.Release|Any CPU.Build.0 = Release|Any CPU + {50B3735E-750E-483F-9A9B-F4CAE1657390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50B3735E-750E-483F-9A9B-F4CAE1657390}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50B3735E-750E-483F-9A9B-F4CAE1657390}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50B3735E-750E-483F-9A9B-F4CAE1657390}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -91,6 +138,14 @@ Global {BE246DD7-2DDB-4064-9017-7E1DD2E67195} = {2A768109-31B7-4C52-928C-3023DAB9F254} {A2BD1C66-505E-48BB-A356-38D74AA3AE0F} = {2A768109-31B7-4C52-928C-3023DAB9F254} {97DDB479-946C-489D-9089-6EAEBFEE97C6} = {2A768109-31B7-4C52-928C-3023DAB9F254} + {4006EECE-A268-4B46-AA4B-743AFB82A1EC} = {2A768109-31B7-4C52-928C-3023DAB9F254} + {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} = {F5F5D604-531B-4B57-A88E-C9C5CEEC55D7} + {B76B1A6D-D756-40ED-BD87-AD8B319D708C} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} + {B6293F8F-5B03-49A0-94A5-0D6778201AAD} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} + {F7514BD9-2BC7-4FF1-A79A-EC5C161C2AC1} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} + {53D8962F-E349-405D-831A-5E35B099F03B} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} + {E727B749-D1CA-44CA-BD86-D553A05C444F} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} + {50B3735E-750E-483F-9A9B-F4CAE1657390} = {13AA8858-C832-4AAD-8B7D-C8AF879F39A7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB69BFDE-9DDB-4D16-8CB8-72472C0319CD} diff --git a/modules/common/Sanhe.Abp.Features.LimitValidation.Redis/Sanhe/Abp/Features/LimitValidation/Redis/RedisRequiresLimitFeatureChecker.cs b/modules/common/Sanhe.Abp.Features.LimitValidation.Redis/Sanhe/Abp/Features/LimitValidation/Redis/RedisRequiresLimitFeatureChecker.cs index 11a050e..3ebd8ce 100644 --- a/modules/common/Sanhe.Abp.Features.LimitValidation.Redis/Sanhe/Abp/Features/LimitValidation/Redis/RedisRequiresLimitFeatureChecker.cs +++ b/modules/common/Sanhe.Abp.Features.LimitValidation.Redis/Sanhe/Abp/Features/LimitValidation/Redis/RedisRequiresLimitFeatureChecker.cs @@ -63,7 +63,7 @@ public class RedisRequiresLimitFeatureChecker : IRequiresLimitFeatureChecker public virtual async Task ProcessAsync(RequiresLimitFeatureContext context, CancellationToken cancellation = default) { await ConnectAsync(cancellation); - + await EvaluateAsync(PROCESS_LUA_SCRIPT, context, cancellation); } @@ -83,7 +83,7 @@ public class RedisRequiresLimitFeatureChecker : IRequiresLimitFeatureChecker var keys = new RedisKey[1] { NormalizeKey(context) }; var values = new RedisValue[] { context.GetEffectTicks() }; var result = await _redis.ScriptEvaluateAsync(luaSha1, keys, values); - + if (result.Type == ResultType.Error) { throw new AbpException($"Script evaluate error: {result}"); diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/FodyWeavers.xml b/modules/common/Sanhe.Abp.Localization.Dynamic/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/README.md b/modules/common/Sanhe.Abp.Localization.Dynamic/README.md new file mode 100644 index 0000000..b6e6578 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/README.md @@ -0,0 +1,38 @@ +# Sanhe.Abp.Localization.Dynamic + +动态本地化提供者组件,添加动态提供者可实现运行时替换本地化文本 + +需要实现 ILocalizationStore 接口 + +LocalizationManagement项目提供支持 + +## 配置使用 + +```csharp +[DependsOn(typeof(AbpLocalizationDynamicModule))] +public class YouProjectModule : AbpModule +{ + // other + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Resources + .Get() + .AddDynamic(); // 添加动态本地化文档支持 + + // 添加所有资源的动态文档支持,将监听所有的资源包文档变更事件 + // options.Resources.AddDynamic(); + + // 添加所有资源的动态文档支持,忽略 IdentityResource 资源 + // options.Resources.AddDynamic(typeof(IdentityResource)); + }); + } +} +``` + +## 注意事项 + +动态资源在启动时加载,如果通过LocalizationManagement模块查询,可能受后端存储资源体量影响整体启动时间 + +详情见: [DynamicLocalizationInitializeService](./Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs#L25-L38) \ No newline at end of file diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe.Abp.Localization.Dynamic.csproj b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe.Abp.Localization.Dynamic.csproj new file mode 100644 index 0000000..5cc3eed --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe.Abp.Localization.Dynamic.csproj @@ -0,0 +1,15 @@ + + + + + + + netstandard2.0 + + + + + + + + diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs new file mode 100644 index 0000000..b90591e --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicModule.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EventBus; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.Localization.Dynamic; + +[DependsOn( + typeof(AbpEventBusModule), + typeof(AbpLocalizationModule))] +public class AbpLocalizationDynamicModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddHostedService(); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs new file mode 100644 index 0000000..4221c3a --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/AbpLocalizationDynamicOptions.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public class AbpLocalizationDynamicOptions +{ + internal LocalizationDictionary LocalizationDictionary { get; } + + public AbpLocalizationDynamicOptions() + { + LocalizationDictionary = new LocalizationDictionary(); + } + + internal void AddOrUpdate(string resourceName, Dictionary dictionaries) + { + var currentDictionaries = LocalizationDictionary + .GetOrAdd(resourceName, () => new Dictionary()); + + currentDictionaries.AddIfNotContains(dictionaries); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DefaultLocalizationStore.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DefaultLocalizationStore.cs new file mode 100644 index 0000000..a084978 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DefaultLocalizationStore.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public class DefaultLocalizationStore : ILocalizationStore, ITransientDependency +{ + public DefaultLocalizationStore() + { + + } + + public Task> GetLanguageListAsync(CancellationToken cancellationToken = default) + { + return Task.FromResult(new List()); + } + + public Task> GetLocalizationDictionaryAsync(string resourceName, CancellationToken cancellationToken = default) + { + return Task.FromResult(new Dictionary()); + } + + public Task ResourceExistsAsync(string resourceName, CancellationToken cancellationToken = default) + { + return Task.FromResult(false); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLanguageProvider.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLanguageProvider.cs new file mode 100644 index 0000000..eec37ff --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLanguageProvider.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +[Dependency(ServiceLifetime.Transient, ReplaceServices = true)] +[ExposeServices( + typeof(ILanguageProvider), + typeof(DynamicLanguageProvider))] +public class DynamicLanguageProvider : ILanguageProvider +{ + protected ILocalizationStore Store { get; } + protected AbpLocalizationOptions Options { get; } + + public DynamicLanguageProvider( + ILocalizationStore store, + IOptions options) + { + Store = store; + Options = options.Value; + } + + public async virtual Task> GetLanguagesAsync() + { + var languages = await Store.GetLanguageListAsync(); + + if (!languages.Any()) + { + return Options.Languages; + } + + return languages + .Distinct(new LanguageInfoComparer()) + .ToList(); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs new file mode 100644 index 0000000..adde6d7 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs @@ -0,0 +1,47 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public class DynamicLocalizationInitializeService : BackgroundService +{ + protected ILocalizationStore Store { get; } + protected AbpLocalizationOptions LocalizationOptions { get; } + protected AbpLocalizationDynamicOptions DynamicOptions { get; } + + public DynamicLocalizationInitializeService( + ILocalizationStore store, + IOptions localizationOptions, + IOptions dynamicOptions) + { + Store = store; + DynamicOptions = dynamicOptions.Value; + LocalizationOptions = localizationOptions.Value; + } + + protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + try + { + foreach (var resource in LocalizationOptions.Resources) + { + foreach (var contributor in resource.Value.Contributors) + { + if (contributor.GetType().IsAssignableFrom(typeof(DynamicLocalizationResourceContributor))) + { + var resourceLocalizationDict = await Store + .GetLocalizationDictionaryAsync( + resource.Value.ResourceName, + stoppingToken); + DynamicOptions.AddOrUpdate(resource.Value.ResourceName, resourceLocalizationDict); + } + } + } + } + catch (OperationCanceledException) { } // 忽略此异常 + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs new file mode 100644 index 0000000..bed5798 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor +{ + private readonly string _resourceName; + + private AbpLocalizationDynamicOptions _options; + + public DynamicLocalizationResourceContributor(string resourceName) + { + _resourceName = resourceName; + } + + public virtual void Initialize(LocalizationResourceInitializationContext context) + { + _options = context.ServiceProvider.GetService>().Value; + } + + public virtual void Fill(string cultureName, Dictionary dictionary) + { + GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); + } + + public virtual LocalizedString GetOrNull(string cultureName, string name) + { + return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); + } + + protected virtual Dictionary GetDictionaries() + { + return _options.LocalizationDictionary + .GetOrAdd(_resourceName, () => new Dictionary()); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/ILocalizationStore.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/ILocalizationStore.cs new file mode 100644 index 0000000..4da2e20 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/ILocalizationStore.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public interface ILocalizationStore +{ + /// + /// 获取语言列表 + /// + /// + /// + Task> GetLanguageListAsync( + CancellationToken cancellationToken = default); + + /// + /// 资源是否存在 + /// + /// 资源名称 + /// + /// + Task ResourceExistsAsync( + string resourceName, + CancellationToken cancellationToken = default); + + /// + /// 获取当前资源下的本地化字典 + /// + /// 资源名称 + /// + /// + Task> GetLocalizationDictionaryAsync( + string resourceName, + CancellationToken cancellationToken = default); +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LanguageInfoComparer.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LanguageInfoComparer.cs new file mode 100644 index 0000000..bec37b2 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LanguageInfoComparer.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +public class LanguageInfoComparer : IEqualityComparer +{ + public bool Equals(LanguageInfo x, LanguageInfo y) + { + if (x == null || y == null) + { + return false; + } + + return x.CultureName.Equals(y.CultureName); + } + + public int GetHashCode(LanguageInfo obj) + { + return obj?.CultureName.GetHashCode() ?? GetHashCode(); + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationCacheItem.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationCacheItem.cs new file mode 100644 index 0000000..d1eb0fb --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationCacheItem.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; + +namespace Sanhe.Abp.Localization.Dynamic; + +/// +/// 本地化缓存项 +/// +public class LocalizationCacheItem +{ + public string Resource { get; set; } + + public string Culture { get; set; } + + public List Texts { get; set; } + + public LocalizationCacheItem() + { + Texts = new List(); + } + + public LocalizationCacheItem( + string resource, + string culture, + List texts) + { + Resource = resource; + Culture = culture; + Texts = texts; + } + + public static string NormalizeKey( + string resource, + string culture) + { + return $"p:Localization,r:{resource},c:{culture}"; + } +} + +public class LocalizationText +{ + public string Key { get; set; } + + public string Value { get; set; } + + public LocalizationText() + { + + } + + public LocalizationText( + string key, + string value) + { + Key = key; + Value = value; + } + +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationDictionary.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationDictionary.cs new file mode 100644 index 0000000..2ad00de --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationDictionary.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic; + +/// +/// 用于查找本地化字符串的字典。 +/// +public class LocalizationDictionary : Dictionary> +{ + +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs new file mode 100644 index 0000000..2ead2bf --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizationResetSynchronizer.cs @@ -0,0 +1,75 @@ +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.Localization.Dynamic +{ + internal class LocalizationResetSynchronizer : + IDistributedEventHandler, + ITransientDependency + { + private readonly AbpLocalizationDynamicOptions _options; + + public LocalizationResetSynchronizer( + IOptions options) + { + _options = options.Value; + } + + public virtual Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) + { + var dictionaries = GetDictionaries(eventData.ResourceName); + + if (!dictionaries.ContainsKey(eventData.CultureName)) + { + // TODO: 需要处理 data.Key data.Value 空引用 + var dictionary = new Dictionary(); + dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); + + var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); + + dictionaries.Add(eventData.CultureName, newLocalizationDictionary); + } + else + { + // 取出当前的缓存写入到新字典进行处理 + var nowLocalizationDictionary = dictionaries[eventData.CultureName]; + var dictionary = new Dictionary(); + nowLocalizationDictionary.Fill(dictionary); + + var existsKey = dictionary.ContainsKey(eventData.Key); + if (!existsKey) + { + // 如果不存在,则新增 + dictionary.Add(eventData.Key, new LocalizedString(eventData.Key, eventData.Value.NormalizeLineEndings())); + } + else if (existsKey && eventData.IsDeleted) + { + // 如果删掉了本地化的节点,删掉当前的缓存 + dictionary.Remove(eventData.Key); + } + + var newLocalizationDictionary = new StaticLocalizationDictionary(eventData.CultureName, dictionary); + + if (newLocalizationDictionary != null) + { + // 重新赋值变更过的缓存 + dictionaries[eventData.CultureName] = newLocalizationDictionary; + } + } + + return Task.CompletedTask; + } + + protected virtual Dictionary GetDictionaries(string resourceName) + { + return _options.LocalizationDictionary + .GetOrAdd(resourceName, () => new Dictionary()); + } + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizedStringCacheResetEventData.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizedStringCacheResetEventData.cs new file mode 100644 index 0000000..2c4357f --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Sanhe/Abp/Localization/Dynamic/LocalizedStringCacheResetEventData.cs @@ -0,0 +1,44 @@ +namespace Sanhe.Abp.Localization.Dynamic; + +public class LocalizedStringCacheResetEventData +{ + /// + /// 是否删除 + /// + public bool IsDeleted { get; set; } + /// + /// 资源名 + /// + public string ResourceName { get; set; } + /// + /// 文化名称 + /// + public string CultureName { get; set; } + /// + /// 键 + /// + public string Key { get; set; } + /// + /// 值 + /// + public string Value { get; set; } + + public LocalizedStringCacheResetEventData() + { + + } + + public LocalizedStringCacheResetEventData( + string resourceName, + string cultureName, + string key, + string value) + { + ResourceName = resourceName; + CultureName = cultureName; + Key = key; + Value = value; + + IsDeleted = false; + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceDictionaryExtensions.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceDictionaryExtensions.cs new file mode 100644 index 0000000..a12c2af --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceDictionaryExtensions.cs @@ -0,0 +1,42 @@ +using Sanhe.Abp.Localization.Dynamic; +using System; +using System.Linq; + +namespace Volo.Abp.Localization +{ + public static class LocalizationResourceDictionaryExtensions + { + public static LocalizationResourceDictionary AddDynamic( + this LocalizationResourceDictionary resources, + params Type[] ignoreResourceTypes) + { + foreach (var resource in resources) + { + if (ShouldIgnoreType(resource.Key, ignoreResourceTypes)) + { + continue; + } + if (ShouldIgnoreType(resource.Value)) + { + continue; + } + resource.Value.AddDynamic(); + } + return resources; + } + + private static bool ShouldIgnoreType(Type resourceType, params Type[] ignoreResourceTypes) + { + if (ignoreResourceTypes == null) + { + return false; + } + return ignoreResourceTypes.Any(x => x == resourceType); + } + + private static bool ShouldIgnoreType(LocalizationResource resource) + { + return resource.Contributors.Exists(x => x is DynamicLocalizationResourceContributor); + } + } +} diff --git a/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceExtensions.cs b/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceExtensions.cs new file mode 100644 index 0000000..83b7cb7 --- /dev/null +++ b/modules/common/Sanhe.Abp.Localization.Dynamic/Volo/Abp/Localization/LocalizationResourceExtensions.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; +using Sanhe.Abp.Localization.Dynamic; + +namespace Volo.Abp.Localization +{ + public static class DynamicLocalizationResourceExtensions + { + public static LocalizationResource AddDynamic( + [NotNull] this LocalizationResource localizationResource) + { + Check.NotNull(localizationResource, nameof(localizationResource)); + + localizationResource.Contributors.Add( + new DynamicLocalizationResourceContributor( + localizationResource.ResourceName)); + + return localizationResource; + } + } +} diff --git a/modules/localization-management/README.md b/modules/localization-management/README.md new file mode 100644 index 0000000..d29f0fd --- /dev/null +++ b/modules/localization-management/README.md @@ -0,0 +1,39 @@ +# Localization Management + +本地化文档管理模块,因项目路径太长Windows系统不支持,项目目录取简称 lt + +## 模块说明 + +### 基础模块 + +* [Sanhe.Abp.Localization.Dynamic](../common/Sanhe.Abp.Localization.Dynamic/Sanhe.Abp.Localization.Dynamic) 本地化扩展模块,增加 DynamicLocalizationResourceContributor 通过 ILocalizationStore 接口获取动态的本地化资源信息 +* [Sanhe.Abp.LocalizationManagement.Domain.Shared](./Sanhe.Abp.LocalizationManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 +* [Sanhe.Abp.LocalizationManagement.Domain](./Sanhe.Abp.LocalizationManagement.Domain) 领域层模块,实现 ILocalizationStore 接口 +* [Sanhe.Abp.LocalizationManagement.EntityFrameworkCore](./Sanhe.Abp.LocalizationManagement.EntityFrameworkCore) 数据访问层模块,集成EfCore +* [Sanhe.Abp.LocalizationManagement.Application.Contracts](./Sanhe.Abp.LocalizationManagement.Application.Contracts) 应用服务层公共模块,定义了管理本地化对象的外部接口、权限、功能限制策略 +* [Sanhe.Abp.LocalizationManagement.Application](./Sanhe.Abp.LocalizationManagement.Application) 应用服务层实现,实现了本地化对象管理接口 +* [Sanhe.Abp.LocalizationManagement.HttpApi](./Sanhe.Abp.LocalizationManagement.HttpApi) RestApi实现,实现了独立的对外RestApi接口 + +### 高阶模块 + +### 权限定义 + +* LocalizationManagement.Resource 授权对象是否允许访问资源 +* LocalizationManagement.Resource.Create 授权对象是否允许创建资源 +* LocalizationManagement.Resource.Update 授权对象是否允许修改资源 +* LocalizationManagement.Resource.Delete 授权对象是否允许删除资源 +* LocalizationManagement.Language 授权对象是否允许访问语言 +* LocalizationManagement.Language.Create 授权对象是否允许创建语言 +* LocalizationManagement.Language.Update 授权对象是否允许修改语言 +* LocalizationManagement.Language.Delete 授权对象是否允许删除语言 +* LocalizationManagement.Text 授权对象是否允许访问文档 +* LocalizationManagement.Text.Create 授权对象是否允许创建文档 +* LocalizationManagement.Text.Update 授权对象是否允许删除Oss对象 +* LocalizationManagement.Text.Delete 授权对象是否允许下载Oss对象 + +### 功能定义 + +### 配置定义 + +## 更新日志 + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj new file mode 100644 index 0000000..9ed7d9a --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationContractsModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationContractsModule.cs new file mode 100644 index 0000000..035e453 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationContractsModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Authorization; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.LocalizationManagement; + +[DependsOn( + typeof(AbpAuthorizationModule), + typeof(AbpLocalizationManagementDomainSharedModule))] +public class AbpLocalizationManagementApplicationContractsModule : AbpModule +{ + +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateLanguageInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateLanguageInput.cs new file mode 100644 index 0000000..cb01781 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateLanguageInput.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class CreateOrUpdateLanguageInput +{ + public virtual bool Enable { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxCultureNameLength))] + public string CultureName { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxUiCultureNameLength))] + public string UiCultureName { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxFlagIconLength))] + public string FlagIcon { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateResourceInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateResourceInput.cs new file mode 100644 index 0000000..9986fb1 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateResourceInput.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class CreateOrUpdateResourceInput +{ + public bool Enable { get; set; } + + [Required] + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxNameLength))] + public string Name { get; set; } + + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxDisplayNameLength))] + public string DisplayName { get; set; } + + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxDescriptionLength))] + public string Description { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateTextInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateTextInput.cs new file mode 100644 index 0000000..86fd36d --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateOrUpdateTextInput.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class CreateOrUpdateTextInput +{ + [DynamicStringLength(typeof(TextConsts), nameof(TextConsts.MaxValueLength))] + public string Value { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateTextInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateTextInput.cs new file mode 100644 index 0000000..5e51b07 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/CreateTextInput.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class CreateTextInput : CreateOrUpdateTextInput +{ + [Required] + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxNameLength))] + public string ResourceName { get; set; } + + [Required] + [DynamicStringLength(typeof(TextConsts), nameof(TextConsts.MaxKeyLength))] + public string Key { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxCultureNameLength))] + public string CultureName { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetLanguagesInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetLanguagesInput.cs new file mode 100644 index 0000000..c4cc77e --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetLanguagesInput.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class GetLanguagesInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetResourcesInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetResourcesInput.cs new file mode 100644 index 0000000..7fd5406 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetResourcesInput.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class GetResourcesInput : PagedAndSortedResultRequestDto +{ + public string Filter { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextByKeyInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextByKeyInput.cs new file mode 100644 index 0000000..4facded --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextByKeyInput.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class GetTextByKeyInput +{ + [Required] + [DynamicStringLength(typeof(TextConsts), nameof(TextConsts.MaxKeyLength))] + public string Key { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxCultureNameLength))] + public string CultureName { get; set; } + + [Required] + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxNameLength))] + public string ResourceName { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextsInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextsInput.cs new file mode 100644 index 0000000..717774c --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/GetTextsInput.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Validation; + +namespace Sanhe.Abp.LocalizationManagement; + +public class GetTextsInput : PagedAndSortedResultRequestDto +{ + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxCultureNameLength))] + public string CultureName { get; set; } + + [Required] + [DynamicStringLength(typeof(LanguageConsts), nameof(LanguageConsts.MaxCultureNameLength))] + public string TargetCultureName { get; set; } + + [DynamicStringLength(typeof(ResourceConsts), nameof(ResourceConsts.MaxNameLength))] + public string ResourceName { get; set; } + + public bool? OnlyNull { get; set; } + + public string Filter { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ILanguageAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ILanguageAppService.cs new file mode 100644 index 0000000..7661303 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ILanguageAppService.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface ILanguageAppService : + ICrudAppService< + LanguageDto, + Guid, + GetLanguagesInput, + CreateOrUpdateLanguageInput, + CreateOrUpdateLanguageInput> +{ + Task> GetAllAsync(); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/IResourceAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/IResourceAppService.cs new file mode 100644 index 0000000..7574635 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/IResourceAppService.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface IResourceAppService : + ICrudAppService< + ResourceDto, + Guid, + GetResourcesInput, + CreateOrUpdateResourceInput, + CreateOrUpdateResourceInput> +{ + Task> GetAllAsync(); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ITextAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ITextAppService.cs new file mode 100644 index 0000000..9cb45cd --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ITextAppService.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface ITextAppService : + ICrudAppService< + TextDto, + TextDifferenceDto, + int, + GetTextsInput, + CreateTextInput, + UpdateTextInput> +{ + Task GetByCultureKeyAsync(GetTextByKeyInput input); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LanguageDto.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LanguageDto.cs new file mode 100644 index 0000000..08593f1 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LanguageDto.cs @@ -0,0 +1,13 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class LanguageDto : AuditedEntityDto +{ + public bool Enable { get; set; } + public string CultureName { get; set; } + public string UiCultureName { get; set; } + public string DisplayName { get; set; } + public string FlagIcon { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LocalizationRemoteServiceConsts.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LocalizationRemoteServiceConsts.cs new file mode 100644 index 0000000..485e883 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/LocalizationRemoteServiceConsts.cs @@ -0,0 +1,6 @@ +namespace Sanhe.Abp.LocalizationManagement; + +public static class LocalizationRemoteServiceConsts +{ + public const string RemoteServiceName = "LocalizationManagement"; +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs new file mode 100644 index 0000000..bfd56ca --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissionDefinitionProvider.cs @@ -0,0 +1,72 @@ +using Sanhe.Abp.LocalizationManagement.Localization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.LocalizationManagement.Permissions; + +public class LocalizationManagementPermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var permissionGroup = context.AddGroup( + LocalizationManagementPermissions.GroupName, + L("Permissions:LocalizationManagement"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + + var resourcePermission = permissionGroup.AddPermission( + LocalizationManagementPermissions.Resource.Default, + L("Permissions:Resource"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + resourcePermission.AddChild( + LocalizationManagementPermissions.Resource.Create, + L("Permissions:Create"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + resourcePermission.AddChild( + LocalizationManagementPermissions.Resource.Update, + L("Permissions:Update"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + resourcePermission.AddChild( + LocalizationManagementPermissions.Resource.Delete, + L("Permissions:Delete"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + + var languagePermission = permissionGroup.AddPermission( + LocalizationManagementPermissions.Language.Default, + L("Permissions:Language"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + languagePermission.AddChild( + LocalizationManagementPermissions.Language.Create, + L("Permissions:Create"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + languagePermission.AddChild( + LocalizationManagementPermissions.Language.Update, + L("Permissions:Update"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + languagePermission.AddChild( + LocalizationManagementPermissions.Language.Delete, + L("Permissions:Delete"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + + var textPermission = permissionGroup.AddPermission( + LocalizationManagementPermissions.Text.Default, + L("Permissions:Text"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + textPermission.AddChild( + LocalizationManagementPermissions.Text.Create, + L("Permissions:Create"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + textPermission.AddChild( + LocalizationManagementPermissions.Text.Update, + L("Permissions:Update"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + textPermission.AddChild( + LocalizationManagementPermissions.Text.Delete, + L("Permissions:Delete"), + Volo.Abp.MultiTenancy.MultiTenancySides.Host); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissions.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissions.cs new file mode 100644 index 0000000..ad01fd4 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/Permissions/LocalizationManagementPermissions.cs @@ -0,0 +1,39 @@ +namespace Sanhe.Abp.LocalizationManagement.Permissions; + +public static class LocalizationManagementPermissions +{ + public const string GroupName = "LocalizationManagement"; + + public class Resource + { + public const string Default = GroupName + ".Resource"; + + public const string Create = Default + ".Create"; + + public const string Update = Default + ".Update"; + + public const string Delete = Default + ".Delete"; + } + + public class Language + { + public const string Default = GroupName + ".Language"; + + public const string Create = Default + ".Create"; + + public const string Update = Default + ".Update"; + + public const string Delete = Default + ".Delete"; + } + + public class Text + { + public const string Default = GroupName + ".Text"; + + public const string Create = Default + ".Create"; + + public const string Update = Default + ".Update"; + + public const string Delete = Default + ".Delete"; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ResourceDto.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ResourceDto.cs new file mode 100644 index 0000000..7037a3e --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/ResourceDto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class ResourceDto : AuditedEntityDto +{ + public bool Enable { get; set; } + public string Name { get; set; } + public string DisplayName { get; set; } + public string Description { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDifferenceDto.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDifferenceDto.cs new file mode 100644 index 0000000..f83bb6c --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDifferenceDto.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class TextDifferenceDto : EntityDto +{ + public string CultureName { get; set; } + public string Key { get; set; } + public string Value { get; set; } + public string ResourceName { get; set; } + public string TargetCultureName { get; set; } + public string TargetValue { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDto.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDto.cs new file mode 100644 index 0000000..969cdda --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/TextDto.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Application.Dtos; + +namespace Sanhe.Abp.LocalizationManagement; + +public class TextDto : EntityDto +{ + public string Key { get; set; } + public string Value { get; set; } + public string CultureName { get; set; } + public string ResourceName { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/UpdateTextInput.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/UpdateTextInput.cs new file mode 100644 index 0000000..28ceacd --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application.Contracts/Sanhe/Abp/LocalizationManagement/UpdateTextInput.cs @@ -0,0 +1,5 @@ +namespace Sanhe.Abp.LocalizationManagement; + +public class UpdateTextInput : CreateOrUpdateTextInput +{ +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe.Abp.LocalizationManagement.Application.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe.Abp.LocalizationManagement.Application.csproj new file mode 100644 index 0000000..dc2e9fe --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe.Abp.LocalizationManagement.Application.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationModule.cs new file mode 100644 index 0000000..1816109 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementApplicationModule.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.LocalizationManagement; + +[DependsOn( + typeof(AbpDddApplicationModule), + typeof(AbpLocalizationManagementDomainModule), + typeof(AbpLocalizationManagementApplicationContractsModule))] +public class AbpLocalizationManagementApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LanguageAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LanguageAppService.cs new file mode 100644 index 0000000..77020c8 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LanguageAppService.cs @@ -0,0 +1,70 @@ +using Sanhe.Abp.LocalizationManagement.Permissions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public class LanguageAppService : CrudAppService< + Language, + LanguageDto, + Guid, + GetLanguagesInput, + CreateOrUpdateLanguageInput, + CreateOrUpdateLanguageInput>, ILanguageAppService +{ + public LanguageAppService(ILanguageRepository repository) : base(repository) + { + GetPolicyName = LocalizationManagementPermissions.Language.Default; + GetListPolicyName = LocalizationManagementPermissions.Language.Default; + CreatePolicyName = LocalizationManagementPermissions.Language.Create; + UpdatePolicyName = LocalizationManagementPermissions.Language.Update; + DeletePolicyName = LocalizationManagementPermissions.Language.Delete; + } + + public async virtual Task> GetAllAsync() + { + await CheckGetListPolicyAsync(); + + var languages = await Repository.GetListAsync(); + + return new ListResultDto( + ObjectMapper.Map, List>(languages)); + } + + protected override Language MapToEntity(CreateOrUpdateLanguageInput createInput) + { + return new Language( + createInput.CultureName, + createInput.UiCultureName, + createInput.DisplayName, + createInput.FlagIcon) + { + Enable = createInput.Enable + }; + } + + protected override void MapToEntity(CreateOrUpdateLanguageInput updateInput, Language entity) + { + if (!string.Equals(entity.FlagIcon, updateInput.FlagIcon, StringComparison.InvariantCultureIgnoreCase)) + { + entity.FlagIcon = updateInput.FlagIcon; + } + entity.ChangeCulture(updateInput.CultureName, updateInput.UiCultureName, updateInput.DisplayName); + entity.Enable = updateInput.Enable; + } + + protected async override Task> CreateFilteredQueryAsync(GetLanguagesInput input) + { + var query = await base.CreateFilteredQueryAsync(input); + + query = query.WhereIf(!input.Filter.IsNullOrWhiteSpace(), + x => x.CultureName.Contains(input.Filter) || x.UiCultureName.Contains(input.Filter) || + x.DisplayName.Contains(input.Filter)); + + return query; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LocalizationManagementApplicationMapperProfile.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LocalizationManagementApplicationMapperProfile.cs new file mode 100644 index 0000000..86a659d --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/LocalizationManagementApplicationMapperProfile.cs @@ -0,0 +1,14 @@ +using AutoMapper; + +namespace Sanhe.Abp.LocalizationManagement; + +public class LocalizationManagementApplicationMapperProfile : Profile +{ + public LocalizationManagementApplicationMapperProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/ResourceAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/ResourceAppService.cs new file mode 100644 index 0000000..fcfa54a --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/ResourceAppService.cs @@ -0,0 +1,75 @@ +using Sanhe.Abp.LocalizationManagement.Permissions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public class ResourceAppService : CrudAppService< + Resource, + ResourceDto, + Guid, + GetResourcesInput, + CreateOrUpdateResourceInput, + CreateOrUpdateResourceInput>, IResourceAppService +{ + public ResourceAppService(IResourceRepository repository) : base(repository) + { + GetPolicyName = LocalizationManagementPermissions.Resource.Default; + GetListPolicyName = LocalizationManagementPermissions.Resource.Default; + CreatePolicyName = LocalizationManagementPermissions.Resource.Create; + UpdatePolicyName = LocalizationManagementPermissions.Resource.Update; + DeletePolicyName = LocalizationManagementPermissions.Resource.Delete; + } + + public async virtual Task> GetAllAsync() + { + await CheckGetListPolicyAsync(); + + var resources = await Repository.GetListAsync(); + + return new ListResultDto( + ObjectMapper.Map, List>(resources)); + } + + protected override Resource MapToEntity(CreateOrUpdateResourceInput createInput) + { + return new Resource( + createInput.Name, + createInput.DisplayName, + createInput.Description) + { + Enable = createInput.Enable + }; + } + + protected override void MapToEntity(CreateOrUpdateResourceInput updateInput, Resource entity) + { + if (!string.Equals(entity.Name, updateInput.Name, StringComparison.InvariantCultureIgnoreCase)) + { + entity.Name = updateInput.Name; + } + if (!string.Equals(entity.DisplayName, updateInput.DisplayName, StringComparison.InvariantCultureIgnoreCase)) + { + entity.DisplayName = updateInput.DisplayName; + } + if (!string.Equals(entity.Description, updateInput.Description, StringComparison.InvariantCultureIgnoreCase)) + { + entity.Description = updateInput.Description; + } + entity.Enable = updateInput.Enable; + } + + protected async override Task> CreateFilteredQueryAsync(GetResourcesInput input) + { + var query = await base.CreateFilteredQueryAsync(input); + + query = query.WhereIf(!input.Filter.IsNullOrWhiteSpace(), + x => x.Name.Contains(input.Filter) || x.DisplayName.Contains(input.Filter)); + + return query; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/TextAppService.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/TextAppService.cs new file mode 100644 index 0000000..fb876e7 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Application/Sanhe/Abp/LocalizationManagement/TextAppService.cs @@ -0,0 +1,71 @@ +using Sanhe.Abp.LocalizationManagement.Permissions; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; + +namespace Sanhe.Abp.LocalizationManagement; + +public class TextAppService : CrudAppService< + Text, + TextDto, + TextDifferenceDto, + int, + GetTextsInput, + CreateTextInput, + UpdateTextInput>, ITextAppService +{ + private readonly ITextRepository _textRepository; + + public TextAppService(ITextRepository repository) : base(repository) + { + _textRepository = repository; + + GetPolicyName = LocalizationManagementPermissions.Text.Default; + GetListPolicyName = LocalizationManagementPermissions.Text.Default; + CreatePolicyName = LocalizationManagementPermissions.Text.Create; + UpdatePolicyName = LocalizationManagementPermissions.Text.Update; + DeletePolicyName = LocalizationManagementPermissions.Text.Delete; + } + + public async virtual Task GetByCultureKeyAsync(GetTextByKeyInput input) + { + await CheckGetPolicyAsync(); + + var text = await _textRepository.GetByCultureKeyAsync( + input.ResourceName, input.CultureName, input.Key); + + return await MapToGetOutputDtoAsync(text); + } + + public async override Task> GetListAsync(GetTextsInput input) + { + await CheckGetListPolicyAsync(); + + var count = await _textRepository.GetDifferenceCountAsync( + input.CultureName, input.TargetCultureName, + input.ResourceName, input.OnlyNull, input.Filter); + + var texts = await _textRepository.GetDifferencePagedListAsync( + input.CultureName, input.TargetCultureName, + input.ResourceName, input.OnlyNull, input.Filter, + input.Sorting, input.SkipCount, input.MaxResultCount); + + return new PagedResultDto(count, + ObjectMapper.Map, List>(texts)); + } + + protected override Text MapToEntity(CreateTextInput createInput) + { + return new Text( + createInput.ResourceName, + createInput.CultureName, + createInput.Key, + createInput.Value); + } + + protected override void MapToEntity(UpdateTextInput updateInput, Text entity) + { + entity.SetValue(updateInput.Value); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj new file mode 100644 index 0000000..57a1009 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs new file mode 100644 index 0000000..6c1a007 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainSharedModule.cs @@ -0,0 +1,29 @@ +using Sanhe.Abp.LocalizationManagement.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Validation; +using Volo.Abp.VirtualFileSystem; + +namespace Sanhe.Abp.LocalizationManagement +{ + [DependsOn( + typeof(AbpValidationModule), + typeof(AbpLocalizationModule))] + public class AbpLocalizationManagementDomainSharedModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Sanhe/Abp/LocalizationManagement/Localization/Resources"); + }); + } + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/LanguageConsts.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/LanguageConsts.cs new file mode 100644 index 0000000..ac5b90a --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/LanguageConsts.cs @@ -0,0 +1,10 @@ +namespace Sanhe.Abp.LocalizationManagement +{ + public static class LanguageConsts + { + public static int MaxCultureNameLength { get; set; } = 20; + public static int MaxUiCultureNameLength { get; set; } = 20; + public static int MaxDisplayNameLength { get; set; } = 64; + public static int MaxFlagIconLength { get; set; } = 30; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/LocalizationManagementResource.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/LocalizationManagementResource.cs new file mode 100644 index 0000000..72a2e3c --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/LocalizationManagementResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace Sanhe.Abp.LocalizationManagement.Localization; + +[LocalizationResourceName("LocalizationManagement")] +public class LocalizationManagementResource +{ +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/en.json b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/en.json new file mode 100644 index 0000000..abf0296 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/en.json @@ -0,0 +1,45 @@ +{ + "culture": "en", + "texts": { + "Languages": "Languages", + "Resources": "Resources", + "Texts": "Texts", + + "Delete": "Delete", + "DisplayName:Any": "Any", + "DisplayName:CreationTime": "Creation Time", + "DisplayName:CultureName": "Culture", + "DisplayName:Description": "Description", + "DisplayName:DisplayName": "Display Name", + "DisplayName:Enable": "Enable", + "DisplayName:FlagIcon": "Flag Icon", + "DisplayName:Key": "Key", + "DisplayName:LastModificationTime": "Modification Time", + "DisplayName:Name": "Name", + "DisplayName:OnlyNull": "Only Null", + "DisplayName:ResourceName": "Resource", + "DisplayName:SaveAndNext": "Save & Next", + "DisplayName:TargetCultureName": "Target Culture", + "DisplayName:TargetValue": "Target Value", + "DisplayName:UiCultureName": "Ui Culture", + "DisplayName:Value": "Value", + "Permissions:LocalizationManagement": "Localization", + "Permissions:Language": "Language", + "Permissions:Resource": "Resource", + "Permissions:Text": "Text", + "Permissions:Create": "Create", + "Permissions:Update": "Update", + "Permissions:Delete": "Delete", + "Edit": "Edit", + "EditByName": "Edit - {0}", + "Filter": "Filter", + "Language:AddNew": "Add New Language", + "Resource:AddNew": "Add New Resource", + "SaveAndNext": "Save & Next", + "SearchFilter": "Search", + "Text:AddNew": "Add New Text", + "WillDeleteLanguage": "Language to be deleted {0}", + "WillDeleteResource": "Resource to be deleted {0}", + "WillDeleteText": "Document to be deleted {0}" + } +} \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json new file mode 100644 index 0000000..8bfb0cb --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/Localization/Resources/zh-Hans.json @@ -0,0 +1,45 @@ +{ + "culture": "zh-Hans", + "texts": { + "Languages": "语言", + "Resources": "资源", + "Texts": "文档", + + "Delete": "删除", + "DisplayName:Any": "所有", + "DisplayName:CreationTime": "创建时间", + "DisplayName:CultureName": "文化名称", + "DisplayName:Description": "描述", + "DisplayName:DisplayName": "显示名称", + "DisplayName:Enable": "启用", + "DisplayName:FlagIcon": "旗帜图标", + "DisplayName:Key": "键", + "DisplayName:LastModificationTime": "变更时间", + "DisplayName:Name": "名称", + "DisplayName:OnlyNull": "仅空值", + "DisplayName:ResourceName": "资源名称", + "DisplayName:SaveAndNext": "保存并下一步", + "DisplayName:TargetCultureName": "目标文化", + "DisplayName:TargetValue": "目标值", + "DisplayName:UiCultureName": "界面文化", + "DisplayName:Value": "值", + "Permissions:LocalizationManagement": "本地化管理", + "Permissions:Language": "语言管理", + "Permissions:Resource": "资源管理", + "Permissions:Text": "文档管理", + "Permissions:Create": "新增", + "Permissions:Update": "编辑", + "Permissions:Delete": "删除", + "Edit": "编辑", + "EditByName": "编辑 - {0}", + "Filter": "过滤字符", + "Language:AddNew": "添加新语言", + "Resource:AddNew": "添加新资源", + "SaveAndNext": "保存并下一步", + "SearchFilter": "请输入过滤字符", + "Text:AddNew": "添加新文档", + "WillDeleteLanguage": "将要删除语言 {0}", + "WillDeleteResource": "将要删除资源 {0}", + "WillDeleteText": "将要删除文档 {0}" + } +} \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/ResourceConsts.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/ResourceConsts.cs new file mode 100644 index 0000000..cd83254 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/ResourceConsts.cs @@ -0,0 +1,9 @@ +namespace Sanhe.Abp.LocalizationManagement +{ + public static class ResourceConsts + { + public static int MaxNameLength { get; set; } = 50; + public static int MaxDisplayNameLength { get; set; } = 64; + public static int MaxDescriptionLength { get; set; } = 64; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextConsts.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextConsts.cs new file mode 100644 index 0000000..ab8bafe --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextConsts.cs @@ -0,0 +1,8 @@ +namespace Sanhe.Abp.LocalizationManagement +{ + public static class TextConsts + { + public static int MaxKeyLength { get; set; } = 512; + public static int MaxValueLength { get; set; } = 2 * 1024; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextDifference.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextDifference.cs new file mode 100644 index 0000000..c956f63 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextDifference.cs @@ -0,0 +1,37 @@ +namespace Sanhe.Abp.LocalizationManagement +{ + /// + /// 文本差异 + /// + public class TextDifference + { + public int Id { get; set; } + public string CultureName { get; set; } + public string Key { get; set; } + public string Value { get; set; } + public string ResourceName { get; set; } + public string TargetCultureName { get; set; } + public string TargetValue { get; set; } + + public TextDifference() { } + + public TextDifference( + int id, + string cultureName, + string key, + string value, + string targetCultureName, + string targetValue = null, + string resourceName = null) + { + Id = id; + Key = key; + Value = value; + CultureName = cultureName; + TargetCultureName = targetCultureName; + + TargetValue = targetValue; + ResourceName = resourceName; + } + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextEto.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextEto.cs new file mode 100644 index 0000000..d5dcbcc --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain.Shared/Sanhe/Abp/LocalizationManagement/TextEto.cs @@ -0,0 +1,22 @@ +namespace Sanhe.Abp.LocalizationManagement +{ + public class TextEto + { + /// + /// 文化名称 + /// + public string CultureName { get; set; } + /// + /// Key + /// + public string Key { get; set; } + /// + /// Value + /// + public string Value { get; set; } + /// + /// 资源名称 + /// + public string ResourceName { get; set; } + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe.Abp.LocalizationManagement.Domain.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe.Abp.LocalizationManagement.Domain.csproj new file mode 100644 index 0000000..3b90f2c --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe.Abp.LocalizationManagement.Domain.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs new file mode 100644 index 0000000..e6b96a2 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementDomainModule.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Sanhe.Abp.Localization.Dynamic; +using Sanhe.Abp.LocalizationManagement.Localization; +using Volo.Abp.AutoMapper; +using Volo.Abp.Domain; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.LocalizationManagement; + +[DependsOn( + typeof(AbpAutoMapperModule), + typeof(AbpDddDomainModule), + typeof(AbpLocalizationDynamicModule), + typeof(AbpLocalizationManagementDomainSharedModule))] +public class AbpLocalizationManagementDomainModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.Resources + .Get() + .AddDynamic(); + }); + + Configure(options => + { + options.AddProfile(validate: true); + }); + + // 分布式事件 + //Configure(options => + //{ + // options.AutoEventSelectors.Add(); + // options.EtoMappings.Add(); + //}); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ILanguageRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ILanguageRepository.cs new file mode 100644 index 0000000..64e58c6 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ILanguageRepository.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface ILanguageRepository : IRepository +{ + Task FindByCultureNameAsync(string cultureName, CancellationToken cancellationToken = default); + + Task> GetActivedListAsync(CancellationToken cancellationToken = default); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/IResourceRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/IResourceRepository.cs new file mode 100644 index 0000000..6467f31 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/IResourceRepository.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface IResourceRepository : IRepository +{ + Task ExistsAsync( + string name, + CancellationToken cancellationToken = default); + + Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ITextRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ITextRepository.cs new file mode 100644 index 0000000..47137a1 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/ITextRepository.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace Sanhe.Abp.LocalizationManagement; + +public interface ITextRepository : IRepository +{ + Task GetByCultureKeyAsync( + string resourceName, + string cultureName, + string key, + CancellationToken cancellationToken = default); + + Task> GetListAsync( + string resourceName, + CancellationToken cancellationToken = default); + + Task> GetListAsync( + string resourceName, + string cultureName, + CancellationToken cancellationToken = default); + + Task GetDifferenceCountAsync( + string cultureName, + string targetCultureName, + string resourceName = null, + bool? onlyNull = null, + string filter = null, + CancellationToken cancellationToken = default); + + Task> GetDifferencePagedListAsync( + string cultureName, + string targetCultureName, + string resourceName = null, + bool? onlyNull = null, + string filter = null, + string sorting = nameof(Text.Key), + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default); +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Language.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Language.cs new file mode 100644 index 0000000..439b99d --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Language.cs @@ -0,0 +1,53 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.LocalizationManagement; + +public class Language : AuditedEntity, ILanguageInfo +{ + public virtual bool Enable { get; set; } + public virtual string CultureName { get; protected set; } + public virtual string UiCultureName { get; protected set; } + public virtual string DisplayName { get; protected set; } + public virtual string FlagIcon { get; set; } + + protected Language() { } + + public Language( + [NotNull] string cultureName, + [NotNull] string uiCultureName, + [NotNull] string displayName, + string flagIcon = null) + { + CultureName = Check.NotNullOrWhiteSpace(cultureName, nameof(cultureName), LanguageConsts.MaxCultureNameLength); + UiCultureName = Check.NotNullOrWhiteSpace(uiCultureName, nameof(uiCultureName), LanguageConsts.MaxUiCultureNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), LanguageConsts.MaxDisplayNameLength); + + FlagIcon = !flagIcon.IsNullOrWhiteSpace() + ? Check.Length(flagIcon, nameof(flagIcon), LanguageConsts.MaxFlagIconLength) + : null; + + Enable = true; + } + + public virtual void ChangeCulture(string cultureName, string uiCultureName = null, string displayName = null) + { + ChangeCultureInternal(cultureName, uiCultureName, displayName); + } + + private void ChangeCultureInternal(string cultureName, string uiCultureName, string displayName) + { + CultureName = Check.NotNullOrWhiteSpace(cultureName, nameof(cultureName), LanguageConsts.MaxCultureNameLength); + + UiCultureName = !uiCultureName.IsNullOrWhiteSpace() + ? Check.Length(uiCultureName, nameof(uiCultureName), LanguageConsts.MaxUiCultureNameLength) + : cultureName; + + DisplayName = !displayName.IsNullOrWhiteSpace() + ? Check.Length(displayName, nameof(displayName), LanguageConsts.MaxDisplayNameLength) + : cultureName; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationDbProperties.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationDbProperties.cs new file mode 100644 index 0000000..ffe1d88 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationDbProperties.cs @@ -0,0 +1,10 @@ +namespace Sanhe.Abp.LocalizationManagement; + +public static class LocalizationDbProperties +{ + public static string DbTablePrefix { get; set; } = "AbpLocalization"; + + public static string DbSchema { get; set; } = null; + + public const string ConnectionStringName = "AbpLocalizationManagement"; +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationManagementDomainMapperProfile.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationManagementDomainMapperProfile.cs new file mode 100644 index 0000000..bb889e1 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationManagementDomainMapperProfile.cs @@ -0,0 +1,11 @@ +using AutoMapper; + +namespace Sanhe.Abp.LocalizationManagement; + +public class LocalizationManagementDomainMapperProfile : Profile +{ + public LocalizationManagementDomainMapperProfile() + { + CreateMap(); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationStore.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationStore.cs new file mode 100644 index 0000000..4caacc3 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationStore.cs @@ -0,0 +1,85 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Sanhe.Abp.Localization.Dynamic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; + +namespace Sanhe.Abp.LocalizationManagement; + +[Dependency(ServiceLifetime.Singleton, ReplaceServices = true)] +[ExposeServices( + typeof(ILocalizationStore), + typeof(LocalizationStore))] +public class LocalizationStore : ILocalizationStore +{ + protected ILanguageRepository LanguageRepository { get; } + protected ITextRepository TextRepository { get; } + protected IResourceRepository ResourceRepository { get; } + + public LocalizationStore( + ILanguageRepository languageRepository, + ITextRepository textRepository, + IResourceRepository resourceRepository) + { + TextRepository = textRepository; + LanguageRepository = languageRepository; + ResourceRepository = resourceRepository; + } + + public async virtual Task> GetLanguageListAsync( + CancellationToken cancellationToken = default) + { + var languages = await LanguageRepository.GetActivedListAsync(cancellationToken); + + return languages + .Select(x => new LanguageInfo(x.CultureName, x.UiCultureName, x.DisplayName, x.FlagIcon)) + .ToList(); + } + + public async virtual Task> GetLocalizationDictionaryAsync( + string resourceName, + CancellationToken cancellationToken = default) + { + // TODO: 引用缓存? + var dictionaries = new Dictionary(); + var resource = await ResourceRepository.FindByNameAsync(resourceName, cancellationToken); + if (resource == null || !resource.Enable) + { + // 资源不存在或未启用返回空 + return dictionaries; + } + + var texts = await TextRepository.GetListAsync(resourceName, cancellationToken); + + foreach (var textGroup in texts.GroupBy(x => x.CultureName)) + { + var cultureTextDictionaires = new Dictionary(); + foreach (var text in textGroup) + { + // 本地化名称去重 + if (!cultureTextDictionaires.ContainsKey(text.Key)) + { + cultureTextDictionaires[text.Key] = new LocalizedString(text.Key, text.Value.NormalizeLineEndings()); + } + } + + // 本地化语言去重 + if (!dictionaries.ContainsKey(textGroup.Key)) + { + dictionaries[textGroup.Key] = new StaticLocalizationDictionary(textGroup.Key, cultureTextDictionaires); + } + } + + return dictionaries; + } + + public async virtual Task ResourceExistsAsync(string resourceName, CancellationToken cancellationToken = default) + { + return await ResourceRepository.ExistsAsync(resourceName, cancellationToken); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationSynchronizer.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationSynchronizer.cs new file mode 100644 index 0000000..c90f5be --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/LocalizationSynchronizer.cs @@ -0,0 +1,52 @@ +using Sanhe.Abp.Localization.Dynamic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.EventBus.Distributed; + +namespace Sanhe.Abp.LocalizationManagement; + +public class LocalizationSynchronizer : + ILocalEventHandler>, + ILocalEventHandler>, + ILocalEventHandler>, + ITransientDependency +{ + private readonly IDistributedEventBus _eventBus; + + public LocalizationSynchronizer( + IDistributedEventBus eventBus) + { + _eventBus = eventBus; + } + + public async virtual Task HandleEventAsync(EntityCreatedEventData eventData) + { + await HandleEventAsync(BuildResetEventData(eventData.Entity)); + } + + public async virtual Task HandleEventAsync(EntityUpdatedEventData eventData) + { + await HandleEventAsync(BuildResetEventData(eventData.Entity)); + } + + public async virtual Task HandleEventAsync(EntityDeletedEventData eventData) + { + var data = BuildResetEventData(eventData.Entity); + data.IsDeleted = true; + + await HandleEventAsync(data); + } + + private LocalizedStringCacheResetEventData BuildResetEventData(Text text) + { + return new LocalizedStringCacheResetEventData( + text.ResourceName, text.CultureName, text.Key, text.Value); + } + + private async Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) + { + await _eventBus.PublishAsync(eventData); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Resource.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Resource.cs new file mode 100644 index 0000000..66b39d8 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Resource.cs @@ -0,0 +1,29 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities.Auditing; + +namespace Sanhe.Abp.LocalizationManagement; + +public class Resource : AuditedEntity +{ + public virtual bool Enable { get; set; } + public virtual string Name { get; set; } + public virtual string DisplayName { get; set; } + public virtual string Description { get; set; } + + protected Resource() { } + + public Resource( + [NotNull] string name, + [CanBeNull] string displayName = null, + [CanBeNull] string description = null) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), ResourceConsts.MaxNameLength); + + DisplayName = displayName ?? Name; + Description = description; + + Enable = true; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Text.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Text.cs new file mode 100644 index 0000000..2a705ba --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.Domain/Sanhe/Abp/LocalizationManagement/Text.cs @@ -0,0 +1,36 @@ +using JetBrains.Annotations; +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities; + +namespace Sanhe.Abp.LocalizationManagement; + +public class Text : Entity +{ + public virtual string CultureName { get; protected set; } + public virtual string Key { get; protected set; } + public virtual string Value { get; protected set; } + public virtual string ResourceName { get; protected set; } + protected Text() { } + public Text( + [NotNull] string resourceName, + [NotNull] string cultureName, + [NotNull] string key, + [CanBeNull] string value) + { + ResourceName = Check.NotNull(resourceName, nameof(resourceName), ResourceConsts.MaxNameLength); + CultureName = Check.NotNullOrWhiteSpace(cultureName, nameof(cultureName), LanguageConsts.MaxCultureNameLength); + Key = Check.NotNullOrWhiteSpace(key, nameof(key), TextConsts.MaxKeyLength); + + Value = !value.IsNullOrWhiteSpace() + ? Check.NotNullOrWhiteSpace(value, nameof(value), TextConsts.MaxValueLength) + : ""; + } + + public void SetValue(string value) + { + Value = !value.IsNullOrWhiteSpace() + ? Check.NotNullOrWhiteSpace(value, nameof(value), TextConsts.MaxValueLength) + : Value; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore.csproj new file mode 100644 index 0000000..c6a50fa --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore.csproj @@ -0,0 +1,19 @@ + + + + + + + net6.0 + + + + + + + + + + + + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/AbpLocalizationManagementEntityFrameworkCoreModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/AbpLocalizationManagementEntityFrameworkCoreModule.cs new file mode 100644 index 0000000..337418d --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/AbpLocalizationManagementEntityFrameworkCoreModule.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Modularity; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +[DependsOn( + typeof(AbpEntityFrameworkCoreModule), + typeof(AbpLocalizationManagementDomainModule))] +public class AbpLocalizationManagementEntityFrameworkCoreModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddRepository(); + options.AddRepository(); + options.AddRepository(); + + options.AddDefaultRepositories(includeAllEntities: true); + }); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreLanguageRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreLanguageRepository.cs new file mode 100644 index 0000000..455f4a0 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreLanguageRepository.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +public class EfCoreLanguageRepository : EfCoreRepository, ILanguageRepository +{ + public EfCoreLanguageRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + + } + + public async virtual Task FindByCultureNameAsync( + string cultureName, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).Where(x => x.CultureName.Equals(cultureName)) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetActivedListAsync(CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).Where(x => x.Enable) + .ToListAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs new file mode 100644 index 0000000..d667a30 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreResourceRepository.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +public class EfCoreResourceRepository : EfCoreRepository, IResourceRepository +{ + public EfCoreResourceRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + public async virtual Task ExistsAsync( + string name, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).AnyAsync(x => x.Name.Equals(name), cancellationToken: cancellationToken); + } + + public async virtual Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()).Where(x => x.Name.Equals(name)) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreTextRepository.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreTextRepository.cs new file mode 100644 index 0000000..54a980c --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/EfCoreTextRepository.cs @@ -0,0 +1,132 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +public class EfCoreTextRepository : EfCoreRepository, ITextRepository +{ + public EfCoreTextRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + + } + + public async virtual Task GetByCultureKeyAsync( + string resourceName, + string cultureName, + string key, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.ResourceName.Equals(resourceName) && x.CultureName.Equals(cultureName) && x.Key.Equals(key)) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task GetDifferenceCountAsync( + string cultureName, + string targetCultureName, + string resourceName = null, + bool? onlyNull = null, + string filter = null, + CancellationToken cancellationToken = default) + { + return await (await BuildTextDifferenceQueryAsync( + cultureName, + targetCultureName, + resourceName, + onlyNull, + filter)) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + string resourceName, + CancellationToken cancellationToken = default) + { + var languages = (await GetDbContextAsync()).Set(); + var texts = await GetDbSetAsync(); + + return await (from txts in texts + join lg in languages + on txts.CultureName equals lg.CultureName + where txts.ResourceName.Equals(resourceName) && + lg.Enable + select txts) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + string resourceName, + string cultureName, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(x => x.ResourceName.Equals(resourceName) && x.CultureName.Equals(cultureName)) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetDifferencePagedListAsync( + string cultureName, + string targetCultureName, + string resourceName = null, + bool? onlyNull = null, + string filter = null, + string sorting = nameof(TextDifference.Key), + int skipCount = 1, + int maxResultCount = 10, + CancellationToken cancellationToken = default) + { + return await (await BuildTextDifferenceQueryAsync( + cultureName, + targetCultureName, + resourceName, + onlyNull, + filter, + sorting)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + protected async virtual Task> BuildTextDifferenceQueryAsync( + string cultureName, + string targetCultureName, + string resourceName = null, + bool? onlyNull = null, + string filter = null, + string sorting = nameof(TextDifference.Key)) + { + var textQuery = (await GetDbSetAsync()) + .Where(x => x.CultureName.Equals(cultureName)) + .WhereIf(!resourceName.IsNullOrWhiteSpace(), x => x.ResourceName.Equals(resourceName)) + .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Key.Contains(filter)) + .OrderBy(sorting ?? nameof(TextDifference.Key)); + + var targetTextQuery = (await GetDbSetAsync()) + .Where(x => x.CultureName.Equals(targetCultureName)) + .WhereIf(!resourceName.IsNullOrWhiteSpace(), x => x.ResourceName.Equals(resourceName)); + + var query = from crtText in textQuery + join tgtText in targetTextQuery + on crtText.Key equals tgtText.Key + into tgt + from tt in tgt.DefaultIfEmpty() + where onlyNull.HasValue && onlyNull.Value + ? tt.Value == null + : 1 == 1 + select new TextDifference( + crtText.Id, + crtText.CultureName, + crtText.Key, + crtText.Value, + targetCultureName, + tt != null ? tt.Value : null, + crtText.ResourceName); + return query; + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/ILocalizationDbContext.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/ILocalizationDbContext.cs new file mode 100644 index 0000000..f2a989e --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/ILocalizationDbContext.cs @@ -0,0 +1,13 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +[ConnectionStringName(LocalizationDbProperties.ConnectionStringName)] +public interface ILocalizationDbContext : IEfCoreDbContext +{ + DbSet Resources { get; set; } + DbSet Languages { get; set; } + DbSet Texts { get; set; } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContext.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContext.cs new file mode 100644 index 0000000..a208fa8 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContext.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +[ConnectionStringName(LocalizationDbProperties.ConnectionStringName)] +public class LocalizationDbContext : AbpDbContext, ILocalizationDbContext +{ + public virtual DbSet Resources { get; set; } + public virtual DbSet Languages { get; set; } + public virtual DbSet Texts { get; set; } + + public LocalizationDbContext(DbContextOptions options) : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureLocalization(); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContextModelBuilderExtensions.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContextModelBuilderExtensions.cs new file mode 100644 index 0000000..3ef3cf0 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationDbContextModelBuilderExtensions.cs @@ -0,0 +1,98 @@ +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +public static class LocalizationDbContextModelBuilderExtensions +{ + public static void ConfigureLocalization( + this ModelBuilder builder, + Action optionsAction = null) + { + Check.NotNull(builder, nameof(builder)); + + var options = new LocalizationModelBuilderConfigurationOptions( + LocalizationDbProperties.DbTablePrefix, + LocalizationDbProperties.DbSchema + ); + + optionsAction?.Invoke(options); + + builder.Entity(x => + { + x.ToTable(options.TablePrefix + "Languages", options.Schema); + + x.Property(p => p.CultureName) + .IsRequired() + .HasMaxLength(LanguageConsts.MaxCultureNameLength) + .HasColumnName(nameof(Language.CultureName)); + x.Property(p => p.UiCultureName) + .IsRequired() + .HasMaxLength(LanguageConsts.MaxUiCultureNameLength) + .HasColumnName(nameof(Language.UiCultureName)); + x.Property(p => p.DisplayName) + .IsRequired() + .HasMaxLength(LanguageConsts.MaxDisplayNameLength) + .HasColumnName(nameof(Language.DisplayName)); + + x.Property(p => p.FlagIcon) + .IsRequired(false) + .HasMaxLength(LanguageConsts.MaxFlagIconLength) + .HasColumnName(nameof(Language.FlagIcon)); + + x.Property(p => p.Enable) + .HasDefaultValue(true); + + x.ConfigureByConvention(); + + x.HasIndex(p => p.CultureName); + }); + + builder.Entity(x => + { + x.ToTable(options.TablePrefix + "Resources", options.Schema); + + x.Property(p => p.Name) + .IsRequired() + .HasMaxLength(ResourceConsts.MaxNameLength) + .HasColumnName(nameof(Resource.Name)); + + x.Property(p => p.DisplayName) + .HasMaxLength(ResourceConsts.MaxDisplayNameLength) + .HasColumnName(nameof(Resource.DisplayName)); + x.Property(p => p.Description) + .HasMaxLength(ResourceConsts.MaxDescriptionLength) + .HasColumnName(nameof(Resource.Description)); + + x.Property(p => p.Enable) + .HasDefaultValue(true); + + x.ConfigureByConvention(); + + x.HasIndex(p => p.Name); + }); + + builder.Entity(x => + { + x.ToTable(options.TablePrefix + "Texts", options.Schema); + + x.Property(p => p.CultureName) + .IsRequired() + .HasMaxLength(LanguageConsts.MaxCultureNameLength) + .HasColumnName(nameof(Text.CultureName)); + x.Property(p => p.Key) + .IsRequired() + .HasMaxLength(TextConsts.MaxKeyLength) + .HasColumnName(nameof(Text.Key)); + x.Property(p => p.Value) + .HasMaxLength(TextConsts.MaxValueLength) + .HasColumnName(nameof(Text.Value)); + + x.ConfigureByConvention(); + + x.HasIndex(p => p.Key); + }); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationModelBuilderConfigurationOptions.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationModelBuilderConfigurationOptions.cs new file mode 100644 index 0000000..93d7bb9 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.EntityFrameworkCore/Sanhe/Abp/LocalizationManagement/EntityFrameworkCore/LocalizationModelBuilderConfigurationOptions.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace Sanhe.Abp.LocalizationManagement.EntityFrameworkCore; + +public class LocalizationModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions +{ + public LocalizationModelBuilderConfigurationOptions( + [NotNull] string tablePrefix = "", + [CanBeNull] string schema = null) + : base( + tablePrefix, + schema) + { + + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/FodyWeavers.xml b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/FodyWeavers.xml new file mode 100644 index 0000000..1715698 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe.Abp.LocalizationManagement.HttpApi.csproj b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe.Abp.LocalizationManagement.HttpApi.csproj new file mode 100644 index 0000000..bdc112b --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe.Abp.LocalizationManagement.HttpApi.csproj @@ -0,0 +1,19 @@ + + + + + + + net6.0 + + + + + + + + + + + + diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementHttpApiModule.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementHttpApiModule.cs new file mode 100644 index 0000000..aceea4e --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/AbpLocalizationManagementHttpApiModule.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Sanhe.Abp.LocalizationManagement.Localization; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Validation.Localization; + +namespace Sanhe.Abp.LocalizationManagement; + +[DependsOn( + typeof(AbpAspNetCoreMvcModule), + typeof(AbpLocalizationManagementApplicationContractsModule))] +public class AbpLocalizationManagementHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + // Dto验证本地化 + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(LocalizationManagementResource), + typeof(AbpLocalizationManagementApplicationContractsModule).Assembly); + }); + + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpLocalizationManagementApplicationContractsModule).Assembly); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Resources + .Get() + .AddBaseTypes(typeof(AbpValidationResource)); + }); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/LanguageController.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/LanguageController.cs new file mode 100644 index 0000000..4e4f9e3 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/LanguageController.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace Sanhe.Abp.LocalizationManagement; + +[RemoteService(Name = LocalizationRemoteServiceConsts.RemoteServiceName)] +[Area("localization")] +[Route("api/localization/languages")] +public class LanguageController : AbpController, ILanguageAppService +{ + private readonly ILanguageAppService _service; + + public LanguageController(ILanguageAppService service) + { + _service = service; + } + + [HttpPost] + public virtual Task CreateAsync(CreateOrUpdateLanguageInput input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{id}")] + public virtual Task DeleteAsync(Guid id) + { + return _service.DeleteAsync(id); + } + + [HttpGet] + [Route("all")] + public virtual Task> GetAllAsync() + { + return _service.GetAllAsync(); + } + + [HttpGet] + [Route("{id}")] + public virtual Task GetAsync(Guid id) + { + return _service.GetAsync(id); + } + + [HttpGet] + public virtual Task> GetListAsync(GetLanguagesInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{id}")] + public virtual Task UpdateAsync(Guid id, CreateOrUpdateLanguageInput input) + { + return _service.UpdateAsync(id, input); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/ResourceController.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/ResourceController.cs new file mode 100644 index 0000000..c605369 --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/ResourceController.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace Sanhe.Abp.LocalizationManagement; + +[RemoteService(Name = LocalizationRemoteServiceConsts.RemoteServiceName)] +[Area("localization")] +[Route("api/localization/resources")] +public class ResourceController : AbpController, IResourceAppService +{ + private readonly IResourceAppService _service; + + public ResourceController(IResourceAppService service) + { + _service = service; + } + + [HttpPost] + public virtual Task CreateAsync(CreateOrUpdateResourceInput input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{id}")] + public virtual Task DeleteAsync(Guid id) + { + return _service.DeleteAsync(id); + } + + [HttpGet] + [Route("all")] + public virtual Task> GetAllAsync() + { + return _service.GetAllAsync(); + } + + [HttpGet] + [Route("{id}")] + public virtual Task GetAsync(Guid id) + { + return _service.GetAsync(id); + } + + [HttpGet] + public virtual Task> GetListAsync(GetResourcesInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{id}")] + public virtual Task UpdateAsync(Guid id, CreateOrUpdateResourceInput input) + { + return _service.UpdateAsync(id, input); + } +} diff --git a/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/TextController.cs b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/TextController.cs new file mode 100644 index 0000000..aac492a --- /dev/null +++ b/modules/localization-management/Sanhe.Abp.LocalizationManagement.HttpApi/Sanhe/Abp/LocalizationManagement/TextController.cs @@ -0,0 +1,60 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace Sanhe.Abp.LocalizationManagement; + +[RemoteService(Name = LocalizationRemoteServiceConsts.RemoteServiceName)] +[Area("localization")] +[Route("api/localization/texts")] +public class TextController : AbpController, ITextAppService +{ + private readonly ITextAppService _service; + + public TextController(ITextAppService service) + { + _service = service; + } + + [HttpPost] + public virtual Task CreateAsync(CreateTextInput input) + { + return _service.CreateAsync(input); + } + + [HttpDelete] + [Route("{id}")] + public virtual Task DeleteAsync(int id) + { + return _service.DeleteAsync(id); + } + + [HttpGet] + [Route("{id}")] + public virtual Task GetAsync(int id) + { + return _service.GetAsync(id); + } + + [HttpGet] + [Route("by-culture-key")] + public virtual Task GetByCultureKeyAsync(GetTextByKeyInput input) + { + return _service.GetByCultureKeyAsync(input); + } + + [HttpGet] + public virtual Task> GetListAsync(GetTextsInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut] + [Route("{id}")] + public virtual Task UpdateAsync(int id, UpdateTextInput input) + { + return _service.UpdateAsync(id, input); + } +} diff --git a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs index 120e803..a5395a1 100644 --- a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs +++ b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionPageWrapResultFilter.cs @@ -64,15 +64,15 @@ public class AbpExceptionPageWrapResultFilter : AbpExceptionPageFilter, ITransie { var statusCodFinder = context.GetRequiredService(); var exceptionWrapHandler = context.GetRequiredService(); - + var exceptionWrapContext = new ExceptionWrapContext( context.Exception, remoteServiceErrorInfo, context.HttpContext.RequestServices, statusCodFinder.GetStatusCode(context.HttpContext, context.Exception)); - + exceptionWrapHandler.CreateFor(exceptionWrapContext).Wrap(exceptionWrapContext); - + context.Result = new ObjectResult(new WrapResult( exceptionWrapContext.ErrorInfo.Code, exceptionWrapContext.ErrorInfo.Message, diff --git a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs index b057372..d3ade76 100644 --- a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs +++ b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/ExceptionHandling/AbpExceptionWrapResultFilter.cs @@ -66,15 +66,15 @@ public class AbpExceptionWrapResultFilter : AbpExceptionFilter, ITransientDepend { var statusCodFinder = context.GetRequiredService(); var exceptionWrapHandler = context.GetRequiredService(); - + var exceptionWrapContext = new ExceptionWrapContext( context.Exception, remoteServiceErrorInfo, context.HttpContext.RequestServices, statusCodFinder.GetStatusCode(context.HttpContext, context.Exception)); - + exceptionWrapHandler.CreateFor(exceptionWrapContext).Wrap(exceptionWrapContext); - + context.Result = new ObjectResult(new WrapResult( exceptionWrapContext.ErrorInfo.Code, exceptionWrapContext.ErrorInfo.Message, diff --git a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/Filters/AbpWrapResultFilter.cs b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/Filters/AbpWrapResultFilter.cs index a86a86a..13b3b55 100644 --- a/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/Filters/AbpWrapResultFilter.cs +++ b/modules/mvc/Sanhe.Abp.AspNetCore.Mvc.Wrapper/Sanhe/Abp/AspNetCore/Mvc/Wrapper/Filters/AbpWrapResultFilter.cs @@ -1,7 +1,7 @@ -using Sanhe.Abp.AspNetCore.Mvc.Wrapper.Wraping; -using Sanhe.Abp.Wrapper; -using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; +using Sanhe.Abp.AspNetCore.Mvc.Wrapper.Wraping; +using Sanhe.Abp.Wrapper; using System.Threading.Tasks; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.DependencyInjection; diff --git a/services/book-store/Data/IdentityServerDataSeedContributor.cs b/services/book-store/Data/IdentityServerDataSeedContributor.cs index efd3d57..2a41710 100644 --- a/services/book-store/Data/IdentityServerDataSeedContributor.cs +++ b/services/book-store/Data/IdentityServerDataSeedContributor.cs @@ -70,7 +70,7 @@ public class IdentityServerDataSeedContributor : IDataSeedContributor, ITransien private async Task CreateApiResourcesAsync() { - var commonApiUserClaims = new[] {"email", "email_verified", "name", "phone_number", "phone_number_verified", "role"}; + var commonApiUserClaims = new[] { "email", "email_verified", "name", "phone_number", "phone_number_verified", "role" }; await CreateApiResourceAsync("BookStore", commonApiUserClaims); } @@ -197,8 +197,8 @@ public class IdentityServerDataSeedContributor : IDataSeedContributor, ITransien AlwaysIncludeUserClaimsInIdToken = true, AllowOfflineAccess = true, AbsoluteRefreshTokenLifetime = 31536000, //365 days - AccessTokenLifetime = 31536000, //365 days - AuthorizationCodeLifetime = 300, + AccessTokenLifetime = 31536000, //365 days + AuthorizationCodeLifetime = 300, IdentityTokenLifetime = 300, RequireConsent = false, FrontChannelLogoutUri = frontChannelLogoutUri, diff --git a/services/book-store/Localization/BookStoreResource.cs b/services/book-store/Localization/BookStoreResource.cs index d3c5a4b..98b54cc 100644 --- a/services/book-store/Localization/BookStoreResource.cs +++ b/services/book-store/Localization/BookStoreResource.cs @@ -5,5 +5,5 @@ namespace BookStore.Localization; [LocalizationResourceName("BookStore")] public class BookStoreResource { - + } \ No newline at end of file