24 changed files with 690 additions and 20 deletions
@ -0,0 +1,174 @@ |
|||||
|
// <auto-generated />
|
||||
|
using System; |
||||
|
using LY.MicroService.LocalizationManagement.DbMigrator.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore.Infrastructure; |
||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
#nullable disable |
||||
|
|
||||
|
namespace LY.MicroService.LocalizationManagement.DbMigrator.Migrations |
||||
|
{ |
||||
|
[DbContext(typeof(LocalizationManagementMigrationsDbContext))] |
||||
|
[Migration("20230110091142_Add-Default-Culture-Name-With-Resource-Record")] |
||||
|
partial class AddDefaultCultureNameWithResourceRecord |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder) |
||||
|
{ |
||||
|
#pragma warning disable 612, 618
|
||||
|
modelBuilder |
||||
|
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) |
||||
|
.HasAnnotation("ProductVersion", "7.0.1") |
||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64); |
||||
|
|
||||
|
modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b => |
||||
|
{ |
||||
|
b.Property<Guid>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnType("datetime(6)") |
||||
|
.HasColumnName("CreationTime"); |
||||
|
|
||||
|
b.Property<Guid?>("CreatorId") |
||||
|
.HasColumnType("char(36)") |
||||
|
.HasColumnName("CreatorId"); |
||||
|
|
||||
|
b.Property<string>("CultureName") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(20) |
||||
|
.HasColumnType("varchar(20)") |
||||
|
.HasColumnName("CultureName"); |
||||
|
|
||||
|
b.Property<string>("DisplayName") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(64) |
||||
|
.HasColumnType("varchar(64)") |
||||
|
.HasColumnName("DisplayName"); |
||||
|
|
||||
|
b.Property<bool>("Enable") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("tinyint(1)") |
||||
|
.HasDefaultValue(true); |
||||
|
|
||||
|
b.Property<string>("FlagIcon") |
||||
|
.HasMaxLength(30) |
||||
|
.HasColumnType("varchar(30)") |
||||
|
.HasColumnName("FlagIcon"); |
||||
|
|
||||
|
b.Property<DateTime?>("LastModificationTime") |
||||
|
.HasColumnType("datetime(6)") |
||||
|
.HasColumnName("LastModificationTime"); |
||||
|
|
||||
|
b.Property<Guid?>("LastModifierId") |
||||
|
.HasColumnType("char(36)") |
||||
|
.HasColumnName("LastModifierId"); |
||||
|
|
||||
|
b.Property<string>("UiCultureName") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(20) |
||||
|
.HasColumnType("varchar(20)") |
||||
|
.HasColumnName("UiCultureName"); |
||||
|
|
||||
|
b.HasKey("Id"); |
||||
|
|
||||
|
b.HasIndex("CultureName"); |
||||
|
|
||||
|
b.ToTable("AbpLocalizationLanguages", (string)null); |
||||
|
}); |
||||
|
|
||||
|
modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b => |
||||
|
{ |
||||
|
b.Property<Guid>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnType("datetime(6)") |
||||
|
.HasColumnName("CreationTime"); |
||||
|
|
||||
|
b.Property<Guid?>("CreatorId") |
||||
|
.HasColumnType("char(36)") |
||||
|
.HasColumnName("CreatorId"); |
||||
|
|
||||
|
b.Property<string>("DefaultCultureName") |
||||
|
.HasMaxLength(64) |
||||
|
.HasColumnType("varchar(64)") |
||||
|
.HasColumnName("DefaultCultureName"); |
||||
|
|
||||
|
b.Property<string>("Description") |
||||
|
.HasMaxLength(64) |
||||
|
.HasColumnType("varchar(64)") |
||||
|
.HasColumnName("Description"); |
||||
|
|
||||
|
b.Property<string>("DisplayName") |
||||
|
.HasMaxLength(64) |
||||
|
.HasColumnType("varchar(64)") |
||||
|
.HasColumnName("DisplayName"); |
||||
|
|
||||
|
b.Property<bool>("Enable") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("tinyint(1)") |
||||
|
.HasDefaultValue(true); |
||||
|
|
||||
|
b.Property<DateTime?>("LastModificationTime") |
||||
|
.HasColumnType("datetime(6)") |
||||
|
.HasColumnName("LastModificationTime"); |
||||
|
|
||||
|
b.Property<Guid?>("LastModifierId") |
||||
|
.HasColumnType("char(36)") |
||||
|
.HasColumnName("LastModifierId"); |
||||
|
|
||||
|
b.Property<string>("Name") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(50) |
||||
|
.HasColumnType("varchar(50)") |
||||
|
.HasColumnName("Name"); |
||||
|
|
||||
|
b.HasKey("Id"); |
||||
|
|
||||
|
b.HasIndex("Name"); |
||||
|
|
||||
|
b.ToTable("AbpLocalizationResources", (string)null); |
||||
|
}); |
||||
|
|
||||
|
modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b => |
||||
|
{ |
||||
|
b.Property<int>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("int"); |
||||
|
|
||||
|
b.Property<string>("CultureName") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(20) |
||||
|
.HasColumnType("varchar(20)") |
||||
|
.HasColumnName("CultureName"); |
||||
|
|
||||
|
b.Property<string>("Key") |
||||
|
.IsRequired() |
||||
|
.HasMaxLength(512) |
||||
|
.HasColumnType("varchar(512)") |
||||
|
.HasColumnName("Key"); |
||||
|
|
||||
|
b.Property<string>("ResourceName") |
||||
|
.HasColumnType("longtext"); |
||||
|
|
||||
|
b.Property<string>("Value") |
||||
|
.HasMaxLength(2048) |
||||
|
.HasColumnType("varchar(2048)") |
||||
|
.HasColumnName("Value"); |
||||
|
|
||||
|
b.HasKey("Id"); |
||||
|
|
||||
|
b.HasIndex("Key"); |
||||
|
|
||||
|
b.ToTable("AbpLocalizationTexts", (string)null); |
||||
|
}); |
||||
|
#pragma warning restore 612, 618
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
|
||||
|
#nullable disable |
||||
|
|
||||
|
namespace LY.MicroService.LocalizationManagement.DbMigrator.Migrations |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public partial class AddDefaultCultureNameWithResourceRecord : Migration |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
protected override void Up(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.AddColumn<string>( |
||||
|
name: "DefaultCultureName", |
||||
|
table: "AbpLocalizationResources", |
||||
|
type: "varchar(64)", |
||||
|
maxLength: 64, |
||||
|
nullable: true) |
||||
|
.Annotation("MySql:CharSet", "utf8mb4"); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
protected override void Down(MigrationBuilder migrationBuilder) |
||||
|
{ |
||||
|
migrationBuilder.DropColumn( |
||||
|
name: "DefaultCultureName", |
||||
|
table: "AbpLocalizationResources"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpPackageVersion)" /> |
||||
|
<PackageReference Include="Polly" Version="$(PollyPackageVersion)" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Localization.Persistence; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpLocalizationModule))] |
||||
|
public class AbpLocalizationPersistenceModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddHostedService<StaticLocalizationSaverHostService>(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Localization.Persistence; |
||||
|
|
||||
|
public class AbpLocalizationPersistenceOptions |
||||
|
{ |
||||
|
public bool SaveStaticLocalizationsToPersistence { get; set; } |
||||
|
|
||||
|
public HashSet<string> SaveToPersistenceResources { get; } |
||||
|
|
||||
|
public AbpLocalizationPersistenceOptions() |
||||
|
{ |
||||
|
SaveStaticLocalizationsToPersistence = true; |
||||
|
|
||||
|
SaveToPersistenceResources = new HashSet<string>(); |
||||
|
} |
||||
|
|
||||
|
public void AddPersistenceResource<TResource>() |
||||
|
{ |
||||
|
AddPersistenceResource(typeof(TResource)); |
||||
|
} |
||||
|
|
||||
|
public void AddPersistenceResource(Type resourceType) |
||||
|
{ |
||||
|
var resourceName = LocalizationResourceNameAttribute.GetName(resourceType); |
||||
|
if (SaveToPersistenceResources.Contains(resourceName)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
SaveToPersistenceResources.Add(resourceName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Localization.Persistence; |
||||
|
|
||||
|
public interface IStaticLocalizationSaver |
||||
|
{ |
||||
|
Task SaveAsync(); |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Localization.Persistence; |
||||
|
|
||||
|
public class StaticLocalizationSaverHostService : BackgroundService |
||||
|
{ |
||||
|
private readonly AbpLocalizationPersistenceOptions _options; |
||||
|
private readonly IStaticLocalizationSaver _staticLocalizationSaver; |
||||
|
|
||||
|
public StaticLocalizationSaverHostService( |
||||
|
IOptions<AbpLocalizationPersistenceOptions> options, |
||||
|
IStaticLocalizationSaver staticLocalizationSaver) |
||||
|
{ |
||||
|
_options = options.Value; |
||||
|
_staticLocalizationSaver = staticLocalizationSaver; |
||||
|
} |
||||
|
|
||||
|
protected async override Task ExecuteAsync(CancellationToken stoppingToken) |
||||
|
{ |
||||
|
if (_options.SaveStaticLocalizationsToPersistence) |
||||
|
{ |
||||
|
await _staticLocalizationSaver.SaveAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,41 @@ |
|||||
|
# LINGYUN.Abp.Localization.Persistence |
||||
|
|
||||
|
## 模块说明 |
||||
|
|
||||
|
本地化组件持久层模块, 引用模块可将需要的本地化文档持久化到存储设施 |
||||
|
|
||||
|
### 基础模块 |
||||
|
|
||||
|
### 高阶模块 |
||||
|
|
||||
|
### 权限定义 |
||||
|
|
||||
|
### 功能定义 |
||||
|
|
||||
|
### 配置定义 |
||||
|
|
||||
|
### 如何使用 |
||||
|
|
||||
|
|
||||
|
```csharp |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpLocalizationPersistenceModule))] |
||||
|
public class YouProjectModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpLocalizationPersistenceOptions>(options => |
||||
|
{ |
||||
|
// 启用持久化设施 |
||||
|
options.SaveStaticLocalizationsToPersistence = true; |
||||
|
|
||||
|
// 指定你的本地化资源类型, 此类型下定义的静态文档将被持久化到存储设施 |
||||
|
options.AddPersistenceResource<YouProjectResource>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
``` |
||||
|
|
||||
|
### 更新日志 |
||||
@ -0,0 +1,19 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpPackageVersion)" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Folder Include="LINGYUN\Abp\Localization\" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,92 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.LocalizationManagement; |
||||
|
|
||||
|
public class LocalizationManagementExternalContributor : ILocalizationResourceContributor |
||||
|
{ |
||||
|
public bool IsDynamic => true; |
||||
|
|
||||
|
private LocalizationResourceBase _resource; |
||||
|
private ITextRepository _textRepository; |
||||
|
private IResourceRepository _resourceRepository; |
||||
|
private ILanguageRepository _languageRepository; |
||||
|
|
||||
|
public void Initialize(LocalizationResourceInitializationContext context) |
||||
|
{ |
||||
|
_resource = context.Resource; |
||||
|
_textRepository = context.ServiceProvider.GetRequiredService<ITextRepository>(); |
||||
|
_resourceRepository = context.ServiceProvider.GetRequiredService<IResourceRepository>(); |
||||
|
_languageRepository = context.ServiceProvider.GetRequiredService<ILanguageRepository>(); |
||||
|
} |
||||
|
|
||||
|
public virtual void Fill(string cultureName, Dictionary<string, LocalizedString> dictionary) |
||||
|
{ |
||||
|
FillInternalAsync(_resource.ResourceName, cultureName, dictionary).GetAwaiter().GetResult(); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task FillAsync(string cultureName, Dictionary<string, LocalizedString> dictionary) |
||||
|
{ |
||||
|
await FillInternalAsync(_resource.ResourceName, cultureName, dictionary); |
||||
|
} |
||||
|
|
||||
|
public virtual LocalizedString GetOrNull(string cultureName, string name) |
||||
|
{ |
||||
|
return GetOrNullInternal(_resource.ResourceName, cultureName, name); |
||||
|
} |
||||
|
|
||||
|
protected virtual LocalizedString GetOrNullInternal(string resourceName, string cultureName, string name) |
||||
|
{ |
||||
|
var resource = GetResourceOrNullAsync(name).GetAwaiter().GetResult(); |
||||
|
if (resource == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
var text = _textRepository.GetByCultureKeyAsync(resourceName, cultureName, name).GetAwaiter().GetResult(); |
||||
|
if (text != null) |
||||
|
{ |
||||
|
return new LocalizedString(name, text.Value); |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IEnumerable<string>> GetSupportedCulturesAsync() |
||||
|
{ |
||||
|
var languages = await _languageRepository.GetActivedListAsync(); |
||||
|
|
||||
|
return languages |
||||
|
.Select(x => x.CultureName) |
||||
|
.ToList(); |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task FillInternalAsync(string resourceName, string cultureName, Dictionary<string, LocalizedString> dictionary) |
||||
|
{ |
||||
|
var resource = await GetResourceOrNullAsync(resourceName); |
||||
|
if (resource == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var texts = await GetTextListByResourceAsync(resourceName, cultureName); |
||||
|
|
||||
|
foreach (var text in texts) |
||||
|
{ |
||||
|
dictionary[text.Key] = new LocalizedString(text.Key, text.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task<Resource> GetResourceOrNullAsync(string resourceName) |
||||
|
{ |
||||
|
return await _resourceRepository.FindByNameAsync(resourceName); |
||||
|
} |
||||
|
|
||||
|
protected async virtual Task<List<Text>> GetTextListByResourceAsync(string resourceName, string cultureName = null) |
||||
|
{ |
||||
|
return await _textRepository.GetListAsync(resourceName, cultureName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,124 @@ |
|||||
|
using LINGYUN.Abp.Localization.Persistence; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Abp.LocalizationManagement; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class StaticLocalizationSaver : IStaticLocalizationSaver, ITransientDependency |
||||
|
{ |
||||
|
protected ILanguageRepository LanguageRepository { get; } |
||||
|
protected ITextRepository TextRepository { get; } |
||||
|
protected IResourceRepository ResourceRepository { get; } |
||||
|
protected IStringLocalizerFactory StringLocalizerFactory { get; } |
||||
|
protected AbpLocalizationOptions LocalizationOptions { get; } |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected AbpLocalizationPersistenceOptions LocalizationPersistenceOptions { get; } |
||||
|
|
||||
|
public StaticLocalizationSaver( |
||||
|
IServiceProvider serviceProvider, |
||||
|
ILanguageRepository languageRepository, |
||||
|
ITextRepository textRepository, |
||||
|
IResourceRepository resourceRepository, |
||||
|
IStringLocalizerFactory stringLocalizerFactory, |
||||
|
IOptions<AbpLocalizationOptions> localizationOptions, |
||||
|
IOptions<AbpLocalizationPersistenceOptions> localizationPersistenceOptions) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
LanguageRepository = languageRepository; |
||||
|
TextRepository = textRepository; |
||||
|
ResourceRepository = resourceRepository; |
||||
|
StringLocalizerFactory = stringLocalizerFactory; |
||||
|
LocalizationOptions = localizationOptions.Value; |
||||
|
LocalizationPersistenceOptions = localizationPersistenceOptions.Value; |
||||
|
} |
||||
|
|
||||
|
[UnitOfWork] |
||||
|
public async virtual Task SaveAsync() |
||||
|
{ |
||||
|
var insertNewTexts = new List<Text>(); |
||||
|
|
||||
|
foreach (var language in LocalizationOptions.Languages) |
||||
|
{ |
||||
|
if (await LanguageRepository.FindByCultureNameAsync(language.CultureName) == null) |
||||
|
{ |
||||
|
await LanguageRepository.InsertAsync( |
||||
|
new Language( |
||||
|
language.CultureName, |
||||
|
language.UiCultureName, |
||||
|
language.DisplayName, |
||||
|
language.FlagIcon)); |
||||
|
} |
||||
|
|
||||
|
foreach (var resource in LocalizationPersistenceOptions.SaveToPersistenceResources) |
||||
|
{ |
||||
|
using (CultureHelper.Use(language.CultureName, language.UiCultureName)) |
||||
|
{ |
||||
|
var localizationResource = LocalizationOptions.Resources.GetOrDefault(resource); |
||||
|
if (localizationResource == null) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var context = new LocalizationResourceInitializationContext(localizationResource, ServiceProvider); |
||||
|
|
||||
|
if (await ResourceRepository.FindByNameAsync(localizationResource.ResourceName) == null) |
||||
|
{ |
||||
|
await ResourceRepository.InsertAsync( |
||||
|
new Resource( |
||||
|
localizationResource.ResourceName, |
||||
|
localizationResource.ResourceName, |
||||
|
localizationResource.ResourceName, |
||||
|
localizationResource.DefaultCultureName)); |
||||
|
} |
||||
|
|
||||
|
foreach (var contributor in localizationResource.Contributors) |
||||
|
{ |
||||
|
if (contributor.IsDynamic) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
contributor.Initialize(context); |
||||
|
var fillTexts = new Dictionary<string, LocalizedString>(); |
||||
|
|
||||
|
await contributor.FillAsync(language.CultureName, fillTexts); |
||||
|
|
||||
|
var existsKeys = await TextRepository.GetExistsKeysAsync( |
||||
|
localizationResource.ResourceName, |
||||
|
language.CultureName, |
||||
|
fillTexts.Values.Select(x => x.Name)); |
||||
|
|
||||
|
var notExistsKeys = fillTexts.Values.Where(x => !existsKeys.Contains(x.Name)); |
||||
|
notExistsKeys = notExistsKeys.Where(x => !insertNewTexts.Any(t => t.Key == x.Name)); |
||||
|
|
||||
|
foreach (var notExistsKey in notExistsKeys) |
||||
|
{ |
||||
|
if (!insertNewTexts.Any(x => x.CultureName == language.CultureName && x.Key == notExistsKey.Name)) |
||||
|
{ |
||||
|
insertNewTexts.Add( |
||||
|
new Text( |
||||
|
localizationResource.ResourceName, |
||||
|
language.CultureName, |
||||
|
notExistsKey.Name, |
||||
|
notExistsKey.Value)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (insertNewTexts.Any()) |
||||
|
{ |
||||
|
await TextRepository.InsertManyAsync(insertNewTexts); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue