Abp源码分析之Abp本地化

aspnetcore mvc 实现本地化

新建mvc项目

Abp源码分析之Abp本地化

修改Program.cs

using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.Razor; using System.Globalization;  var builder = WebApplication.CreateBuilder(args);  var supportedCultures = new[] {     new CultureInfo("zh-CN"),     new CultureInfo("en-US"), }; builder.Services.Configure<RequestLocalizationOptions>(options => {     options.DefaultRequestCulture = new RequestCulture("zh-CN");     options.SupportedCultures = supportedCultures;     options.SupportedUICultures = supportedCultures; });  builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");  builder.Services.AddControllersWithViews()         .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)         .AddDataAnnotationsLocalization();  var app = builder.Build();  app.UseRequestLocalization();  if (!app.Environment.IsDevelopment()) {     app.UseExceptionHandler("/Home/Error");     app.UseHsts(); }  app.UseHttpsRedirection(); app.UseStaticFiles();  app.UseRouting();  app.UseAuthorization();  app.MapControllerRoute(     name: "default",     pattern: "{controller=Home}/{action=Index}/{id?}");   app.Run();  

跟本地化有关的代码

var supportedCultures = new[] {     new CultureInfo("zh-CN"),     new CultureInfo("en-US"), }; builder.Services.Configure<RequestLocalizationOptions>(options => {     options.DefaultRequestCulture = new RequestCulture("zh-CN");     options.SupportedCultures = supportedCultures;     options.SupportedUICultures = supportedCultures; });  builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");  builder.Services.AddControllersWithViews()         .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)         .AddDataAnnotationsLocalization(); 
app.UseRequestLocalization(); 

新建Resources目录,内容如下

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

修改Index.cshtml

@using Microsoft.Extensions.Localization @using Microsoft.AspNetCore.Mvc.Localization @using WebApplication1.Controllers  @inject IHtmlLocalizer<HomeController> HtmlLocalizer @inject IStringLocalizer<HomeController> StringLocalizer @inject IViewLocalizer ViewLocalizer  @{     ViewData["Title"] = "Home Page"; }  <div>string: @StringLocalizer["HelloWorld"]</div>  <div>html: @HtmlLocalizer["HelloWorld"]</div>  <div>view: @ViewLocalizer["HelloWorld"]</div> 

访问首页

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

使用Json资源文件

新建mvc项目

Abp源码分析之Abp本地化

安装WeihanLi.Extensions.Localization.Json包

Abp源码分析之Abp本地化

我为了研究方便,下载了源码,所以引用了源码项目,我们正式使用时只要安装nuget包就可以了

修改Program.cs

using System.Globalization; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.Razor; using WeihanLi.Extensions.Localization.Json;   var builder = WebApplication.CreateBuilder(args);  var services = builder.Services;  // Add services to the container. builder.Services.AddControllersWithViews();  var supportedCultures = new[] {     new CultureInfo("zh-CN"),     new CultureInfo("en-US"), }; services.Configure<RequestLocalizationOptions>(options => {     options.DefaultRequestCulture = new RequestCulture("zh-CN");     options.SupportedCultures = supportedCultures;     options.SupportedUICultures = supportedCultures; }); var resourcesPath = builder.Configuration.GetAppSetting("ResourcesPath") ?? "Resources"; services.AddJsonLocalization(options => {     options.ResourcesPath = resourcesPath;     // options.ResourcesPathType = ResourcesPathType.TypeBased;     options.ResourcesPathType = ResourcesPathType.CultureBased; });  services.AddControllersWithViews()     .AddMvcLocalization(options =>     {         options.ResourcesPath = resourcesPath;     }, LanguageViewLocationExpanderFormat.Suffix);  var app = builder.Build();  app.UseRequestLocalization();    // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) {     app.UseExceptionHandler("/Home/Error");     // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.     app.UseHsts(); }  app.UseHttpsRedirection(); app.UseStaticFiles();  app.UseRouting();  app.UseAuthorization();  app.MapControllerRoute(     name: "default",     pattern: "{controller=Home}/{action=Index}/{id?}");  app.Run();  

