94 changed files with 2631 additions and 20 deletions
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -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<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources |
||||||
|
.Get<YouProjectResource>() |
||||||
|
.AddDynamic(); // 添加动态本地化文档支持 |
||||||
|
|
||||||
|
// 添加所有资源的动态文档支持,将监听所有的资源包文档变更事件 |
||||||
|
// options.Resources.AddDynamic(); |
||||||
|
|
||||||
|
// 添加所有资源的动态文档支持,忽略 IdentityResource 资源 |
||||||
|
// options.Resources.AddDynamic(typeof(IdentityResource)); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
## 注意事项 |
||||||
|
|
||||||
|
动态资源在启动时加载,如果通过LocalizationManagement模块查询,可能受后端存储资源体量影响整体启动时间 |
||||||
|
|
||||||
|
详情见: [DynamicLocalizationInitializeService](./Sanhe/Abp/Localization/Dynamic/DynamicLocalizationInitializeService.cs#L25-L38) |
@ -0,0 +1,15 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.EventBus" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -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<DynamicLocalizationInitializeService>(); |
||||||
|
} |
||||||
|
} |
@ -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<string, ILocalizationDictionary> dictionaries) |
||||||
|
{ |
||||||
|
var currentDictionaries = LocalizationDictionary |
||||||
|
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
||||||
|
|
||||||
|
currentDictionaries.AddIfNotContains(dictionaries); |
||||||
|
} |
||||||
|
} |
@ -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<List<LanguageInfo>> GetLanguageListAsync(CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new List<LanguageInfo>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<Dictionary<string, ILocalizationDictionary>> GetLocalizationDictionaryAsync(string resourceName, CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(new Dictionary<string, ILocalizationDictionary>()); |
||||||
|
} |
||||||
|
|
||||||
|
public Task<bool> ResourceExistsAsync(string resourceName, CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return Task.FromResult(false); |
||||||
|
} |
||||||
|
} |
@ -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<AbpLocalizationOptions> options) |
||||||
|
{ |
||||||
|
Store = store; |
||||||
|
Options = options.Value; |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<IReadOnlyList<LanguageInfo>> GetLanguagesAsync() |
||||||
|
{ |
||||||
|
var languages = await Store.GetLanguageListAsync(); |
||||||
|
|
||||||
|
if (!languages.Any()) |
||||||
|
{ |
||||||
|
return Options.Languages; |
||||||
|
} |
||||||
|
|
||||||
|
return languages |
||||||
|
.Distinct(new LanguageInfoComparer()) |
||||||
|
.ToList(); |
||||||
|
} |
||||||
|
} |
@ -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<AbpLocalizationOptions> localizationOptions, |
||||||
|
IOptions<AbpLocalizationDynamicOptions> 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) { } // 忽略此异常 |
||||||
|
} |
||||||
|
} |
@ -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<IOptions<AbpLocalizationDynamicOptions>>().Value; |
||||||
|
} |
||||||
|
|
||||||
|
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
||||||
|
{ |
||||||
|
GetDictionaries().GetOrDefault(cultureName)?.Fill(dictionary); |
||||||
|
} |
||||||
|
|
||||||
|
public virtual LocalizedString GetOrNull(string cultureName, string name) |
||||||
|
{ |
||||||
|
return GetDictionaries().GetOrDefault(cultureName)?.GetOrNull(name); |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual Dictionary<string, ILocalizationDictionary> GetDictionaries() |
||||||
|
{ |
||||||
|
return _options.LocalizationDictionary |
||||||
|
.GetOrAdd(_resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 获取语言列表 |
||||||
|
/// </summary> |
||||||
|
/// <param name="cancellationToken"></param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<List<LanguageInfo>> GetLanguageListAsync( |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 资源是否存在 |
||||||
|
/// </summary> |
||||||
|
/// <param name="resourceName">资源名称</param> |
||||||
|
/// <param name="cancellationToken"></param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<bool> ResourceExistsAsync( |
||||||
|
string resourceName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 获取当前资源下的本地化字典 |
||||||
|
/// </summary> |
||||||
|
/// <param name="resourceName">资源名称</param> |
||||||
|
/// <param name="cancellationToken"></param> |
||||||
|
/// <returns></returns> |
||||||
|
Task<Dictionary<string, ILocalizationDictionary>> GetLocalizationDictionaryAsync( |
||||||
|
string resourceName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Localization.Dynamic; |
||||||
|
|
||||||
|
public class LanguageInfoComparer : IEqualityComparer<LanguageInfo> |
||||||
|
{ |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Localization.Dynamic; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 本地化缓存项 |
||||||
|
/// </summary> |
||||||
|
public class LocalizationCacheItem |
||||||
|
{ |
||||||
|
public string Resource { get; set; } |
||||||
|
|
||||||
|
public string Culture { get; set; } |
||||||
|
|
||||||
|
public List<LocalizationText> Texts { get; set; } |
||||||
|
|
||||||
|
public LocalizationCacheItem() |
||||||
|
{ |
||||||
|
Texts = new List<LocalizationText>(); |
||||||
|
} |
||||||
|
|
||||||
|
public LocalizationCacheItem( |
||||||
|
string resource, |
||||||
|
string culture, |
||||||
|
List<LocalizationText> 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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.Localization.Dynamic; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 用于查找本地化字符串的字典。 |
||||||
|
/// </summary> |
||||||
|
public class LocalizationDictionary : Dictionary<string, Dictionary<string, ILocalizationDictionary>> |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -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<LocalizedStringCacheResetEventData>, |
||||||
|
ITransientDependency |
||||||
|
{ |
||||||
|
private readonly AbpLocalizationDynamicOptions _options; |
||||||
|
|
||||||
|
public LocalizationResetSynchronizer( |
||||||
|
IOptions<AbpLocalizationDynamicOptions> 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<string, LocalizedString>(); |
||||||
|
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<string, LocalizedString>(); |
||||||
|
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<string, ILocalizationDictionary> GetDictionaries(string resourceName) |
||||||
|
{ |
||||||
|
return _options.LocalizationDictionary |
||||||
|
.GetOrAdd(resourceName, () => new Dictionary<string, ILocalizationDictionary>()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
namespace Sanhe.Abp.Localization.Dynamic; |
||||||
|
|
||||||
|
public class LocalizedStringCacheResetEventData |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 是否删除 |
||||||
|
/// </summary> |
||||||
|
public bool IsDeleted { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 资源名 |
||||||
|
/// </summary> |
||||||
|
public string ResourceName { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 文化名称 |
||||||
|
/// </summary> |
||||||
|
public string CultureName { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 键 |
||||||
|
/// </summary> |
||||||
|
public string Key { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 值 |
||||||
|
/// </summary> |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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对象 |
||||||
|
|
||||||
|
### 功能定义 |
||||||
|
|
||||||
|
### 配置定义 |
||||||
|
|
||||||
|
## 更新日志 |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,20 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Authorization" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Domain.Shared\Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -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 |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class GetLanguagesInput : PagedAndSortedResultRequestDto |
||||||
|
{ |
||||||
|
public string Filter { get; set; } |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class GetResourcesInput : PagedAndSortedResultRequestDto |
||||||
|
{ |
||||||
|
public string Filter { get; set; } |
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -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; } |
||||||
|
} |
@ -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<ListResultDto<LanguageDto>> GetAllAsync(); |
||||||
|
} |
@ -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<ListResultDto<ResourceDto>> GetAllAsync(); |
||||||
|
} |
@ -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<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input); |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
using System; |
||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class LanguageDto : AuditedEntityDto<Guid> |
||||||
|
{ |
||||||
|
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; } |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public static class LocalizationRemoteServiceConsts |
||||||
|
{ |
||||||
|
public const string RemoteServiceName = "LocalizationManagement"; |
||||||
|
} |
@ -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<LocalizationManagementResource>(name); |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
using System; |
||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class ResourceDto : AuditedEntityDto<Guid> |
||||||
|
{ |
||||||
|
public bool Enable { get; set; } |
||||||
|
public string Name { get; set; } |
||||||
|
public string DisplayName { get; set; } |
||||||
|
public string Description { get; set; } |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class TextDifferenceDto : EntityDto<int> |
||||||
|
{ |
||||||
|
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; } |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
using Volo.Abp.Application.Dtos; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class TextDto : EntityDto<int> |
||||||
|
{ |
||||||
|
public string Key { get; set; } |
||||||
|
public string Value { get; set; } |
||||||
|
public string CultureName { get; set; } |
||||||
|
public string ResourceName { get; set; } |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class UpdateTextInput : CreateOrUpdateTextInput |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,20 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Domain\Sanhe.Abp.LocalizationManagement.Domain.csproj" /> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Application.Contracts\Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -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<AbpLocalizationManagementApplicationModule>(); |
||||||
|
|
||||||
|
Configure<AbpAutoMapperOptions>(options => |
||||||
|
{ |
||||||
|
options.AddProfile<LocalizationManagementApplicationMapperProfile>(validate: true); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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<ListResultDto<LanguageDto>> GetAllAsync() |
||||||
|
{ |
||||||
|
await CheckGetListPolicyAsync(); |
||||||
|
|
||||||
|
var languages = await Repository.GetListAsync(); |
||||||
|
|
||||||
|
return new ListResultDto<LanguageDto>( |
||||||
|
ObjectMapper.Map<List<Language>, List<LanguageDto>>(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<IQueryable<Language>> 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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
using AutoMapper; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class LocalizationManagementApplicationMapperProfile : Profile |
||||||
|
{ |
||||||
|
public LocalizationManagementApplicationMapperProfile() |
||||||
|
{ |
||||||
|
CreateMap<Language, LanguageDto>(); |
||||||
|
CreateMap<Resource, ResourceDto>(); |
||||||
|
CreateMap<Text, TextDto>(); |
||||||
|
CreateMap<TextDifference, TextDifferenceDto>(); |
||||||
|
} |
||||||
|
} |
@ -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<ListResultDto<ResourceDto>> GetAllAsync() |
||||||
|
{ |
||||||
|
await CheckGetListPolicyAsync(); |
||||||
|
|
||||||
|
var resources = await Repository.GetListAsync(); |
||||||
|
|
||||||
|
return new ListResultDto<ResourceDto>( |
||||||
|
ObjectMapper.Map<List<Resource>, List<ResourceDto>>(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<IQueryable<Resource>> 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; |
||||||
|
} |
||||||
|
} |
@ -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<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input) |
||||||
|
{ |
||||||
|
await CheckGetPolicyAsync(); |
||||||
|
|
||||||
|
var text = await _textRepository.GetByCultureKeyAsync( |
||||||
|
input.ResourceName, input.CultureName, input.Key); |
||||||
|
|
||||||
|
return await MapToGetOutputDtoAsync(text); |
||||||
|
} |
||||||
|
|
||||||
|
public async override Task<PagedResultDto<TextDifferenceDto>> 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<TextDifferenceDto>(count, |
||||||
|
ObjectMapper.Map<List<TextDifference>, List<TextDifferenceDto>>(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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,25 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<None Remove="Sanhe\Abp\LocalizationManagement\Localization\Resources\en.json" /> |
||||||
|
<None Remove="Sanhe\Abp\LocalizationManagement\Localization\Resources\zh-Hans.json" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\LocalizationManagement\Localization\Resources\en.json" /> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\LocalizationManagement\Localization\Resources\zh-Hans.json" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Validation" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -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<AbpVirtualFileSystemOptions>(options => |
||||||
|
{ |
||||||
|
options.FileSets.AddEmbedded<AbpLocalizationManagementDomainSharedModule>(); |
||||||
|
}); |
||||||
|
|
||||||
|
Configure<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources |
||||||
|
.Add<LocalizationManagementResource>("en") |
||||||
|
.AddVirtualJson("/Sanhe/Abp/LocalizationManagement/Localization/Resources"); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement.Localization; |
||||||
|
|
||||||
|
[LocalizationResourceName("LocalizationManagement")] |
||||||
|
public class LocalizationManagementResource |
||||||
|
{ |
||||||
|
} |
@ -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}" |
||||||
|
} |
||||||
|
} |
@ -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}" |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
namespace Sanhe.Abp.LocalizationManagement |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 文本差异 |
||||||
|
/// </summary> |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
namespace Sanhe.Abp.LocalizationManagement |
||||||
|
{ |
||||||
|
public class TextEto |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 文化名称 |
||||||
|
/// </summary> |
||||||
|
public string CultureName { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// Key |
||||||
|
/// </summary> |
||||||
|
public string Key { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// Value |
||||||
|
/// </summary> |
||||||
|
public string Value { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 资源名称 |
||||||
|
/// </summary> |
||||||
|
public string ResourceName { get; set; } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,20 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\..\common\Sanhe.Abp.Localization.Dynamic\Sanhe.Abp.Localization.Dynamic.csproj" /> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Domain.Shared\Sanhe.Abp.LocalizationManagement.Domain.Shared.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -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<AbpLocalizationManagementDomainModule>(); |
||||||
|
|
||||||
|
Configure<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources |
||||||
|
.Get<LocalizationManagementResource>() |
||||||
|
.AddDynamic(); |
||||||
|
}); |
||||||
|
|
||||||
|
Configure<AbpAutoMapperOptions>(options => |
||||||
|
{ |
||||||
|
options.AddProfile<LocalizationManagementDomainMapperProfile>(validate: true); |
||||||
|
}); |
||||||
|
|
||||||
|
// 分布式事件 |
||||||
|
//Configure<AbpDistributedEntityEventOptions>(options => |
||||||
|
//{ |
||||||
|
// options.AutoEventSelectors.Add<Text>(); |
||||||
|
// options.EtoMappings.Add<Text, TextEto>(); |
||||||
|
//}); |
||||||
|
} |
||||||
|
} |
@ -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<Language, Guid> |
||||||
|
{ |
||||||
|
Task<Language> FindByCultureNameAsync(string cultureName, CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<Language>> GetActivedListAsync(CancellationToken cancellationToken = default); |
||||||
|
} |
@ -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<Resource, Guid> |
||||||
|
{ |
||||||
|
Task<bool> ExistsAsync( |
||||||
|
string name, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<Resource> FindByNameAsync( |
||||||
|
string name, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
} |
@ -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<Text, int> |
||||||
|
{ |
||||||
|
Task<Text> GetByCultureKeyAsync( |
||||||
|
string resourceName, |
||||||
|
string cultureName, |
||||||
|
string key, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<Text>> GetListAsync( |
||||||
|
string resourceName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<Text>> GetListAsync( |
||||||
|
string resourceName, |
||||||
|
string cultureName, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<int> GetDifferenceCountAsync( |
||||||
|
string cultureName, |
||||||
|
string targetCultureName, |
||||||
|
string resourceName = null, |
||||||
|
bool? onlyNull = null, |
||||||
|
string filter = null, |
||||||
|
CancellationToken cancellationToken = default); |
||||||
|
|
||||||
|
Task<List<TextDifference>> 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); |
||||||
|
} |
@ -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<Guid>, 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; |
||||||
|
} |
||||||
|
} |
@ -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"; |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
using AutoMapper; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.LocalizationManagement; |
||||||
|
|
||||||
|
public class LocalizationManagementDomainMapperProfile : Profile |
||||||
|
{ |
||||||
|
public LocalizationManagementDomainMapperProfile() |
||||||
|
{ |
||||||
|
CreateMap<Text, TextEto>(); |
||||||
|
} |
||||||
|
} |
@ -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<List<LanguageInfo>> 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<Dictionary<string, ILocalizationDictionary>> GetLocalizationDictionaryAsync( |
||||||
|
string resourceName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
// TODO: 引用缓存? |
||||||
|
var dictionaries = new Dictionary<string, ILocalizationDictionary>(); |
||||||
|
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<string, LocalizedString>(); |
||||||
|
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<bool> ResourceExistsAsync(string resourceName, CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await ResourceRepository.ExistsAsync(resourceName, cancellationToken); |
||||||
|
} |
||||||
|
} |
@ -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<EntityCreatedEventData<Text>>, |
||||||
|
ILocalEventHandler<EntityUpdatedEventData<Text>>, |
||||||
|
ILocalEventHandler<EntityDeletedEventData<Text>>, |
||||||
|
ITransientDependency |
||||||
|
{ |
||||||
|
private readonly IDistributedEventBus _eventBus; |
||||||
|
|
||||||
|
public LocalizationSynchronizer( |
||||||
|
IDistributedEventBus eventBus) |
||||||
|
{ |
||||||
|
_eventBus = eventBus; |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task HandleEventAsync(EntityCreatedEventData<Text> eventData) |
||||||
|
{ |
||||||
|
await HandleEventAsync(BuildResetEventData(eventData.Entity)); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task HandleEventAsync(EntityUpdatedEventData<Text> eventData) |
||||||
|
{ |
||||||
|
await HandleEventAsync(BuildResetEventData(eventData.Entity)); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task HandleEventAsync(EntityDeletedEventData<Text> 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); |
||||||
|
} |
||||||
|
} |
@ -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<Guid> |
||||||
|
{ |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
@ -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<int> |
||||||
|
{ |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,19 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>net6.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Domain\Sanhe.Abp.LocalizationManagement.Domain.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -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<LocalizationDbContext>(options => |
||||||
|
{ |
||||||
|
options.AddRepository<Text, EfCoreTextRepository>(); |
||||||
|
options.AddRepository<Language, EfCoreLanguageRepository>(); |
||||||
|
options.AddRepository<Resource, EfCoreResourceRepository>(); |
||||||
|
|
||||||
|
options.AddDefaultRepositories(includeAllEntities: true); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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<LocalizationDbContext, Language, Guid>, ILanguageRepository |
||||||
|
{ |
||||||
|
public EfCoreLanguageRepository(IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<Language> FindByCultureNameAsync( |
||||||
|
string cultureName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await (await GetDbSetAsync()).Where(x => x.CultureName.Equals(cultureName)) |
||||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<List<Language>> GetActivedListAsync(CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await (await GetDbSetAsync()).Where(x => x.Enable) |
||||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||||
|
} |
||||||
|
} |
@ -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<LocalizationDbContext, Resource, Guid>, IResourceRepository |
||||||
|
{ |
||||||
|
public EfCoreResourceRepository(IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<bool> ExistsAsync( |
||||||
|
string name, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await (await GetDbSetAsync()).AnyAsync(x => x.Name.Equals(name), cancellationToken: cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<Resource> FindByNameAsync( |
||||||
|
string name, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
return await (await GetDbSetAsync()).Where(x => x.Name.Equals(name)) |
||||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||||
|
} |
||||||
|
} |
@ -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<LocalizationDbContext, Text, int>, ITextRepository |
||||||
|
{ |
||||||
|
public EfCoreTextRepository(IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public async virtual Task<Text> 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<int> 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<List<Text>> GetListAsync( |
||||||
|
string resourceName, |
||||||
|
CancellationToken cancellationToken = default) |
||||||
|
{ |
||||||
|
var languages = (await GetDbContextAsync()).Set<Language>(); |
||||||
|
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<List<Text>> 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<List<TextDifference>> 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<IQueryable<TextDifference>> 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; |
||||||
|
} |
||||||
|
} |
@ -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<Resource> Resources { get; set; } |
||||||
|
DbSet<Language> Languages { get; set; } |
||||||
|
DbSet<Text> Texts { get; set; } |
||||||
|
} |
@ -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<LocalizationDbContext>, ILocalizationDbContext |
||||||
|
{ |
||||||
|
public virtual DbSet<Resource> Resources { get; set; } |
||||||
|
public virtual DbSet<Language> Languages { get; set; } |
||||||
|
public virtual DbSet<Text> Texts { get; set; } |
||||||
|
|
||||||
|
public LocalizationDbContext(DbContextOptions<LocalizationDbContext> options) : base(options) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder) |
||||||
|
{ |
||||||
|
base.OnModelCreating(modelBuilder); |
||||||
|
|
||||||
|
modelBuilder.ConfigureLocalization(); |
||||||
|
} |
||||||
|
} |
@ -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<LocalizationModelBuilderConfigurationOptions> optionsAction = null) |
||||||
|
{ |
||||||
|
Check.NotNull(builder, nameof(builder)); |
||||||
|
|
||||||
|
var options = new LocalizationModelBuilderConfigurationOptions( |
||||||
|
LocalizationDbProperties.DbTablePrefix, |
||||||
|
LocalizationDbProperties.DbSchema |
||||||
|
); |
||||||
|
|
||||||
|
optionsAction?.Invoke(options); |
||||||
|
|
||||||
|
builder.Entity<Language>(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<Resource>(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<Text>(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); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,19 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>net6.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.LocalizationManagement.Application.Contracts\Sanhe.Abp.LocalizationManagement.Application.Contracts.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -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<AbpMvcDataAnnotationsLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.AddAssemblyResource( |
||||||
|
typeof(LocalizationManagementResource), |
||||||
|
typeof(AbpLocalizationManagementApplicationContractsModule).Assembly); |
||||||
|
}); |
||||||
|
|
||||||
|
PreConfigure<IMvcBuilder>(mvcBuilder => |
||||||
|
{ |
||||||
|
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpLocalizationManagementApplicationContractsModule).Assembly); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
Configure<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources |
||||||
|
.Get<LocalizationManagementResource>() |
||||||
|
.AddBaseTypes(typeof(AbpValidationResource)); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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<LanguageDto> 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<ListResultDto<LanguageDto>> GetAllAsync() |
||||||
|
{ |
||||||
|
return _service.GetAllAsync(); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
[Route("{id}")] |
||||||
|
public virtual Task<LanguageDto> GetAsync(Guid id) |
||||||
|
{ |
||||||
|
return _service.GetAsync(id); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
public virtual Task<PagedResultDto<LanguageDto>> GetListAsync(GetLanguagesInput input) |
||||||
|
{ |
||||||
|
return _service.GetListAsync(input); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPut] |
||||||
|
[Route("{id}")] |
||||||
|
public virtual Task<LanguageDto> UpdateAsync(Guid id, CreateOrUpdateLanguageInput input) |
||||||
|
{ |
||||||
|
return _service.UpdateAsync(id, input); |
||||||
|
} |
||||||
|
} |
@ -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<ResourceDto> 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<ListResultDto<ResourceDto>> GetAllAsync() |
||||||
|
{ |
||||||
|
return _service.GetAllAsync(); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
[Route("{id}")] |
||||||
|
public virtual Task<ResourceDto> GetAsync(Guid id) |
||||||
|
{ |
||||||
|
return _service.GetAsync(id); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
public virtual Task<PagedResultDto<ResourceDto>> GetListAsync(GetResourcesInput input) |
||||||
|
{ |
||||||
|
return _service.GetListAsync(input); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPut] |
||||||
|
[Route("{id}")] |
||||||
|
public virtual Task<ResourceDto> UpdateAsync(Guid id, CreateOrUpdateResourceInput input) |
||||||
|
{ |
||||||
|
return _service.UpdateAsync(id, input); |
||||||
|
} |
||||||
|
} |
@ -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<TextDto> 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<TextDto> GetAsync(int id) |
||||||
|
{ |
||||||
|
return _service.GetAsync(id); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
[Route("by-culture-key")] |
||||||
|
public virtual Task<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input) |
||||||
|
{ |
||||||
|
return _service.GetByCultureKeyAsync(input); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
public virtual Task<PagedResultDto<TextDifferenceDto>> GetListAsync(GetTextsInput input) |
||||||
|
{ |
||||||
|
return _service.GetListAsync(input); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPut] |
||||||
|
[Route("{id}")] |
||||||
|
public virtual Task<TextDto> UpdateAsync(int id, UpdateTextInput input) |
||||||
|
{ |
||||||
|
return _service.UpdateAsync(id, input); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue