使用XLocalizer进行ASP.NET Core本地化
目录
介绍
XLocalizer提供什么?
安装
设置XLocalizer
为翻译服务添加API密钥
完整的XLocalizer启动代码
本地化视图
本地化验证属性错误、模型绑定错误和身份错误消息
自定义错误消息
JSON设置
添加语言导航
运行应用程序
支持的.NET Core版本
支持的项目类型
参考文献
- 下载Blazor本地化示例-941.4 KB
- 下载Razor页面本地化示例-1.4 MB
介绍
开发一个多元文化的Web应用程序需要构建本地化基础结构,该基础结构将处理请求本地化并本地化视图、错误消息等。另一方面; 每个本地化区域性都至少需要一个资源文件,其中包含所有本地化的键值对。
构建本地化基础结构和填充资源文件可能会花费大量时间和精力。XLocalizer是从零开始开发的,可以解决这两个问题并使开发人员摆脱不必要的工作量。
XLocalizer提供什么?
简单的本地化设置:首先,它旨在帮助开发人员轻松创建本地化的Web应用程序,而不会浪费时间开发本地化基础结构。
自动本地化:XLocalizer最吸引人的两个功能是自动资源创建和在线翻译。因此,任何丢失的键都将被翻译并自动添加到相关的资源文件中。
支持多种资源类型:默认情况下,ASP.NET Core使用“.resx”资源文件存储本地化的字符串。XLocalizer通过提供内置的本地化存储(XML、RESX、DB)打破了障碍。此外,可以实现任何其他文件或数据库格式的自定义资源类型。
灵活性:XLocalizer使用标准的本地化接口IStringLocalizer和IHtmlLocalizer,因此很容易从默认的.NET Core本地化系统切换到XLocalizer,反之亦然。借助内置资源导出,所有本地化资源都可以从任何文件/数据库类型导出为“.resx”文件类型。
定制:XLocalizer可以对每个细节进行定制
- 使用自定义资源类型(例如mysql,json,csv等),
- 使用自定义资源导出器将资源从任何来源导出到任何来源,
- 使用定制翻译服务来翻译资源。
集中化:一个地方,以一种简单的方式轻松自定义所有验证错误,模型绑定错误和身份错误。
在本教程中,我将展示如何让带有XML资源文件的XLocalizer和在线翻译一起使用。要了解其他资源类型(如resx,db或自定义源)的设置,请访问 https://DOCS.Ziyad.info。
安装
- 要充分利用XLocalizer,需要一些细节,首先我将提及所有软件包,然后在下一步中我们将了解每个软件包的作用。
// The main package
PM > Install-Package XLocalizer// Online translation support
PM > Install-Package XLocalizer.Translate// Translation service
PM > Install-Package XLocalizer.Translate.MyMemoryTranslate// Use html tags to localize views
PM > Install-Package XLocalizer.TagHelpers// Additional taghelper package for language dropdown
PM > Install-Package LazZiya.TagHelpers
- 资源文件夹:在项目根目录下,创建一个名为“LocalizationResources”的新文件夹,然后在其中创建一个名为“LocSource”的新空类。此类将用于从代码访问相关的资源文件。
// Dummy class for grouping and accessing resource files
public class LocSource { }
无需创建区域性特定的资源文件,它们将由XLocalizer创建并自动填充。
设置XLocalizer
加速编码的小技巧;VS2019可以自动插入缺少的命名空间(使用…)。或者,您可以按(Crtl +.)查看上下文菜单,该菜单将添加缺少的命名空间。
- 打开启动文件并像往常一样配置请求本地化选项:
services.Configure<RequestLocalizationOptions>(ops =>
{var cultures = new CultureInfo[] { new CultureInfo("en"),new CultureInfo("tr"),...};ops.SupportedCultres = cultures;ops.SupportedUICultures = cultures;ops.DefaultRequestCulture = new RequestCulture("en");// Optional: add custom provider to support localization // based on route valueops.RequestCultureProviders.Insert(0, new RouteSegmentRequestCultureProvider(cultures));
});
XLocalizer支持多种资源类型,例如XML、RESX、DB等。在此示例中,我将使用XML文件存储本地化的值,因此我们需要注册内置的XmlResourceProvider,该提供程序将帮助我们将XML文件用作存储本地化的键值对的资源文件。
services.AddSingleton<IXResourceProvider, XmlResourceProvider>();
- XLocalizer在线翻译支持是它的主要好处之一,因此我们需要在启动文件中注册至少一个翻译服务。
services.AddHttpClient<ITranslator, MyMemoryTranslateService>();
我在XLocalizer开发时曾经用过MyMemoryTranslateService,但是您可以自由选择任何可用的翻译服务,甚至可以实现自己的翻译服务。
- (可选)将Razor页面配置为使用基于路由的本地化提供程序,因此我们可以使用以下网址:http://localhost:111/en/Index。然后XLocalizer在同一步骤中进行配置XLocalizer:
services.AddRazorPages().AddRazorPagesOptions(ops => {ops.Conventions.Insert(0, new RouteTemplateModelConventionRazorPages());}).AddXLocalizer<LocSource, MyMemoryTranslateService>(ops => {ops.ResourcesPath = "LocalizationResources";ops.AutoAddKeys = true;ops.AutoTranslate = true;ops.TranslateFromCulture = "en";});
- 配置应用程序以使用本地化中间件:
app.UseRequestLocalization();
为翻译服务添加API密钥
MyMemory翻译API提供免费的匿名用法,直到1000字/天(撰写本文时为止)。因此,基本上,您无需添加任何密钥即可对其进行测试。无论如何,您只需提供电子邮件和免费生成的密钥,就可以将免费使用量增加到每天30.000个单词。有关更多详细信息,请参见MyMemory API使用限制。
使用MyMemory API Keygen获取密钥,然后将具有有效电子邮件地址的密钥添加到用户机密文件中,如下所示:
{ "XLocalizer.Translate": {"MyMemory": {"Email": "...","Key": "..."}}
}
不同的翻译服务可能需要不同的设置。有关设置不同翻译服务的详细信息,请参见翻译服务文档。
完整的XLocalizer启动代码
示例启动文件,为简化起见省略了不必要的代码。
public class Startup
{ public Startup(IConfiguration configuration){Configuration = configuration;}// ...public void ConfigureServices(IServiceCollection services){// Configure request localizationservices.Configure<RequestLocalizationOptions>(ops =>{var cultures = new CultureInfo[] { new CultureInfo("en"), new CultureInfo("tr"), new CultureInfo("ar") };ops.SupportedCultures = cultures;ops.SupportedUICultures = cultures;ops.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en");ops.RequestCultureProviders.Insert(0, new RouteSegmentRequestCultureProvider(cultures));});// Register translation serviceservices.AddHttpClient<ITranslator, MyMemoryTranslateService>();// Register XmlResourceProviderservices.AddSingleton<IXResourceProvider, XmlResourceProvider>();services.AddRazorPages().AddRazorPagesOptions(ops => { ops.Conventions.Insert(0, new RouteTemplateModelConventionRazorPages()); })// Add XLocalizer.AddXLocalizer<LocSource, MyMemoryTranslateService>(ops =>{ops.ResourcesPath = "LocalizationResources";ops.AutoAddKeys = true;ops.AutoTranslate = true;// Optional: Just in case you need to change the source translation culture.// if not provided, the default culture will be usedops.TranslateFromCulture = "en";// Recommended: turn on caching during production for faster localizationops.UseExpressMemoryCache = true; });}// This method gets called by the runtime. // Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IWebHostEnvironment env){// ...// Use request localization middlewareapp.UseRequestLocalization();app.UseEndpoints(endpoints =>{endpoints.MapRazorPages();});}
}
这就是启动文件中所需的所有设置。接下来,我们将配置视图和后端本地化。
本地化视图
我们已经安装了用于本地化视图的便捷nuget XLocalizer.TagHelpers,此软件包使您可以轻松使用html标签和html属性来本地化视图,从而使html代码保持整洁并易于阅读和维护。
- 在_ViewImports.cshtml文件中添加taghelper:
@addTagHelper *, XLocalizer.TagHelpers
- 在html标记内使用localize-content属性来本地化内部文本/html:
<h1 localize-content>Welcome</h1>
- 使用localize html标记本地化text/htm段落:
<localize><h1>Welcome</h1><p>My contents...</p>
</localize>
- 使用参数本地化html字符串:
@{var args = new object[] { "http://DOCS.Ziyad.info" }
}<p localize-args="args">Visit <a href="{0}">DOCS</a> for more details.
</p>
- 本地化html属性(例如title):
<img src="../picture.jpg" localize-att-title="Nature picture" />
下面是Register.cshtml页面的完全本地化的示例,请注意,我们只需要在相关标签中添加“localize-content”属性,即可使页面代码保持整洁并易于阅读和更新。
@page
@model RegisterModel
@{ViewData["Title"] = "Register";
}<h1 localize-content>@ViewData["Title"]</h1><div class="row"><div class="col-md-4"><form asp-route-returnUrl="@Model.ReturnUrl" method="post"><h4 localize-content>Create a new account.</h4><hr /><div asp-validation-summary="All" class="text-danger"></div><div class="form-group"><label asp-for="Input.Email"></label><input asp-for="Input.Email" class="form-control" /><span asp-validation-for="Input.Email" class="text-danger"></span></div><div class="form-group"><label asp-for="Input.Password"></label><input asp-for="Input.Password" class="form-control" /><span asp-validation-for="Input.Password" class="text-danger"></span></div><div class="form-group"><label asp-for="Input.ConfirmPassword"></label><input asp-for="Input.ConfirmPassword" class="form-control" /><span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span></div><button type="submit" class="btn btn-primary" localize-content>Register</button></form></div>
</div>
@section Scripts {<partial name="_ValidationScriptsPartial" />
}
使用XLocalizer.TagHelpers查看本地化示例
本地化验证属性错误、模型绑定错误和身份错误消息
本地化所有框架错误消息不需要使用XLocalizer进行任何其他设置,并且没有必要在attribute标签内提供任何错误消息!所有错误消息都将通过XLocalizer的默认设置进行分配和本地化。
以下是一些验证属性的示例用法:
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
此外,对于模型绑定错误和身份错误,我们无需进行任何其他设置,默认情况下XLocalizer将负责本地化所有错误消息。
以下是Register.cshtml.cs文件的后端本地化示例:
public class InputModel
{[Required][EmailAddress][Display(Name = "Email")]public string Email { get; set; }[Required][StringLength(100, MinimumLength = 6)][DataType(DataType.Password)][Display(Name = "Password")]public string Password { get; set; }[DataType(DataType.Password)][Display(Name = "Confirm password")][Compare("Password")]public string ConfirmPassword { get; set; }
}
验证属性使用情况,但未定义错误消息
自定义错误消息
在某些情况下,您可能需要针对验证属性,模型绑定或身份自定义错误消息。或者,您可能希望在除“en”之外的区域性中提供默认错误消息,因此XLocalizer可以从正确的区域性进行翻译。
第一种解决方案是通过提供以下相关错误消息,在启动文件中使用内联选项设置:
services.AddRazorPages().AddXLocalizer<...>(ops =>{// ...ops.ValidationErrors = new ValidationErrors {RequiredAttribute_ValidationError = "The {0} field is required.",CompareAttribute_MustMatch = "'{0}' and '{1}' do not match.",StringLengthAttribute_ValidationError = "The field {0} must be a string with a maximum length of {1}.",// ...};ops.ModelBindingErrors = new ModelBindingErrors {AttemptedValueIsInvalidAccessor = "The value '{0}' is not valid for {1}.",MissingBindRequiredValueAccessor = "A value for the '{0}' parameter or property was not provided.",MissingKeyOrValueAccessor = "A value is required.",// ...};ops.IdentityErrors = new IdentityErrors {DuplicateEmail = "Email '{0}' is already taken.",DuplicateUserName = "User name '{0}' is already taken.",InvalidEmail = "Email '{0}' is invalid.",// ...};});
在启动文件中自定义错误消息。
另一个选项是在json文件中配置所有XLocalizer设置。
JSON设置
如果您是偏爱保持启动文件整洁的开发人员,像我一样,您将很高兴知道可以在json文件中进行所有这些自定义,并且仅需一行即可读取启动时的配置。
- 将相关配置添加到appsettings.json或您选择的任何自定义json文件中。
{"XLocalizerOptions" : {"AutoAddKeys" : true,"AutoTranslate" : true,// ...}
}
- 进行设置XLocalizer以阅读相关的配置部分:
services.AddRaqzorPages().AddXLocalizer<...>(ops => Configuration.GetSection("XLocalizerOptions").Bind(ops));
- 以下是XLocalizer带有可自定义错误消息的选项的示例json设置:
{"XLocalizerOptions": {"ResourcesPath": "LocalizationResources","AutoAddKeys": true,"AutoTranslate": true,"UseExpressMemoryCache": true,"TranslateFromCulture": "en","ValidationErrors": {"CompareAttribute_MustMatch": "'{0}' and '{1}' do not match. They should not be different!","CreditCardAttribute_Invalid": "The {0} field is not a valid credit card number.","CustomValidationAttribute_ValidationError": "{0} is not valid.","DataTypeAttribute_EmptyDataTypeString": "The custom DataType string cannot be null or empty.","EmailAddressAttribute_Invalid": "The {0} field is not a valid e-mail address.","FileExtensionsAttribute_Invalid": "The {0} field only accepts files with the following extensions: {1}","MaxLengthAttribute_ValidationError": "The field {0} must be a string or array type with a maximum length of '{1}'.","MinLengthAttribute_ValidationError": "The field {0} must be a string or array type with a minimum length of '{1}'.","PhoneAttribute_Invalid": "The {0} field is not a valid phone number.","RangeAttribute_ValidationError": "The field {0} must be between {1} and {2}.","RegexAttribute_ValidationError": "The field {0} must match the regular expression '{1}'.","RequiredAttribute_ValidationError": "The {0} field is required. Don't bypass this field!","StringLengthAttribute_ValidationError": "The field {0} must be a string with a maximum length of {1}.","StringLengthAttribute_ValidationErrorIncludingMinimum": "The field {0} must be a string with a minimum length of {2}and a maximum length of {1}.","UrlAttribute_Invalid": "The {0} field is not a valid fully-qualified http,https, or ftp URL.","ValidationAttribute_ValidationError": "The field {0} is invalid."},"IdentityErrors": {"DuplicateEmail": "Email '{0}' is already taken.","DuplicateUserName": "User name '{0}' is already taken. Please try another one.","InvalidEmail": "Email '{0}' is invalid.","DuplicateRoleName": "Role name '{0}' is already taken.","InvalidRoleName": "Role name '{0}' is invalid.","InvalidToken": "Invalid token.","InvalidUserName": "User name '{0}' is invalid, can only contain letters or digits.","LoginAlreadyAssociated": "A user with this login already exists.","PasswordMismatch": "Incorrect password.","PasswordRequiresDigit": "Passwords must have at least one digit ('0'-'9').","PasswordRequiresLower": "Passwords must have at least one lowercase ('a'-'z').","PasswordRequiresNonAlphanumeric": "Passwords must have at least one non alphanumeric character.","PasswordRequiresUniqueChars": "Passwords must use at least {0} different characters.","PasswordRequiresUpper": "Passwords must have at least one uppercase ('A'-'Z').","PasswordTooShort": "Passwords must be at least {0} characters.","UserAlreadyHasPassword": "User already has a password set.","UserAlreadyInRole": "User already in role '{0}'.","UserNotInRole": "User is not in role '{0}'.","UserLockoutNotEnabled": "Lockout is not enabled for this user.","RecoveryCodeRedemptionFailed": "Recovery code redemption failed.","ConcurrencyFailure": "Optimistic concurrency failure, object has been modified.","DefaultError": "An unknown failure has occurred."},"ModelBindingErrors": {"AttemptedValueIsInvalidAccessor": "The value '{0}' is not valid for {1}.","MissingBindRequiredValueAccessor": "A value for the '{0}' parameter or property was not provided.","MissingKeyOrValueAccessor": "A value is required.","MissingRequestBodyRequiredValueAccessor": "A non-empty request body is required.","NonPropertyAttemptedValueIsInvalidAccessor": "The value '{0}' is not valid.","NonPropertyUnknownValueIsInvalidAccessor": "The supplied value is invalid.","NonPropertyValueMustBeANumberAccessor": "The field must be a number.","UnknownValueIsInvalidAccessor": "The supplied value is invalid for {0}.","ValueIsInvalidAccessor": "The value '{0}' is invalid. You entered something weird!","ValueMustBeANumberAccessor": "The field {0} must be a number. Don't use letters or special characters.","ValueMustNotBeNullAccessor": "The value '{0}' is invalid. This can't be null."}}
}
自定义json文件中的所有XLocalizer选项。
因此,这是自定义所有错误消息的简单方法。XLocalizer将根据请求区域性将这些消息翻译成其他区域性。
添加语言导航
每个多文化Web应用程序都必须提供一种在不同语言之间进行切换的方法。您可能有自己的语言导航实现,但以防万一您需要轻松添加一个(我们之前已安装的LazZiya.TagHelpers):
- 添加taghelpers到_ViewImports文件中:
@addTagHelper *, LazZiya.TagHelpers
- 打开_layout.cshtml,然后在需要显示的位置添加语言导航:
<language-nav> </ language-nav >
我强烈建议按照此处的文档页面中的说明设置语言导航以配置区域性cookie 。因此,区域性选择可以存储在cookie中以备后用。
运行应用程序
如果正确完成了所有步骤,然后启动应用程序, 请查看VS中的输出窗口以查看日志,您将看到该窗口XLocalizer已开始翻译视图并自动插入值。此外,所有验证属性,模型绑定和身份错误也已本地化。
注意:本地化身份页面需要将身份脚手架放入项目中。
您需要添加新区域性的是:将区域性添加到启动文件中受支持的区域性,其余所有工作由XLocalizer来完成。:)
支持的.NET Core版本
- 2.x
- 3.x
- 5.0
支持的项目类型
- Razor Pages
- MVC
- Blazor Server
参考文献
- Docs: https://docs.ziyad.info
- Repo: https://github.com/LazZiya/XLocalizer
- Samples: https://github.com/LazZiya/XLocalizer.Samples
https://www.codeproject.com/Articles/5275604/ASP-NET-Core-Localization-with-XLocalizer
使用XLocalizer进行ASP.NET Core本地化相关推荐
- Asp.Net Core IdentityServer4 管理面板集成
前言 IdentityServer4(以下简称 Id4) 是 Asp.Net Core 中一个非常流行的 OpenId Connect 和 OAuth 2.0 框架,可以轻松集成到 Asp.Net C ...
- Asp.Net Core 混合全球化与本地化支持
前言 最近的新型冠状病毒流行让很多人主动在家隔离,希望疫情能快点消退.武汉加油,中国必胜! Asp.Net Core 提供了内置的网站国际化(全球化与本地化)支持,微软还内置了基于 resx 资源字符 ...
- ASP.NET Core 中文文档 第二章 指南(4.4)添加 Model
原文:Adding a model 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:许登洋(Seay).孟帅洋(书缘).姚阿勇(Mr.Yao).夏申斌 在这一节里,你将添加一些类来 ...
- ASP.NET Core 1.1 Preview 1 简介(包含.NETCore 1.1升级公告)
ASP.NET Core 1.1 Preview 1于2016年10月25日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强. 要将现有项目更新到ASP.NET Core 1.1 Pre ...
- ASP.NET Core 3.0中使用动态控制器路由
原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...
- [Abp 源码分析]ASP.NET Core 集成
点击上方蓝字关注我们 0. 简介 整个 Abp 框架最为核心的除了 Abp 库之外,其次就是 Abp.AspNetCore 库了.虽然 Abp 本身是可以用于控制台程序的,不过那样的话 Abp 就基本 ...
- asp.net core 5.0的一些模块
.net 5就要发布了,把asp.net core 3.1的一些模块改成了5.0来适配,基本都是体力活,没有太大改动. ORM dapper一个轻量级的ORM,重点实现SQL语句实体映射,用sql不失 ...
- ASP.NET Core学习资源汇总
ASP.NET Core入门学习资源汇总篇幅比較長,分为七个部分. (一)认识.NET Core (二)Vistual Studio安装.调试 (三)Asp.Net Core入门指南与学习路线 (四) ...
- asp.net core 实现支持多语言
asp.net core 实现支持多语言 Intro 最近有一个外国友人通过邮件联系我,想用我的活动室预约,但是还没支持多语言,基本上都是写死的中文,所以最近想支持一下更多语言,于是有了多语言方面的一 ...
最新文章
- 经典大数据面试题及解析
- DFTug - Architecture Your Test Design
- 【风险管理】系统技术框架
- C语言编译报错:incompatible pointer type [-Wincompatible-pointer-types](传参类型不匹配)
- 拓扑排序(字典序最小,字典序最小)
- ubuntu16 redis5.0以后版本集群部署示例
- Python安装、使用MySQL数据库
- Apache Maven 3.0.3 (yum) 安裝 (CentOS 6.4 x64)
- HDU2079 选课时间【母函数】
- OSD仿真_MFC程序01
- Atitit rgb yuv hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别
- 在线IDE开发入门之从零实现一个在线代码编辑器
- 世界杯的狂欢也是黑灰产的狂欢?
- 通过计算机主机数来划分子网,计算机网络知识梳理(2)——子网掩码及网络划分...
- QNX Hypervisor —— 物理设备
- 逻辑回归代价函数的推导过程
- Cstyle的UEFI导读: UEFI的N种实现及差别
- 软件测试 | 测试开发 | Git实战(四)| Git分支管理实操,在线合并和本地合并
- 周鸿祎:没钱也能创业 怎样写商业计划书
- Malaysia Tips
热门文章
- arp协议属于哪一层_网络工程师(3):详解ARP协议
- python怎样填充颜色_python – 使用颜色填充Tkinter画布对象之间的空间
- chromedriver放在哪个目录下_Windows下ThinkPHP与Linux互通
- 人工智能导论 王万良教授_FCES2019 panel4:人工智能的第一堂课究竟讲什么?
- python找不到文件中文文件名_找不到的方法虽然存在于同一个py文件中 - python
- 年底了,各大电商大促会员活动反馈万能模板,必备的PSD分层格式
- C++结构体中有构造函数和析构函数
- 云计算:OpenStack、Docker、K8S(Kubernetes容器编排工具)的演进史 | 附推荐阅读
- DPDK服务核心(coremask)
- Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别