基於EF Core儲存的國際化服務

coredx發表於2024-07-11

前言

.NET 官方有一個用來管理國際化資源的擴充套件包Microsoft.Extensions.Localization,ASP.NET Core也用這個來實現國際化功能。但是這個包的翻譯資料是使用resx資原始檔來管理的,這就意味著無法動態管理。雖然官方有在文件中提供了一些第三方管理方案,但是都不太方便。其中一個是基於Json檔案的,雖然可以動態管理,但是正確的Key值有時很難猜對,特別是對於巢狀類和泛型類之類名字比較特殊的。另外兩個基於EF Core的一個只是個demo;另一個已多年未更新,且上下文生命週期和併發管理有缺陷(這個庫還是我提交pr才支援的 .NET 5)。最近專案有用到國際化功能,只好重新寫一個。

新書宣傳

有關新書的更多介紹歡迎檢視《C#與.NET6 開發從入門到實踐》上市,作者親自來打廣告了!
image

相關舊文

Asp.Net Core 混合全球化與本地化支援

正文

這個擴充套件包程式碼不多也不算複雜,主要結構參考官方內建實現。對於 .NET 5以上支援上下文工廠的版本使用上下文工廠,而對於舊版本則建立內部作用域獲取私有上下文,以此徹底避免併發問題。作用域和上下文都是需要查詢時臨時獲取和使用,查詢完資料立即銷燬避免記憶體洩漏。如果使用池化上下文工廠效能會更好。

對程式碼感興趣的朋友可以移步Github。這裡直接介紹一下基本用法。

這個庫分為三個包:抽象包定義了所需介面,實體模型包定義基本實體型別,功能包定義了服務介面的實現類和用於註冊服務的擴充套件方法。方便為分離專案的解決方案按需引用,減少無關型別的汙染。

以在ASP.NET Core中使用為例:

實體模型和上下文

public class YourLocalizationRecord : LocalizationRecord
{
    public int YourProperty { get; set; }
}

public class YourDbContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 使用預設型別。
        modelBuilder.UseLocalizationRecord();

        // 使用自定義型別,需要繼承LocalizationRecord。
        modelBuilder.UseLocalizationRecord<YourLocalizationRecord>(b =>
        {
            b.Property(r => r.ResourceCulture).HasMaxLength(32);
            b.ToTable($"{nameof(YourLocalizationRecord)}s");
        });
    }
}

服務註冊

// 對於 .NET 5 以上請使用上下文工廠。
services.AddDbContextFactoty<YourDbContext>(options => options.UseSqlite("Localization.db"));
// 或者池化工廠也是一樣的,而且更好。
services.AddPooledDbContextFactoty<YourDbContext>(options => options.UseSqlite("Localization.db"));
// 註冊一個自定義工廠服務模擬作用域上下文服務
services.AddScoped<YourDbContext>(sp => sp.GetRequiredService<IDbContextFactory<YourDbContext>>().CreateDbContext());

// 對於 .NETStandard 2.0 或 2.1 請使用上下文。
services.AddDbContext<YourDbContext>(options => options.UseSqlite("Localization.db"));

// 註冊使用預設實體型別的服務。
services.AddEntityFrameworkCoreLocalization<YourDbContext>(options =>
{
    options.ResourcesPath = "Resources";
    // 是否自動建立缺失的資源記錄
    options.CreateLocalizationResourcesIfNotExist = true;
});

//  註冊使用自定義實體型別的服務。
services.AddEntityFrameworkCoreLocalization<YourDbContext, YourLocalizationRecord>(options =>
{
    options.ResourcesPath = "Resources";
    // 是否自動建立缺失的資源記錄
    options.CreateLocalizationResourcesIfNotExist = true;
});

其他的和官方文件用法完全一致,如果需要清除快取使資源能在下次讀取時更新,可以使用服務IDynamicResourceStringLocalizerFactory。這個服務繼承自內建服務,獲取的IStringLocalizerFactory服務實際上也是IDynamicResourceStringLocalizerFactory的實現。

既然已經有上下文了,想怎麼讀寫資料應該不必多言了吧。實體類的屬性LocalizedContent就是翻譯後的文字。如果使用自動建立記錄,只需要查詢所有這個屬性為null的記錄並翻譯儲存,最後清除快取即可。

image

結語

為了實現對 .NETStantard 2.0 的相容程式碼上使用了條件編譯預處理實現一份程式碼一個專案同時編譯到所有框架,最大程度共用程式碼簡化程式碼管理。

附上國際化官方文件:使 ASP.NET Core 應用內容可本地化在本地化 ASP.NET Core 應用中為每個請求選擇語言/區域性

許可證:MIT
程式碼倉庫:CoreDX.Extensions.Localization.EntityFrameworkCore - Github
Nuget:CoreDX.Extensions.Localization.EntityFrameworkCore
Nuget:CoreDX.Extensions.Localization.EntityFrameworkCore.Abstractions
Nuget:CoreDX.Extensions.Localization.EntityFrameworkCore.Models

QQ群

讀者交流QQ群:540719365
image

歡迎讀者和廣大朋友一起交流,如發現本書錯誤也歡迎透過部落格園、QQ群等方式告知筆者。

本文地址:https://www.cnblogs.com/coredx/p/18294729.html

相關文章