From d9b68954c171bfb2e68ea2568e3827ab120e30f0 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 18 Mar 2021 20:40:22 +0800 Subject: [PATCH 1/6] Upgrade bootstrap to 4.6 & bootstrap-v4-rtl to 4.6.0-1. --- npm/packs/bootstrap/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/packs/bootstrap/package.json b/npm/packs/bootstrap/package.json index 98e3516d53..8ae3b42e8e 100644 --- a/npm/packs/bootstrap/package.json +++ b/npm/packs/bootstrap/package.json @@ -6,8 +6,8 @@ }, "dependencies": { "@abp/core": "~4.2.2", - "bootstrap": "^4.5.0", - "bootstrap-v4-rtl": "4.4.1-2" + "bootstrap": "^4.6.0", + "bootstrap-v4-rtl": "4.6.0-1" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } From ff11212f40c98e4e1f3e06891681c7c36a560774 Mon Sep 17 00:00:00 2001 From: enisn Date: Fri, 19 Mar 2021 16:24:31 +0300 Subject: [PATCH 2/6] CmsKit - Refactoring for TagAdminAppService --- ...CmsKitAdminApplicationAutoMapperProfile.cs | 2 + .../CmsKit/Admin/Tags/TagAdminAppService.cs | 72 ++++++++++--------- .../Volo/CmsKit/Tags/TagDto.cs | 2 +- .../Volo/CmsKit/Tags/ITagRepository.cs | 4 ++ .../Volo/CmsKit/Tags/EfCoreTagRepository.cs | 28 ++++++-- .../CmsKit/MongoDB/Tags/MongoTagRepository.cs | 31 +++++++- 6 files changed, 98 insertions(+), 41 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs index a2615292f0..125c8f293c 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/CmsKitAdminApplicationAutoMapperProfile.cs @@ -34,6 +34,8 @@ namespace Volo.CmsKit.Admin CreateMap(MemberList.Destination); + CreateMap(); + CreateMap(); } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs index 5d4a9b03e0..da30721267 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Tags/TagAdminAppService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; using Volo.CmsKit.Permissions; @@ -12,39 +13,27 @@ using Volo.CmsKit.Tags; namespace Volo.CmsKit.Admin.Tags { [Authorize(CmsKitAdminPermissions.Tags.Default)] - public class TagAdminAppService : - CrudAppService< - Tag, - TagDto, - Guid, - TagGetListInput, - TagCreateDto, - TagUpdateDto>, - ITagAdminAppService + public class TagAdminAppService : CmsKitAppServiceBase, ITagAdminAppService { + protected ITagRepository Repository { get; } protected TagManager TagManager { get; } protected ITagDefinitionStore TagDefinitionStore { get; } protected IStringLocalizerFactory StringLocalizerFactory { get; } public TagAdminAppService( - IRepository repository, + ITagRepository repository, TagManager tagManager, ITagDefinitionStore tagDefinitionStore, - IStringLocalizerFactory stringLocalizerFactory) : base(repository) + IStringLocalizerFactory stringLocalizerFactory) { + Repository = repository; TagManager = tagManager; TagDefinitionStore = tagDefinitionStore; StringLocalizerFactory = stringLocalizerFactory; - - GetListPolicyName = CmsKitAdminPermissions.Tags.Default; - GetPolicyName = CmsKitAdminPermissions.Tags.Default; - CreatePolicyName = CmsKitAdminPermissions.Tags.Create; - UpdatePolicyName = CmsKitAdminPermissions.Tags.Update; - DeletePolicyName = CmsKitAdminPermissions.Tags.Delete; } [Authorize(CmsKitAdminPermissions.Tags.Create)] - public override async Task CreateAsync(TagCreateDto input) + public async Task CreateAsync(TagCreateDto input) { var tag = await TagManager.CreateAsync( GuidGenerator.Create(), @@ -53,11 +42,11 @@ namespace Volo.CmsKit.Admin.Tags await Repository.InsertAsync(tag); - return await MapToGetOutputDtoAsync(tag); + return ObjectMapper.Map(tag); } [Authorize(CmsKitAdminPermissions.Tags.Update)] - public override async Task UpdateAsync(Guid id, TagUpdateDto input) + public async Task UpdateAsync(Guid id, TagUpdateDto input) { var tag = await TagManager.UpdateAsync( id, @@ -65,31 +54,48 @@ namespace Volo.CmsKit.Admin.Tags await Repository.UpdateAsync(tag); - return await MapToGetOutputDtoAsync(tag); - } - - protected override async Task> CreateFilteredQueryAsync(TagGetListInput input) - { - return (await base.CreateFilteredQueryAsync(input)) - .WhereIf( - !input.Filter.IsNullOrEmpty(), - x => - x.Name.ToLower().Contains(input.Filter) || - x.EntityType.ToLower().Contains(input.Filter)); + return ObjectMapper.Map(tag); } + [Authorize(CmsKitAdminPermissions.Tags.Default)] public virtual async Task> GetTagDefinitionsAsync() { var definitions = await TagDefinitionStore.GetTagEntityTypeDefinitionListAsync(); return definitions - .Select(s => + .Select(s => new TagDefinitionDto { - EntityType = s.EntityType, + EntityType = s.EntityType, DisplayName = s.DisplayName?.Localize(StringLocalizerFactory) ?? s.EntityType }) .ToList(); } + + [Authorize(CmsKitAdminPermissions.Tags.Default)] + public async Task GetAsync(Guid id) + { + var tag = await Repository.GetAsync(id); + + return ObjectMapper.Map(tag); + } + + [Authorize(CmsKitAdminPermissions.Tags.Default)] + public async Task> GetListAsync(TagGetListInput input) + { + var tags = await Repository.GetListAsync(input.Filter); + var count = await Repository.GetCountAsync(input.Filter); + + return new PagedResultDto( + count, + ObjectMapper.Map, List>(tags) + ); + } + + [Authorize(CmsKitAdminPermissions.Tags.Delete)] + public async Task DeleteAsync(Guid id) + { + await Repository.DeleteAsync(id); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/TagDto.cs b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/TagDto.cs index ab9114919c..b9bffe880b 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/TagDto.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Common.Application.Contracts/Volo/CmsKit/Tags/TagDto.cs @@ -8,6 +8,6 @@ namespace Volo.CmsKit.Tags { public string EntityType { get; set; } - public string Name { get; protected set; } + public string Name { get; set; } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs index b45bd30db7..a399a662db 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Tags/ITagRepository.cs @@ -24,6 +24,10 @@ namespace Volo.CmsKit.Tags [NotNull] string name, CancellationToken cancellationToken = default); + Task> GetListAsync(string filter); + + Task GetCountAsync(string filter); + Task> GetAllRelatedTagsAsync( [NotNull] string entityType, [NotNull] string entityId, diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs index bc33e4f660..f22da7bce7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs @@ -25,7 +25,7 @@ namespace Volo.CmsKit.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(name, nameof(name)); - + return await (await GetDbSetAsync()).AnyAsync(x => x.EntityType == entityType && x.Name == name, @@ -39,7 +39,7 @@ namespace Volo.CmsKit.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(name, nameof(name)); - + return GetAsync(x => x.EntityType == entityType && x.Name == name, @@ -53,7 +53,7 @@ namespace Volo.CmsKit.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(name, nameof(name)); - + return FindAsync(x => x.EntityType == entityType && x.Name == name, @@ -67,7 +67,7 @@ namespace Volo.CmsKit.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityId, nameof(entityId)); - + var entityTagIds = await (await GetDbContextAsync()).Set() .Where(q => q.EntityId == entityId) .Select(q => q.TagId) @@ -79,5 +79,25 @@ namespace Volo.CmsKit.Tags return await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); } + + public async Task> GetListAsync(string filter) + { + return await (await GetQueryableByFilterAsync(filter)).ToListAsync(); + } + + public async Task GetCountAsync(string filter) + { + return await (await GetQueryableByFilterAsync(filter)).CountAsync(); + } + + private async Task> GetQueryableByFilterAsync(string filter) + { + return (await GetQueryableAsync()) + .WhereIf( + !filter.IsNullOrEmpty(), + x => + x.Name.ToLower().Contains(filter) || + x.EntityType.ToLower().Contains(filter)); + } } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs index bb35a19075..7452709bfd 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Tags/MongoTagRepository.cs @@ -26,7 +26,7 @@ namespace Volo.CmsKit.MongoDB.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(name, nameof(name)); - + return await (await GetMongoQueryableAsync(cancellationToken)) .AnyAsync(x => x.EntityType == entityType && @@ -52,7 +52,7 @@ namespace Volo.CmsKit.MongoDB.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(name, nameof(name)); - + return FindAsync(x => x.EntityType == entityType && x.Name == name, @@ -66,7 +66,7 @@ namespace Volo.CmsKit.MongoDB.Tags { Check.NotNullOrEmpty(entityType, nameof(entityType)); Check.NotNullOrEmpty(entityId, nameof(entityId)); - + var entityTagIds = await (await GetDbContextAsync(cancellationToken)).EntityTags.AsQueryable() .Where(q => q.EntityId == entityId) .Select(q => q.TagId) @@ -80,5 +80,30 @@ namespace Volo.CmsKit.MongoDB.Tags var result = await query.ToListAsync(cancellationToken: GetCancellationToken(cancellationToken)); return result; } + + + public async Task> GetListAsync(string filter) + { + return await (await GetQueryableByFilterAsync(filter)).ToListAsync(); + } + + public async Task GetCountAsync(string filter) + { + return await (await GetQueryableByFilterAsync(filter)).CountAsync(); + } + + private async Task> GetQueryableByFilterAsync(string filter) + { + var mongoQueryable = await GetMongoQueryableAsync(); + + if (!filter.IsNullOrWhiteSpace()) + { + mongoQueryable = mongoQueryable.Where(x => + x.Name.ToLower().Contains(filter) || + x.EntityType.ToLower().Contains(filter)); + } + + return mongoQueryable; + } } } From 0a7543a80342871e735eea42574cae70454c8043 Mon Sep 17 00:00:00 2001 From: enisn Date: Fri, 19 Mar 2021 16:34:28 +0300 Subject: [PATCH 3/6] CmsKit - Update TagRepository Tests --- .../Volo/CmsKit/Tags/EfCoreTagRepository.cs | 4 ++-- .../Tags/TagRepository_Test.cs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs index f22da7bce7..3949ec61a4 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Tags/EfCoreTagRepository.cs @@ -96,8 +96,8 @@ namespace Volo.CmsKit.Tags .WhereIf( !filter.IsNullOrEmpty(), x => - x.Name.ToLower().Contains(filter) || - x.EntityType.ToLower().Contains(filter)); + x.Name.ToLower().Contains(filter.ToLower()) || + x.EntityType.ToLower().Contains(filter.ToLower())); } } } diff --git a/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/TagRepository_Test.cs b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/TagRepository_Test.cs index 18cc12df68..97034f9f21 100644 --- a/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/TagRepository_Test.cs +++ b/modules/cms-kit/test/Volo.CmsKit.TestBase/Tags/TagRepository_Test.cs @@ -112,5 +112,22 @@ namespace Volo.CmsKit.Tags tags.Count.ShouldBe(0); } + + [Fact] + public async Task Should_GetList_With_Filter() + { + var tags = await _tagRepository.GetListAsync(_cmsKitTestData.TagName_1); + + tags.ShouldNotBeNull(); + tags.Count.ShouldBe(1); + } + + [Fact] + public async Task Should_GetCount_With_Filter() + { + var count = await _tagRepository.GetCountAsync(_cmsKitTestData.TagName_1); + + count.ShouldBe(1); + } } } \ No newline at end of file From 72770f68a1481bfadddd71bda0d91cea504a5b5c Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 19 Mar 2021 22:45:13 +0800 Subject: [PATCH 4/6] Store jqXHR in promise object. Resolve #8139 --- npm/packs/jquery/src/abp.jquery.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/npm/packs/jquery/src/abp.jquery.js b/npm/packs/jquery/src/abp.jquery.js index 77537c2406..6f8f5b20ce 100644 --- a/npm/packs/jquery/src/abp.jquery.js +++ b/npm/packs/jquery/src/abp.jquery.js @@ -1,4 +1,4 @@ -var abp = abp || {}; +var abp = abp || {}; (function($) { if (!$) { @@ -99,19 +99,28 @@ options.success = undefined; options.error = undefined; - return $.Deferred(function ($dfd) { - $.ajax(options) + var xhr = null; + var promise = $.Deferred(function ($dfd) { + xhr = $.ajax(options) .done(function (data, textStatus, jqXHR) { $dfd.resolve(data); userOptions.success && userOptions.success(data); }).fail(function (jqXHR) { + if(jqXHR.status === 0 || jqXHR.statusText === 'abort') { + //ajax request is abort, ignore error handle. + return; + } if (jqXHR.getResponseHeader('_AbpErrorFormat') === 'true') { abp.ajax.handleAbpErrorResponse(jqXHR, userOptions, $dfd); } else { abp.ajax.handleNonAbpErrorResponse(jqXHR, userOptions, $dfd); } }); - }); + }).promise(); + + promise['jqXHR'] = xhr; + + return promise; }; $.extend(abp.ajax, { From 62f5a2f2154afe4285e9a514be4b0762334e9d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 22 Mar 2021 11:28:23 +0300 Subject: [PATCH 5/6] Resolved #8155: Separate cms kit npm package as admin and public. --- npm/packs/cms-kit.admin/package.json | 13 +++++++++++++ npm/packs/cms-kit.public/package.json | 11 +++++++++++ npm/packs/cms-kit/package.json | 6 ++---- 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 npm/packs/cms-kit.admin/package.json create mode 100644 npm/packs/cms-kit.public/package.json diff --git a/npm/packs/cms-kit.admin/package.json b/npm/packs/cms-kit.admin/package.json new file mode 100644 index 0000000000..c100f21d15 --- /dev/null +++ b/npm/packs/cms-kit.admin/package.json @@ -0,0 +1,13 @@ +{ + "version": "4.2.2", + "name": "@abp/cms-kit.admin", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@abp/tui-editor": "^4.2.2", + "@abp/slugify": "^4.2.2", + "@abp/uppy": "^4.2.2" + }, + "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" +} diff --git a/npm/packs/cms-kit.public/package.json b/npm/packs/cms-kit.public/package.json new file mode 100644 index 0000000000..001d8016fd --- /dev/null +++ b/npm/packs/cms-kit.public/package.json @@ -0,0 +1,11 @@ +{ + "version": "4.2.2", + "name": "@abp/cms-kit.public", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@abp/star-rating-svg": "~4.2.2" + }, + "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" +} diff --git a/npm/packs/cms-kit/package.json b/npm/packs/cms-kit/package.json index ec163279f7..d01a0cade0 100644 --- a/npm/packs/cms-kit/package.json +++ b/npm/packs/cms-kit/package.json @@ -5,10 +5,8 @@ "access": "public" }, "dependencies": { - "@abp/star-rating-svg": "~4.2.2", - "@abp/tui-editor": "^4.2.2", - "@abp/slugify": "^4.2.2", - "@abp/uppy": "^4.2.2" + "@abp/cms-kit.admin": "~4.2.2", + "@abp/cms-kit.public": "~4.2.2" }, "gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431" } From e9ae597adb5fd8417e76025d5e8f487f8628e553 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 22 Mar 2021 17:56:48 +0800 Subject: [PATCH 6/6] Add multi-lingual-entities document --- docs/en/Multi-Lingual-Entities.md | 100 +++++++++++++++++++++++++ docs/en/docs-nav.json | 4 + docs/zh-Hans/Multi-Lingual-Entities.md | 100 +++++++++++++++++++++++++ docs/zh-Hans/docs-nav.json | 4 + 4 files changed, 208 insertions(+) create mode 100644 docs/en/Multi-Lingual-Entities.md create mode 100644 docs/zh-Hans/Multi-Lingual-Entities.md diff --git a/docs/en/Multi-Lingual-Entities.md b/docs/en/Multi-Lingual-Entities.md new file mode 100644 index 0000000000..85746a3fea --- /dev/null +++ b/docs/en/Multi-Lingual-Entities.md @@ -0,0 +1,100 @@ +# Multi Lingual Entities + +ABP Framework defines two basic interfaces for Multi-Lingual entity definitions to provide a standard model for translating entities. + +## IHasMultiLingual + +`IHasMultiLingual` interface is used to mark multi lingual entities. The entities marked with `IHasMultiLingual` interface must define language-neutral information. The entities marked with `IHasMultiLingual` contains a collection of Translations which contains language-dependent information. + +Example: + +```csharp +public class Product : Entity, IMultiLingualEntity +{ + public decimal Price { get; set; } + + public ICollection Translations { get; set; } +} +``` + +## IMultiLingualTranslation + +`IMultiLingualTranslation` interface is used to mark translation of a Multi-Lingual entity. The entities marked with `IMultiLingualTranslation` interface must define language dependent information. The entities marked with `IMultiLingualTranslation` contains Language field which contains a language code for the translation. + +Example: + +```csharp +public class ProductTranslation : Entity, IMultiLingualTranslation +{ + public string Name { get; set; } + + public string Language { get; set; } +} +``` + +## Map to DTO object + +ABP provdies the [Object To Object Mapping](Object-To-Object-Mapping.md) system, you can implement the `IObjectMapper` interface to map multi lingual entities to DTOs. + +Example: + +```csharp +public class MultiLingualProductObjectMapper : IObjectMapper, ITransientDependency +{ + private readonly IMultiLingualObjectManager _multiLingualObjectManager; + + public MultiLingualProductObjectMapper(IMultiLingualObjectManager multiLingualObjectManager) + { + _multiLingualObjectManager = multiLingualObjectManager; + } + + public ProductDto Map(Product source) + { + var translation = _multiLingualObjectManager.GetTranslation(source); + + return new ProductDto + { + Price = source.Price, + Id = source.Id, + Name = translation?.Name + }; + } + + public ProductDto Map(Product source, ProductDto destination) + { + return default; + } +} + +``` + +### AutoMapper integration + +ABP provides the `CreateMultiLingualMap` extension method for mapping multilingual entities to DTOs. + +Example: + +```csharp +public class ProductProfile : Profile +{ + public ProductProfile() + { + var mapResult = this.CreateMultiLingualMap(); + } +} +``` + +`CreateMultiLingualMap` extension method returns an object of type `CreateMultiLingualMapResult` which contains `EntityMap` and `TranslationMap` fields. These fields can be used to customize multi lingual mapping. + +Example: + +```csharp +this.CreateMultiLingualMap(context) + .EntityMap.ForMember(dest => dest.ProductCount, opt => opt.MapFrom(src => src.Products.Count)); +``` + +## IMultiLingualObjectManager + +`IMultiLingualObjectManager` interface defines `GetTranslation` and `GetTranslationAsync` method to get the translation object of the entity. + +The default implementation of the `IMultiLingualObjectManager` interface finds the translation with selected UI language first. If there is no translation with selected UI language, then extension method searches for the default language setting (see [Setting](Settings.md)) and uses the translation in default language. If extension method couldn't find any translation in current UI language or default language, it uses one of the existing translations. \ No newline at end of file diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index efca73a484..ec3341c623 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -376,6 +376,10 @@ "text": "Entities & Aggregate Roots", "path": "Entities.md" }, + { + "text": "Multi-Lingual-Entities", + "path": "Multi-Lingual-Entities.md" + }, { "text": "Value Objects", "path": "Value-Objects.md" diff --git a/docs/zh-Hans/Multi-Lingual-Entities.md b/docs/zh-Hans/Multi-Lingual-Entities.md new file mode 100644 index 0000000000..2deff4e38f --- /dev/null +++ b/docs/zh-Hans/Multi-Lingual-Entities.md @@ -0,0 +1,100 @@ +# 多语言实体 + +ABP框架为多语言实体定义了两个基本接口用于翻译实体的标准模型. + +## IHasMultiLingual + +`IHasMultiLingual` 接口用于标记多语言实体. 通过 `IHasMultiLingual` 接口被标记为多语言的实体定义与语言无关的信息. 多语言实体包含翻译集合,其中包含与语言有关的信息. + +示例: + +```csharp +public class Product : Entity, IMultiLingualEntity +{ + public decimal Price { get; set; } + + public ICollection Translations { get; set; } +} +``` + +## IMultiLingualTranslation + +`IMultiLingualTranslation` 接口用于标记多语言实体的翻译. 通过 `IHasMultiLingual` 接口被标记为的翻译实体定义与语言有关的信息. 翻译实体包含 `Language` 字段,用于翻译的语言代码. + +示例: + +```csharp +public class ProductTranslation : Entity, IMultiLingualTranslation +{ + public string Name { get; set; } + + public string Language { get; set; } +} +``` + +## 映射为DTO对象 + +ABP提供了[对象到对象的映射](Object-To-Object-Mapping.md)系统,你可以通过实现 `IObjectMapper` 接口将多语言实体映射为DTO. + +示例: + +```csharp +public class MultiLingualProductObjectMapper : IObjectMapper, ITransientDependency +{ + private readonly IMultiLingualObjectManager _multiLingualObjectManager; + + public MultiLingualProductObjectMapper(IMultiLingualObjectManager multiLingualObjectManager) + { + _multiLingualObjectManager = multiLingualObjectManager; + } + + public ProductDto Map(Product source) + { + var translation = _multiLingualObjectManager.GetTranslation(source); + + return new ProductDto + { + Price = source.Price, + Id = source.Id, + Name = translation?.Name + }; + } + + public ProductDto Map(Product source, ProductDto destination) + { + return default; + } +} + +``` + +### AutoMapper集成 + +ABP提供了 `CreateMultiLingualMap` 扩展方法用于将多语言实体映射为DTO. + +示例: + +```csharp +public class ProductProfile : Profile +{ + public ProductProfile() + { + var mapResult = this.CreateMultiLingualMap(); + } +} +``` + +`CreateMultiLingualMap` 扩展方法返回了一个类型为 `CreateMultiLingualMapResult` 的对象,它包含 `EntityMap` 和 `TranslationMap` 字段. 这些字段可以用于自定义多语言映射. + +示例: + +```csharp +this.CreateMultiLingualMap(context) + .EntityMap.ForMember(dest => dest.ProductCount, opt => opt.MapFrom(src => src.Products.Count)); +``` + +## IMultiLingualObjectManager + +`IMultiLingualObjectManager` 接口定义了 `GetTranslation` 和 `GetTranslationAsync` 方法用于获取实体当前的翻译对象. + +`IMultiLingualObjectManager` 的默认实现首先使用当前的UI语言寻找翻译, 如果当前的UI语言没有对应的翻译, 那么会搜索默认语言设置(参阅[设置](Settings.md))用于寻找翻译. 如果默认语言没有对应的翻译, 那么它会返回已存在翻译集合中的第一个翻译对象. diff --git a/docs/zh-Hans/docs-nav.json b/docs/zh-Hans/docs-nav.json index 4f47dd2760..241633caf5 100644 --- a/docs/zh-Hans/docs-nav.json +++ b/docs/zh-Hans/docs-nav.json @@ -354,6 +354,10 @@ "text": "实体&聚合根", "path": "Entities.md" }, + { + "text": "多语言实体", + "path": "Multi-Lingual-Entities.md" + }, { "text": "值对象" },