与aspnetcore原始的代码仅一下不同

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); 改为: services.AddJsonLocalization(options => {     options.ResourcesPath = resourcesPath;     // options.ResourcesPathType = ResourcesPathType.TypeBased;     options.ResourcesPathType = ResourcesPathType.CultureBased; }); 

资源文件文件目录

Abp源码分析之Abp本地化

内容:

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

源码分析

Abp源码分析之Abp本地化

就是写了一个类JsonStringLocalizerFactory实现了IStringLocalizerFactory

写了JsonStringLocalizer实现了IStringLocalizer

在JsonStringLocalizer类的GetResources中加载json文件

     private Dictionary<string, string> GetResources(string culture)     {         return _resourcesCache.GetOrAdd(culture, _ =>         {             var resourceFile = "json";             if (_resourcesPathType == ResourcesPathType.TypeBased)             {                 resourceFile = $"{culture}.json";                 if (_resourceName != null)                 {                     resourceFile = string.Join(".", _resourceName.Replace('.', Path.DirectorySeparatorChar), resourceFile);                 }             }             else             {                 resourceFile = string.Join(".",                     Path.Combine(culture, _resourceName.Replace('.', Path.DirectorySeparatorChar)), resourceFile);             }              _searchedLocation = Path.Combine(_resourcesPath, resourceFile);             Dictionary<string, string> value = null;              if (File.Exists(_searchedLocation))             {                 try                 {                     using var stream = File.OpenRead(_searchedLocation);                     value = JsonSerializer.Deserialize<Dictionary<string, string>>(stream);                 }                 catch (Exception e)                 {                     _logger.LogError(e, "Failed to get json content, path: {path}", _searchedLocation);                 }             }             else             {                 _logger.LogWarning("Resource file {path} not exists", _searchedLocation);             }              return value;         });     } 

ABP本地化

新建mvc项目 导入下面四个包

Abp源码分析之Abp本地化

## 新建BookAppWebModule.cs

using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; using Volo.Abp.Autofac; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc.Localization; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.Hosting.Internal; using BookApp.Localization;  namespace BookApp {     [DependsOn(         typeof(AbpAutofacModule),         typeof(AbpLocalizationModule),         typeof(AbpVirtualFileSystemModule),         typeof(AbpAspNetCoreMvcModule)     )]     public class BookAppWebModule: AbpModule     {         public override void PreConfigureServices(ServiceConfigurationContext context)         {             var hostingEnvironment = context.Services.GetHostingEnvironment();             var configuration = context.Services.GetConfiguration();              context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>             {                 options.AddAssemblyResource(                     typeof(BookStoreResource)                 );             });         }         public override void ConfigureServices(ServiceConfigurationContext context)         {             var hostingEnvironment = context.Services.GetHostingEnvironment();              ConfigureVirtualFileSystem(hostingEnvironment);              Configure<AbpLocalizationOptions>(options =>             {                 options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));                 options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));                 options.Languages.Add(new LanguageInfo("en", "en", "English"));                 options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));                 options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));                 options.Languages.Add(new LanguageInfo("fi", "fi", "Finnish"));                 options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));                 options.Languages.Add(new LanguageInfo("hi", "hi", "Hindi"));                 options.Languages.Add(new LanguageInfo("it", "it", "Italiano"));                 options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));                 options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));                 options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak"));                 options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));                 options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));                 options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));                 options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch"));                 options.Languages.Add(new LanguageInfo("es", "es", "Español"));                  options.Resources                     .Add<BookStoreResource>("en")                     .AddVirtualJson("/Localization/BookStore");                  options.DefaultResourceType = typeof(BookStoreResource);             });              //context.Services.AddControllersWithViews()             //    .AddMvcLocalization(options =>             //    {             //        options.ResourcesPath = "/Localization/BookStore";             //    }, LanguageViewLocationExpanderFormat.Suffix);              //Configure<AbpExceptionLocalizationOptions>(options =>             //{             //    options.MapCodeNamespace("BookStore", typeof(BookStoreResource));             //});         }          public override void OnApplicationInitialization(ApplicationInitializationContext context)         {             var app = context.GetApplicationBuilder();             var env = context.GetEnvironment();              app.UseAbpRequestLocalization();              if (env.IsDevelopment())             {                 app.UseDeveloperExceptionPage();             }              app.UseHttpsRedirection();             app.UseStaticFiles();              app.UseRouting();         }          private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)         {             Configure<AbpVirtualFileSystemOptions>(options =>             {                 options.FileSets.AddEmbedded<BookAppWebModule>();                  if (hostingEnvironment.IsDevelopment())                 {                     options.FileSets.ReplaceEmbeddedByPhysical<BookAppWebModule>(hostingEnvironment.ContentRootPath);                 }             });         }     } }  

修改Program.cs

using BookApp; using Microsoft.Extensions.DependencyInjection;  var builder = WebApplication.CreateBuilder(args);  builder.Host     .AddAppSettingsSecretsJson()     .UseAutofac();  await builder.AddApplicationAsync<BookAppWebModule>();  var app = builder.Build();  await app.InitializeApplicationAsync();  app.MapControllerRoute(     name: "default",     pattern: "{controller=Home}/{action=Index}/{id?}");  await app.RunAsync();  

新建资源文件与目录

Abp源码分析之Abp本地化

en.json内容

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

我们只用到AppName

新建BookStoreResource.cs

using Volo.Abp.Localization;  namespace BookApp.Localization;  [LocalizationResourceName("BookStore")] public class BookStoreResource {  }  

修改Index.cshtml

@using Microsoft.Extensions.Localization @using Microsoft.AspNetCore.Mvc.Localization @using BookApp.Controllers @using BookApp.Localization  @inject IHtmlLocalizer<BookStoreResource> HtmlLocalizer @inject IStringLocalizer<BookStoreResource> StringLocalizer @inject IViewLocalizer ViewLocalizer @{     ViewData["Title"] = "Home Page"; }  <div>string: @StringLocalizer["AppName"]</div>  <div>html: @HtmlLocalizer["AppName"]</div>  <div>view: @ViewLocalizer["AppName"]</div> 

显示效果

Abp源码分析之Abp本地化

Abp源码分析之Abp本地化

源码分析

AbpLocalizationModule.cs中

using Volo.Abp.Localization.Resources.AbpLocalization; using Volo.Abp.Modularity; using Volo.Abp.Settings; using Volo.Abp.Threading; using Volo.Abp.VirtualFileSystem;  namespace Volo.Abp.Localization;  [DependsOn(     typeof(AbpVirtualFileSystemModule),     typeof(AbpSettingsModule),     typeof(AbpLocalizationAbstractionsModule),     typeof(AbpThreadingModule)     )] public class AbpLocalizationModule : AbpModule {     public override void ConfigureServices(ServiceConfigurationContext context)     {         AbpStringLocalizerFactory.Replace(context.Services);          Configure<AbpVirtualFileSystemOptions>(options =>         {             options.FileSets.AddEmbedded<AbpLocalizationModule>("Volo.Abp", "Volo/Abp");         });          Configure<AbpLocalizationOptions>(options =>         {             options                 .Resources                 .Add<DefaultResource>("en");              options                 .Resources                 .Add<AbpLocalizationResource>("en")                 .AddVirtualJson("/Localization/Resources/AbpLocalization");         });     } } 

我们查看AbpStringLocalizerFactory.Replace(context.Services);的内容

    internal static void Replace(IServiceCollection services)     {         services.Replace(ServiceDescriptor.Singleton<IStringLocalizerFactory, AbpStringLocalizerFactory>());         services.AddSingleton<ResourceManagerStringLocalizerFactory>();     } 

我们发现自定义的AbpStringLocalizerFactory实现了IStringLocalizerFactory

AbpDictionaryBasedStringLocalizer实现了IStringLocalizer

Abp源码分析之Abp本地化

跟踪GetLocalizedString()

Abp源码分析之Abp本地化

在这里读取json文件

相关文章

[理解ASP.NET Core - 全球化&本地化&多语言(Globalization and Localization) ](理解ASP.NET Core - 全球化&本地化&多语言(Globalization and Localization) - xiaoxiaotank - 博客园)

作者

吴晓阳(手机:13736969112微信同号)

发表评论

相关文章