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