mirror of https://github.com/abpframework/abp.git
committed by
GitHub
32 changed files with 75 additions and 524 deletions
@ -1,100 +0,0 @@ |
|||
# 多语言实体 |
|||
|
|||
ABP框架为多语言实体定义了两个基本接口用于翻译实体的标准模型. |
|||
|
|||
## IHasMultiLingual |
|||
|
|||
`IHasMultiLingual<TTranslation>` 接口用于标记多语言实体. 通过 `IHasMultiLingual<TTranslation>` 接口被标记为多语言的实体定义与语言无关的信息. 多语言实体包含翻译集合,其中包含与语言有关的信息. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class Product : Entity<Guid>, IMultiLingualEntity<ProductTranslation> |
|||
{ |
|||
public decimal Price { get; set; } |
|||
|
|||
public ICollection<ProductTranslation> Translations { get; set; } |
|||
} |
|||
``` |
|||
|
|||
## IMultiLingualTranslation |
|||
|
|||
`IMultiLingualTranslation` 接口用于标记多语言实体的翻译. 通过 `IHasMultiLingual<TTranslation>` 接口被标记为的翻译实体定义与语言有关的信息. 翻译实体包含 `Language` 字段,用于翻译的语言代码. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class ProductTranslation : Entity<Guid>, IMultiLingualTranslation |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Language { get; set; } |
|||
} |
|||
``` |
|||
|
|||
## 映射为DTO对象 |
|||
|
|||
ABP提供了[对象到对象的映射](Object-To-Object-Mapping.md)系统,你可以通过实现 `IObjectMapper<TSource, TDestination>` 接口将多语言实体映射为DTO. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
public class MultiLingualProductObjectMapper : IObjectMapper<Product, ProductDto>, ITransientDependency |
|||
{ |
|||
private readonly IMultiLingualObjectManager _multiLingualObjectManager; |
|||
|
|||
public MultiLingualProductObjectMapper(IMultiLingualObjectManager multiLingualObjectManager) |
|||
{ |
|||
_multiLingualObjectManager = multiLingualObjectManager; |
|||
} |
|||
|
|||
public ProductDto Map(Product source) |
|||
{ |
|||
var translation = _multiLingualObjectManager.GetTranslation<Product, ProductDto>(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<Product, ProductTranslation, ProductDto>(); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
`CreateMultiLingualMap` 扩展方法返回了一个类型为 `CreateMultiLingualMapResult` 的对象,它包含 `EntityMap` 和 `TranslationMap` 字段. 这些字段可以用于自定义多语言映射. |
|||
|
|||
示例: |
|||
|
|||
```csharp |
|||
this.CreateMultiLingualMap<Order, OrderTranslation, OrderListDto>(context) |
|||
.EntityMap.ForMember(dest => dest.ProductCount, opt => opt.MapFrom(src => src.Products.Count)); |
|||
``` |
|||
|
|||
## IMultiLingualObjectManager |
|||
|
|||
`IMultiLingualObjectManager` 接口定义了 `GetTranslation` 和 `GetTranslationAsync` 方法用于获取实体当前的翻译对象. |
|||
|
|||
`IMultiLingualObjectManager` 的默认实现首先使用当前的UI语言寻找翻译, 如果当前的UI语言没有对应的翻译, 那么会搜索默认语言设置(参阅[设置](Settings.md))用于寻找翻译. 如果默认语言没有对应的翻译, 那么它会返回已存在翻译集合中的第一个翻译对象. |
|||
@ -1,54 +0,0 @@ |
|||
using Volo.Abp.MultiLingualObject; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace AutoMapper |
|||
{ |
|||
public static class AbpAutoMapperMultiLingualDtoExtensions |
|||
{ |
|||
public static CreateMultiLingualMapResult<TSource, TTranslation, TDestination> CreateMultiLingualMap<TSource, TTranslation, TDestination>(this Profile profile) |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
where TSource : IHasMultiLingual<TTranslation> |
|||
{ |
|||
|
|||
return new( |
|||
profile.CreateMap<TSource, TDestination>().BeforeMap<AbpMultiLingualMapperAction<TSource, TTranslation, TDestination>>(), |
|||
profile.CreateMap<TTranslation, TDestination>()); |
|||
} |
|||
} |
|||
|
|||
public class AbpMultiLingualMapperAction<TSource, TTranslation, TDestination> : IMappingAction<TSource, TDestination> |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
where TSource : IHasMultiLingual<TTranslation> |
|||
{ |
|||
private readonly IMultiLingualObjectManager _multiLingualObjectManager; |
|||
|
|||
public AbpMultiLingualMapperAction(IMultiLingualObjectManager multiLingualObjectManager) |
|||
{ |
|||
_multiLingualObjectManager = multiLingualObjectManager; |
|||
} |
|||
|
|||
public void Process(TSource source, TDestination destination, ResolutionContext context) |
|||
{ |
|||
var translation = AsyncHelper.RunSync(() => _multiLingualObjectManager.GetTranslationAsync<TSource, TTranslation>(source)); |
|||
if (translation != null) |
|||
{ |
|||
context.Mapper.Map(translation, destination); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class CreateMultiLingualMapResult<TSource, TTranslation, TDestination> |
|||
{ |
|||
public IMappingExpression<TSource, TDestination> EntityMap { get; } |
|||
|
|||
public IMappingExpression<TTranslation, TDestination> TranslateMap { get; } |
|||
|
|||
public CreateMultiLingualMapResult( |
|||
IMappingExpression<TSource, TDestination> entityMap, |
|||
IMappingExpression<TTranslation, TDestination> translateMap) |
|||
{ |
|||
EntityMap = entityMap; |
|||
TranslateMap = translateMap; |
|||
} |
|||
} |
|||
} |
|||
@ -1,10 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation |
|||
{ |
|||
ICollection<TTranslation> Translations { get; set; } |
|||
} |
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IMultiLingualObjectManager |
|||
{ |
|||
TTranslation GetTranslation<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
bool fallbackToParentCultures = true, |
|||
string culture = null) |
|||
where TMultiLingual : IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation; |
|||
|
|||
Task<TTranslation> GetTranslationAsync<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
bool fallbackToParentCultures = true, |
|||
string culture = null) |
|||
where TMultiLingual : IHasMultiLingual<TTranslation> |
|||
where TTranslation : class, IMultiLingualTranslation; |
|||
} |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public interface IMultiLingualTranslation |
|||
{ |
|||
string Language { get; set; } |
|||
} |
|||
} |
|||
@ -1,11 +1,11 @@ |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpMultiLingualObjectModule : AbpModule |
|||
public class AbpMultiLingualObjectsModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IMultiLingualObject<TTranslation> |
|||
where TTranslation : class, IObjectTranslation |
|||
{ |
|||
ICollection<TTranslation> Translations { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IMultiLingualObjectManager |
|||
{ |
|||
Task<TTranslation> GetTranslationAsync<TMultiLingual, TTranslation>( |
|||
TMultiLingual multiLingual, |
|||
string culture = null, |
|||
bool fallbackToParentCultures = true) |
|||
where TMultiLingual : IMultiLingualObject<TTranslation> |
|||
where TTranslation : class, IObjectTranslation; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
public interface IObjectTranslation |
|||
{ |
|||
string Language { get; set; } |
|||
} |
|||
} |
|||
@ -1,114 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.MultiLingualObject.TestObjects; |
|||
using Volo.Abp.Testing; |
|||
using Xunit; |
|||
|
|||
namespace AutoMapper |
|||
{ |
|||
public class AbpAutoMapperMultiLingualDto_Tests : AbpIntegratedTest<AutoMapperTestModule> |
|||
{ |
|||
private readonly Volo.Abp.ObjectMapping.IObjectMapper _objectMapper; |
|||
private readonly MultiLingualBook _book; |
|||
|
|||
public AbpAutoMapperMultiLingualDto_Tests() |
|||
{ |
|||
_objectMapper = ServiceProvider.GetRequiredService<Volo.Abp.ObjectMapping.IObjectMapper>(); |
|||
|
|||
var id = Guid.NewGuid(); |
|||
_book = new MultiLingualBook(id, 100) |
|||
{ |
|||
Translations = new List<MultiLingualBookTranslation>() |
|||
}; |
|||
|
|||
var en = new MultiLingualBookTranslation |
|||
{ |
|||
Language = "en", |
|||
Name = "C# in Depth", |
|||
}; |
|||
var zh = new MultiLingualBookTranslation |
|||
{ |
|||
Language = "zh-Hans", |
|||
Name = "深入理解C#", |
|||
}; |
|||
|
|||
_book.Translations.Add(en); |
|||
_book.Translations.Add(zh); |
|||
} |
|||
|
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Current_UI_Culture() |
|||
{ |
|||
using (CultureHelper.Use("zh-Hans")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("深入理解C#"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Fallback_UI_Culture() |
|||
{ |
|||
using (CultureHelper.Use("en-us")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("C# in Depth"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Default_Language() |
|||
{ |
|||
using (CultureHelper.Use("tr")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("C# in Depth"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void NoTranslations_ShouldStillMapObject() |
|||
{ |
|||
_book.Translations.Clear(); |
|||
|
|||
using (CultureHelper.Use("tr")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBeNull(); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class BookProfile : Profile |
|||
{ |
|||
public BookProfile() |
|||
{ |
|||
var mapResult = this.CreateMultiLingualMap<MultiLingualBook, MultiLingualBookTranslation, MultiLingualBookDto>(); |
|||
|
|||
mapResult.EntityMap.ValidateMemberList(MemberList.None); |
|||
mapResult.TranslateMap.ValidateMemberList(MemberList.None); |
|||
} |
|||
} |
|||
} |
|||
@ -1,132 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.MultiLingualObject.TestObjects; |
|||
using Volo.Abp.ObjectMapping; |
|||
using Volo.Abp.Testing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
{ |
|||
public class MultiLingualObject_Tests : AbpIntegratedTest<AbpMultiLingualObjectTestModule> |
|||
{ |
|||
private readonly IObjectMapper _objectMapper; |
|||
private readonly MultiLingualBook _book; |
|||
|
|||
public MultiLingualObject_Tests() |
|||
{ |
|||
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>(); |
|||
|
|||
var id = Guid.NewGuid(); |
|||
_book = new MultiLingualBook(id, 100) |
|||
{ |
|||
Translations = new List<MultiLingualBookTranslation>() |
|||
}; |
|||
|
|||
var en = new MultiLingualBookTranslation |
|||
{ |
|||
Language = "en", |
|||
Name = "C# in Depth", |
|||
}; |
|||
var zh = new MultiLingualBookTranslation |
|||
{ |
|||
Language = "zh-Hans", |
|||
Name = "深入理解C#", |
|||
}; |
|||
|
|||
_book.Translations.Add(en); |
|||
_book.Translations.Add(zh); |
|||
} |
|||
|
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Current_UI_Culture() |
|||
{ |
|||
using (CultureHelper.Use("zh-Hans")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("深入理解C#"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Fallback_UI_Culture() |
|||
{ |
|||
using (CultureHelper.Use("en-us")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("C# in Depth"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Map_Default_Language() |
|||
{ |
|||
using (CultureHelper.Use("tr")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBe("C# in Depth"); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void NoTranslations_ShouldStillMapObject() |
|||
{ |
|||
_book.Translations.Clear(); |
|||
|
|||
using (CultureHelper.Use("tr")) |
|||
{ |
|||
var bookDto = _objectMapper.Map<MultiLingualBook, MultiLingualBookDto>(_book); |
|||
|
|||
bookDto.Name.ShouldBeNull(); |
|||
bookDto.Price.ShouldBe(_book.Price); |
|||
bookDto.Id.ShouldBe(_book.Id); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class MultiLingualBookObjectMapper : IObjectMapper<MultiLingualBook, MultiLingualBookDto>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly IMultiLingualObjectManager _multiLingualObjectManager; |
|||
|
|||
public MultiLingualBookObjectMapper(IMultiLingualObjectManager multiLingualObjectManager) |
|||
{ |
|||
_multiLingualObjectManager = multiLingualObjectManager; |
|||
} |
|||
|
|||
public MultiLingualBookDto Map(MultiLingualBook source) |
|||
{ |
|||
var translation = |
|||
_multiLingualObjectManager.GetTranslation<MultiLingualBook, MultiLingualBookTranslation>(source); |
|||
|
|||
return new MultiLingualBookDto |
|||
{ |
|||
Price = source.Price, |
|||
Id = source.Id, |
|||
Name = translation?.Name |
|||
}; |
|||
} |
|||
|
|||
public MultiLingualBookDto Map(MultiLingualBook source, MultiLingualBookDto destination) |
|||
{ |
|||
return default; |
|||
} |
|||
} |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject.TestObjects |
|||
{ |
|||
public class MultiLingualBookTranslation : IMultiLingualTranslation |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Language { get; set; } |
|||
} |
|||
} |
|||
@ -1,21 +1,20 @@ |
|||
using Autofac.Extensions.DependencyInjection; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.ObjectMapping; |
|||
using Volo.Abp.Settings; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject |
|||
namespace Volo.Abp.MultiLingualObjects |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpLocalizationModule), |
|||
typeof(AbpSettingsModule), |
|||
typeof(AbpObjectMappingModule), |
|||
typeof(AbpMultiLingualObjectModule), |
|||
typeof(AbpMultiLingualObjectsModule), |
|||
typeof(AbpTestBaseModule) |
|||
)] |
|||
public class AbpMultiLingualObjectTestModule : AbpModule |
|||
public class AbpMultiLingualObjectsTestModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -1,9 +1,9 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject.TestObjects |
|||
namespace Volo.Abp.MultiLingualObjects.TestObjects |
|||
{ |
|||
public class MultiLingualBook : IHasMultiLingual<MultiLingualBookTranslation> |
|||
public class MultiLingualBook : IMultiLingualObject<MultiLingualBookTranslation> |
|||
{ |
|||
public MultiLingualBook(Guid id, decimal price) |
|||
{ |
|||
@ -1,6 +1,6 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.MultiLingualObject.TestObjects |
|||
namespace Volo.Abp.MultiLingualObjects.TestObjects |
|||
{ |
|||
public class MultiLingualBookDto |
|||
{ |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.MultiLingualObjects.TestObjects |
|||
{ |
|||
public class MultiLingualBookTranslation : IObjectTranslation |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public string Language { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue