aspnetcore mvc 实现本地化
新建mvc项目
修改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目录,内容如下
修改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>
访问首页
使用Json资源文件
新建mvc项目
安装WeihanLi.Extensions.Localization.Json包
我为了研究方便,下载了源码,所以引用了源码项目,我们正式使用时只要安装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; });
资源文件文件目录
内容:
源码分析
就是写了一个类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项目 导入下面四个包
## 新建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();
新建资源文件与目录
en.json内容
我们只用到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>
显示效果
源码分析
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
跟踪GetLocalizedString()
在这里读取json文件
相关文章
[理解ASP.NET Core - 全球化&本地化&多语言(Globalization and Localization) ](理解ASP.NET Core - 全球化&本地化&多语言(Globalization and Localization) - xiaoxiaotank - 博客园)
作者
吴晓阳(手机:13736969112微信同号)