committed by
GitHub
137 changed files with 6458 additions and 159 deletions
@ -0,0 +1,18 @@ |
|||
## 总览 |
|||
|
|||
# [2021-03-29] |
|||
1、增加动态本地化组件支持,用于在运行时替换本地化文本,需要实现 ILocalizationStore; |
|||
|
|||
2、增加本地化文档管理项目,实现了 ILocalizationStore持久化本地资源到数据库; |
|||
使用须知: 需要先定位到 [LocalizationManagement](./aspnet-core/services/localization/LINGYUN.Abp.LocalizationManagement.HttpApi.Host) 目录下 |
|||
执行Ef迁移命令: **dotnet ef database update** |
|||
|
|||
3、增加一个dotnet-compose配置文件[docker-compose.configuration.yml](./docker-compose.configuration.yml); |
|||
|
|||
4、vueJs 增加本地化管理组件视图: views/localization-management; |
|||
|
|||
5、vueJs 用户登录后的异步等待调用修改为通过store来调用abp模块初始化事件; |
|||
|
|||
6、vueJs 修复了HttpProxy模块传递的params与data使用情况混淆的问题; |
|||
|
|||
7、同步本地化管理组件的网关路由初始化配置。 |
|||
@ -0,0 +1,91 @@ |
|||
{ |
|||
"ConnectionStrings": { |
|||
"Default": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" |
|||
}, |
|||
"CAP": { |
|||
"EventBus": { |
|||
"DefaultGroup": "Platform", |
|||
"Version": "v1", |
|||
"FailedRetryInterval": 300, |
|||
"FailedRetryCount": 10 |
|||
}, |
|||
"RabbitMQ": { |
|||
"HostName": "Your RabbitMQ server connection address", |
|||
"Port": 5672, |
|||
"UserName": "Your RabbitMQ server connection user", |
|||
"Password": "Your RabbitMQ server connection user password", |
|||
"ExchangeName": "The name of your RabbitMQ server switch", |
|||
"VirtualHost": "Name of your RabbitMQ server VirtualHost" |
|||
} |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "127.0.0.1,defaultDatabase=11", |
|||
"InstanceName": "LINGYUN.Abp.Application" |
|||
}, |
|||
"AuthServer": { |
|||
"Authority": "http://localhost:44385/", |
|||
"ApiName": "lingyun-abp-application" |
|||
} |
|||
"Serilog": { |
|||
"MinimumLevel": { |
|||
"Default": "Debug", |
|||
"Override": { |
|||
"Microsoft.EntityFrameworkCore": "Debug", |
|||
"System": "Warning", |
|||
"Microsoft": "Warning" |
|||
} |
|||
}, |
|||
"Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId" ], |
|||
"WriteTo": [ |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Debug-.log", |
|||
"restrictedToMinimumLevel": "Debug", |
|||
"rollingInterval": "Day", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Info-.log", |
|||
"restrictedToMinimumLevel": "Information", |
|||
"rollingInterval": "Day", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Warn-.log", |
|||
"restrictedToMinimumLevel": "Warning", |
|||
"rollingInterval": "Day", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Error-.log", |
|||
"restrictedToMinimumLevel": "Error", |
|||
"rollingInterval": "Day", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Fatal-.log", |
|||
"restrictedToMinimumLevel": "Fatal", |
|||
"rollingInterval": "Day", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
File diff suppressed because one or more lines are too long
@ -0,0 +1,15 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.EventBus" Version="4.2.1" /> |
|||
<PackageReference Include="Volo.Abp.Localization" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.EventBus; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpEventBusModule), |
|||
typeof(AbpLocalizationModule))] |
|||
public class AbpLocalizationDynamicModule : AbpModule |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.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,42 @@ |
|||
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 LINGYUN.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 virtual async Task<IReadOnlyList<LanguageInfo>> GetLanguagesAsync() |
|||
{ |
|||
var languages = await Store.GetLanguageListAsync(); |
|||
|
|||
if (!languages.Any()) |
|||
{ |
|||
return Options.Languages; |
|||
} |
|||
|
|||
return languages |
|||
.Distinct(new LanguageInfoComparer()) |
|||
.ToList(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,120 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Logging; |
|||
using Nito.AsyncEx; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class DynamicLocalizationResourceContributor : ILocalizationResourceContributor |
|||
{ |
|||
private ILogger _logger; |
|||
private ILocalizationSubscriber _subscriber; |
|||
|
|||
private ILocalizationStore _store; |
|||
protected ILocalizationStore Store => _store; |
|||
|
|||
private Dictionary<string, ILocalizationDictionary> _dictionaries; |
|||
|
|||
private readonly string _resourceName; |
|||
private readonly AsyncLock _asyncLock = new AsyncLock(); |
|||
|
|||
public DynamicLocalizationResourceContributor(string resourceName) |
|||
{ |
|||
_resourceName = resourceName; |
|||
} |
|||
|
|||
public virtual void Initialize(LocalizationResourceInitializationContext context) |
|||
{ |
|||
_logger = context.ServiceProvider.GetService<ILogger<DynamicLocalizationResourceContributor>>(); |
|||
|
|||
_store = context.ServiceProvider.GetRequiredService<ILocalizationStore>(); |
|||
_subscriber = context.ServiceProvider.GetRequiredService<ILocalizationSubscriber>(); |
|||
_subscriber.Subscribe(OnChanged); |
|||
} |
|||
|
|||
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() |
|||
{ |
|||
var dictionaries = _dictionaries; |
|||
if (dictionaries != null) |
|||
{ |
|||
return dictionaries; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
using (_asyncLock.Lock()) |
|||
{ |
|||
dictionaries = _dictionaries = AsyncHelper.RunSync(async () => |
|||
await Store.GetLocalizationDictionaryAsync(_resourceName)); |
|||
} |
|||
} |
|||
catch(Exception ex) |
|||
{ |
|||
// 错误不应该影响到应用程序,而是记录到日志
|
|||
_logger?.LogWarning("Failed to get localized text, error: ", ex.Message); |
|||
} |
|||
|
|||
return dictionaries; |
|||
} |
|||
|
|||
private Task OnChanged(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
if (string.Equals(_resourceName, data.ResourceName)) |
|||
{ |
|||
if (!_dictionaries.ContainsKey(data.CultureName)) |
|||
{ |
|||
// TODO: 需要处理 data.Key data.Value 空引用
|
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
_dictionaries.Add(data.CultureName, newLocalizationDictionary); |
|||
} |
|||
else |
|||
{ |
|||
// 取出当前的缓存写入到新字典进行处理
|
|||
var nowLocalizationDictionary = _dictionaries[data.CultureName]; |
|||
var dictionary = new Dictionary<string, LocalizedString>(); |
|||
nowLocalizationDictionary.Fill(dictionary); |
|||
|
|||
var existsKey = dictionary.ContainsKey(data.Key); |
|||
if (!existsKey) |
|||
{ |
|||
// 如果不存在,则新增
|
|||
dictionary.Add(data.Key, new LocalizedString(data.Key, data.Value.NormalizeLineEndings())); |
|||
} |
|||
else if (existsKey && data.IsDeleted) |
|||
{ |
|||
// 如果删掉了本地化的节点,删掉当前的缓存
|
|||
dictionary.Remove(data.Key); |
|||
} |
|||
|
|||
var newLocalizationDictionary = new StaticLocalizationDictionary(data.CultureName, dictionary); |
|||
|
|||
if (newLocalizationDictionary != null) |
|||
{ |
|||
// 重新赋值变更过的缓存
|
|||
_dictionaries[data.CultureName] = newLocalizationDictionary; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal interface ILocalizationDispatcher |
|||
{ |
|||
/// <summary>
|
|||
/// 发布变更事件
|
|||
/// </summary>
|
|||
/// <param name="data"></param>
|
|||
/// <returns></returns>
|
|||
Task DispatchAsync(LocalizedStringCacheResetEventData data); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.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,17 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
/// <summary>
|
|||
/// 本地化资源订阅
|
|||
/// </summary>
|
|||
internal interface ILocalizationSubscriber |
|||
{ |
|||
/// <summary>
|
|||
/// 订阅变更事件
|
|||
/// </summary>
|
|||
/// <param name="func"></param>
|
|||
void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.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,51 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
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,23 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
internal class LocalizationResetSynchronizer : |
|||
IDistributedEventHandler<LocalizedStringCacheResetEventData>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly ILocalizationDispatcher _dispatcher; |
|||
|
|||
public LocalizationResetSynchronizer( |
|||
ILocalizationDispatcher dispatcher) |
|||
{ |
|||
_dispatcher = dispatcher; |
|||
} |
|||
public async Task HandleEventAsync(LocalizedStringCacheResetEventData eventData) |
|||
{ |
|||
await _dispatcher.DispatchAsync(eventData); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
[ExposeServices( |
|||
typeof(ILocalizationSubscriber), |
|||
typeof(ILocalizationDispatcher), |
|||
typeof(LocalizationSubscriber))] |
|||
internal class LocalizationSubscriber : ILocalizationSubscriber, ILocalizationDispatcher, ISingletonDependency |
|||
{ |
|||
private Func<LocalizedStringCacheResetEventData, Task> _handler; |
|||
|
|||
public LocalizationSubscriber() |
|||
{ |
|||
_handler = (d) => |
|||
{ |
|||
return Task.CompletedTask; |
|||
}; |
|||
} |
|||
|
|||
public void Subscribe(Func<LocalizedStringCacheResetEventData, Task> func) |
|||
{ |
|||
_handler += func; |
|||
} |
|||
|
|||
public virtual async Task DispatchAsync(LocalizedStringCacheResetEventData data) |
|||
{ |
|||
await _handler(data); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
namespace LINGYUN.Abp.Localization.Dynamic |
|||
{ |
|||
public class LocalizedStringCacheResetEventData |
|||
{ |
|||
public bool IsDeleted { get; set; } |
|||
public string ResourceName { get; set; } |
|||
public string CultureName { get; set; } |
|||
public string Key { get; set; } |
|||
public string Value { get; set; } |
|||
public LocalizedStringCacheResetEventData() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public LocalizedStringCacheResetEventData( |
|||
string resourceName, |
|||
string cultureName, |
|||
string key, |
|||
string value) |
|||
{ |
|||
ResourceName = resourceName; |
|||
CultureName = cultureName; |
|||
Key = key; |
|||
Value = value; |
|||
|
|||
IsDeleted = false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
# LINGYUN.Abp.Localization.Dynamic |
|||
|
|||
动态本地化提供者组件,添加动态提供者可实现运行时替换本地化文本 |
|||
|
|||
需要实现 ILocalizationStore 接口 |
|||
|
|||
LocalizationManagement项目提供支持 |
|||
|
|||
|
|||
由于框架设计为延迟初始化,当某个本地化资源被使用的时候才会进行初始化 |
|||
当资源被第一次使用到的时候,才会注册动态变更事件 |
|||
详情见: [DynamicLocalizationResourceContributor](./LINGYUN/Abp/Localization/Dynamic/DynamicLocalizationResourceContributor.cs#L29-L34) |
|||
|
|||
## 配置使用 |
|||
|
|||
```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)); |
|||
}); |
|||
} |
|||
} |
|||
``` |
|||
@ -0,0 +1,42 @@ |
|||
using LINGYUN.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 LINGYUN.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,19 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Authorization" Version="4.2.1" /> |
|||
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Domain.Shared\LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using Volo.Abp.Authorization; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpAuthorizationModule), |
|||
typeof(AbpLocalizationManagementDomainSharedModule))] |
|||
public class AbpLocalizationManagementApplicationContractsModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.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,20 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.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,10 @@ |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class CreateOrUpdateTextInput |
|||
{ |
|||
[DynamicStringLength(typeof(TextConsts), nameof(TextConsts.MaxValueLength))] |
|||
public string Value { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.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,9 @@ |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class GetLanguagesInput : PagedAndSortedResultRequestDto |
|||
{ |
|||
public string Filter { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class GetResourcesInput : PagedAndSortedResultRequestDto |
|||
{ |
|||
public string Filter { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.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,24 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.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,19 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public interface ILanguageAppService : |
|||
ICrudAppService< |
|||
LanguageDto, |
|||
Guid, |
|||
GetLanguagesInput, |
|||
CreateOrUpdateLanguageInput, |
|||
CreateOrUpdateLanguageInput |
|||
> |
|||
{ |
|||
Task<ListResultDto<LanguageDto>> GetAllAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public interface IResourceAppService : |
|||
ICrudAppService< |
|||
ResourceDto, |
|||
Guid, |
|||
GetResourcesInput, |
|||
CreateOrUpdateResourceInput, |
|||
CreateOrUpdateResourceInput> |
|||
{ |
|||
Task<ListResultDto<ResourceDto>> GetAllAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public interface ITextAppService : |
|||
ICrudAppService< |
|||
TextDto, |
|||
TextDifferenceDto, |
|||
int, |
|||
GetTextsInput, |
|||
CreateTextInput, |
|||
UpdateTextInput> |
|||
{ |
|||
Task<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.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,7 @@ |
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public static class LocalizationRemoteServiceConsts |
|||
{ |
|||
public const string RemoteServiceName = "LocalizationManagement"; |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
using LINGYUN.Abp.LocalizationManagement.Localization; |
|||
using Volo.Abp.Authorization.Permissions; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.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,40 @@ |
|||
namespace LINGYUN.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,13 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.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,14 @@ |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.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,12 @@ |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace LINGYUN.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,6 @@ |
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class UpdateTextInput : CreateOrUpdateTextInput |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Ddd.Application" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Domain\LINGYUN.Abp.LocalizationManagement.Domain.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Application.Contracts\LINGYUN.Abp.LocalizationManagement.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,24 @@ |
|||
using Volo.Abp.Application; |
|||
using Volo.Abp.Modularity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.AutoMapper; |
|||
|
|||
namespace LINGYUN.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,73 @@ |
|||
using LINGYUN.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 LINGYUN.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 virtual async 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 override async 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,15 @@ |
|||
using AutoMapper; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class LocalizationManagementApplicationMapperProfile : Profile |
|||
{ |
|||
public LocalizationManagementApplicationMapperProfile() |
|||
{ |
|||
CreateMap<Language, LanguageDto>(); |
|||
CreateMap<Resource, ResourceDto>(); |
|||
CreateMap<Text, TextDto>(); |
|||
CreateMap<TextDifference, TextDifferenceDto>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
using LINGYUN.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 LINGYUN.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 virtual async 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 override async 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,73 @@ |
|||
using LINGYUN.Abp.LocalizationManagement.Permissions; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.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 virtual async Task<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input) |
|||
{ |
|||
await CheckGetPolicyAsync(); |
|||
|
|||
var text = await _textRepository.GetByCultureKeyAsync( |
|||
input.ResourceName, input.CultureName, input.Key); |
|||
|
|||
return await MapToGetOutputDtoAsync(text); |
|||
} |
|||
|
|||
public override async 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,25 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\LocalizationManagement\Localization\Resources\en.json" /> |
|||
<None Remove="LINGYUN\Abp\LocalizationManagement\Localization\Resources\zh-Hans.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="LINGYUN\Abp\LocalizationManagement\Localization\Resources\en.json" /> |
|||
<EmbeddedResource Include="LINGYUN\Abp\LocalizationManagement\Localization\Resources\zh-Hans.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Validation" Version="4.2.1" /> |
|||
<PackageReference Include="Volo.Abp.Localization" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,29 @@ |
|||
using LINGYUN.Abp.LocalizationManagement.Localization; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Validation; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.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("/LINGYUN/Abp/LocalizationManagement/Localization/Resources"); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace LINGYUN.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,9 @@ |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement.Localization |
|||
{ |
|||
[LocalizationResourceName("LocalizationManagement")] |
|||
public class LocalizationManagementResource |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
{ |
|||
"culture": "en", |
|||
"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,41 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"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 LINGYUN.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 LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public static class TextConsts |
|||
{ |
|||
public static int MaxKeyLength { get; set; } = 512; |
|||
public static int MaxValueLength { get; set; } = 2 * 1024; |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class TextDifference |
|||
{ |
|||
public int Id { get; set; } |
|||
public string CultureName { get; set; } |
|||
public string Key { get; set; } |
|||
public string Value { get; set; } |
|||
public string ResourceName { get; set; } |
|||
public string TargetCultureName { get; set; } |
|||
public string TargetValue { get; set; } |
|||
|
|||
public TextDifference() { } |
|||
public TextDifference( |
|||
int id, |
|||
string cultureName, |
|||
string key, |
|||
string value, |
|||
string targetCultureName, |
|||
string targetValue = null, |
|||
string resourceName = null) |
|||
{ |
|||
Id = id; |
|||
Key = key; |
|||
Value = value; |
|||
CultureName = cultureName; |
|||
TargetCultureName = targetCultureName; |
|||
|
|||
TargetValue = targetValue; |
|||
ResourceName = resourceName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class TextEto |
|||
{ |
|||
public string CultureName { get; set; } |
|||
public string Key { get; set; } |
|||
public string Value { get; set; } |
|||
public string ResourceName { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.AutoMapper" Version="4.2.1" /> |
|||
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\common\LINGYUN.Abp.Localization.Dynamic\LINGYUN.Abp.Localization.Dynamic.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Domain.Shared\LINGYUN.Abp.LocalizationManagement.Domain.Shared.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,44 @@ |
|||
using LINGYUN.Abp.Localization.Dynamic; |
|||
using LINGYUN.Abp.LocalizationManagement.Localization; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Domain; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.Domain.Entities.Events.Distributed; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace LINGYUN.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,17 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.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,18 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.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,45 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.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; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LINGYUN.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,11 @@ |
|||
namespace LINGYUN.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,12 @@ |
|||
using AutoMapper; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
public class LocalizationManagementDomainMapperProfile : Profile |
|||
{ |
|||
public LocalizationManagementDomainMapperProfile() |
|||
{ |
|||
CreateMap<Text, TextEto>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
using LINGYUN.Abp.Localization.Dynamic; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
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 LINGYUN.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 virtual async 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 virtual async 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 virtual async Task<bool> ResourceExistsAsync(string resourceName, CancellationToken cancellationToken = default) |
|||
{ |
|||
return await ResourceRepository.ExistsAsync(resourceName, cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
using LINGYUN.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 LINGYUN.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 virtual async Task HandleEventAsync(EntityCreatedEventData<Text> eventData) |
|||
{ |
|||
await HandleEventAsync(BuildResetEventData(eventData.Entity)); |
|||
} |
|||
|
|||
public virtual async Task HandleEventAsync(EntityUpdatedEventData<Text> eventData) |
|||
{ |
|||
await HandleEventAsync(BuildResetEventData(eventData.Entity)); |
|||
} |
|||
|
|||
public virtual async 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,28 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
|
|||
namespace LINGYUN.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,37 @@ |
|||
using JetBrains.Annotations; |
|||
using System; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace LINGYUN.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,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.1</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Domain\LINGYUN.Abp.LocalizationManagement.Domain.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,24 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace LINGYUN.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,34 @@ |
|||
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 LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreLanguageRepository : EfCoreRepository<LocalizationDbContext, Language, Guid>, |
|||
ILanguageRepository |
|||
{ |
|||
public EfCoreLanguageRepository( |
|||
IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<Language> FindByCultureNameAsync( |
|||
string cultureName, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()).Where(x => x.CultureName.Equals(cultureName)) |
|||
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
|
|||
public virtual async Task<List<Language>> GetActivedListAsync(CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()).Where(x => x.Enable) |
|||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
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 LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreResourceRepository : EfCoreRepository<LocalizationDbContext, Resource, Guid>, |
|||
IResourceRepository |
|||
{ |
|||
public EfCoreResourceRepository( |
|||
IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<bool> ExistsAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()).AnyAsync(x => x.Name.Equals(name)); |
|||
} |
|||
|
|||
public virtual async Task<Resource> FindByNameAsync( |
|||
string name, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()).Where(x => x.Name.Equals(name)) |
|||
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
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 LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreTextRepository : EfCoreRepository<LocalizationDbContext, Text, int>, |
|||
ITextRepository |
|||
{ |
|||
public EfCoreTextRepository( |
|||
IDbContextProvider<LocalizationDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async 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 virtual async 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 virtual async 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 virtual async 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 virtual async 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 virtual async 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,10 @@ |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
[ConnectionStringName(LocalizationDbProperties.ConnectionStringName)] |
|||
public interface ILocalizationDbContext : IEfCoreDbContext |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.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,99 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using System; |
|||
using Volo.Abp; |
|||
using Volo.Abp.EntityFrameworkCore.Modeling; |
|||
|
|||
namespace LINGYUN.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,18 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.EntityFrameworkCore.Modeling; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class LocalizationModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions |
|||
{ |
|||
public LocalizationModelBuilderConfigurationOptions( |
|||
[NotNull] string tablePrefix = "", |
|||
[CanBeNull] string schema = null) |
|||
: base( |
|||
tablePrefix, |
|||
schema) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net5.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="4.2.1" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.LocalizationManagement.Application.Contracts\LINGYUN.Abp.LocalizationManagement.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,42 @@ |
|||
using LINGYUN.Abp.LocalizationManagement.Localization; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
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 LINGYUN.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,62 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.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 async Task<LanguageDto> CreateAsync(CreateOrUpdateLanguageInput input) |
|||
{ |
|||
return await _service.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{id}")] |
|||
public virtual async Task DeleteAsync(Guid id) |
|||
{ |
|||
await _service.DeleteAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("all")] |
|||
public virtual async Task<ListResultDto<LanguageDto>> GetAllAsync() |
|||
{ |
|||
return await _service.GetAllAsync(); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}")] |
|||
public virtual async Task<LanguageDto> GetAsync(Guid id) |
|||
{ |
|||
return await _service.GetAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
public virtual async Task<PagedResultDto<LanguageDto>> GetListAsync(GetLanguagesInput input) |
|||
{ |
|||
return await _service.GetListAsync(input); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}")] |
|||
public virtual async Task<LanguageDto> UpdateAsync(Guid id, CreateOrUpdateLanguageInput input) |
|||
{ |
|||
return await _service.UpdateAsync(id, input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.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 async Task<ResourceDto> CreateAsync(CreateOrUpdateResourceInput input) |
|||
{ |
|||
return await _service.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{id}")] |
|||
public virtual async Task DeleteAsync(Guid id) |
|||
{ |
|||
await _service.DeleteAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("all")] |
|||
public virtual async Task<ListResultDto<ResourceDto>> GetAllAsync() |
|||
{ |
|||
return await _service.GetAllAsync(); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}")] |
|||
public virtual async Task<ResourceDto> GetAsync(Guid id) |
|||
{ |
|||
return await _service.GetAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
public virtual async Task<PagedResultDto<ResourceDto>> GetListAsync(GetResourcesInput input) |
|||
{ |
|||
return await _service.GetListAsync(input); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}")] |
|||
public virtual async Task<ResourceDto> UpdateAsync(Guid id, CreateOrUpdateResourceInput input) |
|||
{ |
|||
return await _service.UpdateAsync(id, input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.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 async Task<TextDto> CreateAsync(CreateTextInput input) |
|||
{ |
|||
return await _service.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{id}")] |
|||
public virtual async Task DeleteAsync(int id) |
|||
{ |
|||
await _service.DeleteAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}")] |
|||
public virtual async Task<TextDto> GetAsync(int id) |
|||
{ |
|||
return await _service.GetAsync(id); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("by-culture-key")] |
|||
public virtual async Task<TextDto> GetByCultureKeyAsync(GetTextByKeyInput input) |
|||
{ |
|||
return await _service.GetByCultureKeyAsync(input); |
|||
} |
|||
|
|||
[HttpGet] |
|||
public virtual async Task<PagedResultDto<TextDifferenceDto>> GetListAsync(GetTextsInput input) |
|||
{ |
|||
return await _service.GetListAsync(input); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}")] |
|||
public virtual async Task<TextDto> UpdateAsync(int id, UpdateTextInput input) |
|||
{ |
|||
return await _service.UpdateAsync(id, input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
# Localization Management |
|||
|
|||
本地化文档管理模块,因项目路径太长Windows系统不支持,项目目录取简称 lt |
|||
|
|||
## 模块说明 |
|||
|
|||
### 基础模块 |
|||
|
|||
* [LINGYUN.Abp.Localization.Dynamic](../common/LINGYUN.Abp.Localization.Dynamic/LINGYUN.Abp.Localization.Dynamic) 本地化扩展模块,增加 DynamicLocalizationResourceContributor 通过 ILocalizationStore 接口获取动态的本地化资源信息 |
|||
* [LINGYUN.Abp.LocalizationManagement.Domain.Shared](./LINGYUN.Abp.LocalizationManagement.Domain.Shared) 领域层公共模块,定义了错误代码、本地化、模块设置 |
|||
* [LINGYUN.Abp.LocalizationManagement.Domain](./LINGYUN.Abp.LocalizationManagement.Domain) 领域层模块,实现 ILocalizationStore 接口 |
|||
* [LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore](./LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore) 数据访问层模块,集成EfCore |
|||
* [LINGYUN.Abp.LocalizationManagement.Application.Contracts](./LINGYUN.Abp.LocalizationManagement.Application.Contracts) 应用服务层公共模块,定义了管理本地化对象的外部接口、权限、功能限制策略 |
|||
* [LINGYUN.Abp.LocalizationManagement.Application](./LINGYUN.Abp.LocalizationManagement.Application) 应用服务层实现,实现了本地化对象管理接口 |
|||
* [LINGYUN.Abp.LocalizationManagement.HttpApi](./LINGYUN.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对象 |
|||
|
|||
### 功能定义 |
|||
|
|||
### 配置定义 |
|||
|
|||
## 更新日志 |
|||
|
|||
Binary file not shown.
@ -0,0 +1,268 @@ |
|||
using DotNetCore.CAP; |
|||
using LINGYUN.Abp.EventBus.CAP; |
|||
using LINGYUN.Abp.ExceptionHandling; |
|||
using LINGYUN.Abp.ExceptionHandling.Emailing; |
|||
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; |
|||
using LINGYUN.Abp.MultiTenancy.DbFinder; |
|||
using Localization.Resources.AbpUi; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.DataProtection; |
|||
using Microsoft.Extensions.Caching.StackExchangeRedis; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Microsoft.OpenApi.Models; |
|||
using StackExchange.Redis; |
|||
using System; |
|||
using System.Text; |
|||
using System.Text.Encodings.Web; |
|||
using System.Text.Unicode; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Authentication.JwtBearer; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.Caching.StackExchangeRedis; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore.MySQL; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.PermissionManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Security.Encryption; |
|||
using Volo.Abp.SettingManagement.EntityFrameworkCore; |
|||
using Volo.Abp.TenantManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Threading; |
|||
using Volo.Abp.Validation.Localization; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpLocalizationManagementApplicationModule), |
|||
typeof(AbpLocalizationManagementHttpApiModule), |
|||
typeof(AbpLocalizationManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAspNetCoreMultiTenancyModule), |
|||
typeof(AbpEntityFrameworkCoreMySQLModule), |
|||
typeof(AbpTenantManagementEntityFrameworkCoreModule), |
|||
typeof(AbpSettingManagementEntityFrameworkCoreModule), |
|||
typeof(AbpPermissionManagementEntityFrameworkCoreModule), |
|||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), |
|||
typeof(AbpEmailingExceptionHandlingModule), |
|||
typeof(AbpCAPEventBusModule), |
|||
typeof(AbpDbFinderMultiTenancyModule), |
|||
typeof(AbpCachingStackExchangeRedisModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public class AbpLocalizationManagementHttpApiHostModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
PreConfigure<CapOptions>(options => |
|||
{ |
|||
options |
|||
.UseMySql(configuration.GetConnectionString("Default")) |
|||
.UseRabbitMQ(rabbitMQOptions => |
|||
{ |
|||
configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); |
|||
}) |
|||
.UseDashboard(); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
// 配置Ef
|
|||
Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.UseMySQL(); |
|||
}); |
|||
|
|||
// 解决某些不支持类型的序列化
|
|||
Configure<AbpJsonOptions>(options => |
|||
{ |
|||
options.UseHybridSerializer = true; |
|||
}); |
|||
// 中文序列化的编码问题
|
|||
Configure<AbpSystemTextJsonSerializerOptions>(options => |
|||
{ |
|||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); |
|||
}); |
|||
|
|||
// 加解密
|
|||
Configure<AbpStringEncryptionOptions>(options => |
|||
{ |
|||
var encryptionConfiguration = configuration.GetSection("Encryption"); |
|||
if (encryptionConfiguration.Exists()) |
|||
{ |
|||
options.DefaultPassPhrase = encryptionConfiguration["PassPhrase"] ?? options.DefaultPassPhrase; |
|||
options.DefaultSalt = encryptionConfiguration.GetSection("Salt").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["Salt"]) |
|||
: options.DefaultSalt; |
|||
options.InitVectorBytes = encryptionConfiguration.GetSection("InitVector").Exists() |
|||
? Encoding.ASCII.GetBytes(encryptionConfiguration["InitVector"]) |
|||
: options.InitVectorBytes; |
|||
} |
|||
}); |
|||
|
|||
// 自定义需要处理的异常
|
|||
Configure<AbpExceptionHandlingOptions>(options => |
|||
{ |
|||
// 加入需要处理的异常类型
|
|||
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>(); |
|||
options.Handlers.Add<AbpInitializationException>(); |
|||
options.Handlers.Add<ObjectDisposedException>(); |
|||
options.Handlers.Add<StackOverflowException>(); |
|||
options.Handlers.Add<OutOfMemoryException>(); |
|||
options.Handlers.Add<System.Data.Common.DbException>(); |
|||
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>(); |
|||
options.Handlers.Add<System.Data.DBConcurrencyException>(); |
|||
}); |
|||
// 自定义需要发送邮件通知的异常类型
|
|||
Configure<AbpEmailExceptionHandlingOptions>(options => |
|||
{ |
|||
// 是否发送堆栈信息
|
|||
options.SendStackTrace = true; |
|||
// 未指定异常接收者的默认接收邮件
|
|||
// 指定自己的邮件地址
|
|||
// options.DefaultReceiveEmail = "colin.in@foxmail.com";
|
|||
}); |
|||
|
|||
Configure<AbpDistributedCacheOptions>(options => |
|||
{ |
|||
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
|
|||
options.KeyPrefix = "LINGYUN.Abp.Application"; |
|||
// 滑动过期30天
|
|||
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); |
|||
// 绝对过期60天
|
|||
options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); |
|||
}); |
|||
|
|||
Configure<RedisCacheOptions>(options => |
|||
{ |
|||
var redisConfig = ConfigurationOptions.Parse(options.Configuration); |
|||
options.ConfigurationOptions = redisConfig; |
|||
options.InstanceName = configuration["Redis:InstanceName"]; |
|||
}); |
|||
|
|||
// 可以禁用多租户
|
|||
Configure<AbpMultiTenancyOptions>(options => |
|||
{ |
|||
options.IsEnabled = false; |
|||
}); |
|||
|
|||
// 添加动态本地化组件
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources.AddDynamic(); |
|||
}); |
|||
|
|||
// Swagger
|
|||
context.Services.AddSwaggerGen( |
|||
options => |
|||
{ |
|||
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Localization Management API", Version = "v1" }); |
|||
options.DocInclusionPredicate((docName, description) => true); |
|||
options.CustomSchemaIds(type => type.FullName); |
|||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|||
{ |
|||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", |
|||
Name = "Authorization", |
|||
In = ParameterLocation.Header, |
|||
Scheme = "bearer", |
|||
Type = SecuritySchemeType.Http, |
|||
BearerFormat = "JWT" |
|||
}); |
|||
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|||
{ |
|||
{ |
|||
new OpenApiSecurityScheme |
|||
{ |
|||
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } |
|||
}, |
|||
new string[] { } |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
// 默认支持的本地化语言类型
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
|||
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
|||
}); |
|||
|
|||
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|||
.AddJwtBearer(options => |
|||
{ |
|||
options.Authority = configuration["AuthServer:Authority"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.Audience = configuration["AuthServer:ApiName"]; |
|||
}); |
|||
|
|||
if (!hostingEnvironment.IsDevelopment()) |
|||
{ |
|||
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
|||
context.Services |
|||
.AddDataProtection() |
|||
.PersistKeysToStackExchangeRedis(redis, "Localization-Management-Protection-Keys"); |
|||
} |
|||
} |
|||
|
|||
//public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
|
|||
//{
|
|||
// // 注释代码取消启动时缓存本地化信息
|
|||
// var initialize = context.ServiceProvider.GetRequiredService<ILocalizationCacheInitialize>();
|
|||
// AsyncHelper.RunSync(async () => await initialize.InitializeAsync());
|
|||
//}
|
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
|
|||
// http调用链
|
|||
app.UseCorrelationId(); |
|||
// 虚拟文件系统
|
|||
app.UseVirtualFiles(); |
|||
// 本地化
|
|||
app.UseAbpRequestLocalization(); |
|||
// 多租户
|
|||
// app.UseMultiTenancy();
|
|||
//路由
|
|||
app.UseRouting(); |
|||
// 认证
|
|||
app.UseAuthentication(); |
|||
// jwt
|
|||
app.UseJwtTokenMiddleware(); |
|||
// 授权
|
|||
app.UseAuthorization(); |
|||
// Swagger
|
|||
app.UseSwagger(); |
|||
// Swagger可视化界面
|
|||
app.UseSwaggerUI(options => |
|||
{ |
|||
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support Localization Management API"); |
|||
}); |
|||
// 审计日志
|
|||
app.UseAuditing(); |
|||
// 路由
|
|||
app.UseConfiguredEndpoints(); |
|||
|
|||
if (env.IsDevelopment()) |
|||
{ |
|||
AsyncHelper.RunSync(async () => |
|||
await app.ApplicationServices.GetRequiredService<IDataSeeder>() |
|||
.SeedAsync()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
FROM mcr.microsoft.com/dotnet/aspnet:5.0 |
|||
LABEL maintainer="colin.in@foxmail.com" |
|||
WORKDIR /app |
|||
|
|||
COPY . /app |
|||
|
|||
ENV TZ=Asia/Shanghai |
|||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone |
|||
|
|||
EXPOSE 80/tcp |
|||
VOLUME [ "./app/Logs" ] |
|||
|
|||
ENTRYPOINT ["dotnet", "LINGYUN.Abp.LocalizationManagement.HttpApi.Host.dll"] |
|||
@ -0,0 +1,22 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class LocalizationManagementHttpApiHostMigrationsDbContext : AbpDbContext<LocalizationManagementHttpApiHostMigrationsDbContext> |
|||
{ |
|||
public LocalizationManagementHttpApiHostMigrationsDbContext( |
|||
DbContextOptions<LocalizationManagementHttpApiHostMigrationsDbContext> options) |
|||
: base(options) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|||
{ |
|||
base.OnModelCreating(modelBuilder); |
|||
|
|||
modelBuilder.ConfigureLocalization(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Design; |
|||
using Microsoft.Extensions.Configuration; |
|||
using System.IO; |
|||
|
|||
namespace LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore |
|||
{ |
|||
public class LocalizationManagementHttpApiHostMigrationsDbContextFactory : IDesignTimeDbContextFactory<LocalizationManagementHttpApiHostMigrationsDbContext> |
|||
{ |
|||
public LocalizationManagementHttpApiHostMigrationsDbContext CreateDbContext(string[] args) |
|||
{ |
|||
var configuration = BuildConfiguration(); |
|||
var connectionString = configuration.GetConnectionString("Default"); |
|||
|
|||
var builder = new DbContextOptionsBuilder<LocalizationManagementHttpApiHostMigrationsDbContext>() |
|||
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); |
|||
|
|||
return new LocalizationManagementHttpApiHostMigrationsDbContext(builder.Options); |
|||
} |
|||
|
|||
private static IConfigurationRoot BuildConfiguration() |
|||
{ |
|||
var builder = new ConfigurationBuilder() |
|||
.SetBasePath(Directory.GetCurrentDirectory()) |
|||
.AddJsonFile("appsettings.Development.json", optional: false); |
|||
|
|||
return builder.Build(); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue