使用 LazZiya.ExpressLocalization 开发多文化 ASP.NET Core 3, 2, 1 项目






4.80/5 (25投票s)
如何用简单的步骤创建多文化 ASP.NET Core 网站应用程序
- 下载示例 - 5 MB
- https://github.com/LazZiya/ExpressLocalizationSampleCore3 (Core 3.x Razor 页面 & Mvc)
背景
大多数网站应用程序都使用基于 URL 的本地化,因此我们可以在 URL 中看到选定的区域性,例如 http://www.example.com/en/Contact。默认情况下,ASP.NET Core 提供以下请求区域性提供程序:
QueryStringRequestCultureProvider
CookieRequestCultureProvider
AcceptLanguageHeaderRequestCultureProvider
为了实现路由值本地化,我们将构建自定义的本地化提供程序并定义一个全局路由模板,所以基本上,我们需要完成以下本地化步骤才能拥有完全本地化的网站应用程序:
-
构建路由值请求区域性提供程序
根据 {culture} 路由值进行请求本地化
- 为 culture 参数定义全局路由模板
将 {culture} 参数添加到 URL,例如 www.example.com/en-US/
-
设置 DataAnnotations 本地化
数据批注的本地化,如显示名称、必需、字符串长度等。
DataAnnotations 定义在 System.ComponentModel.DataAnnotations 命名空间中。
除了本地化默认的DataAnnotation
外,自定义属性也必须使用相同的逻辑进行本地化。有关更多详细信息,请参阅 DataAnnotations。
-
设置 ModelBinding 错误消息本地化
服务器端提交后输入类型的验证,例如
ValueMustBeANumberAccessor
、AttemptedValueIsInvalidAccessor
等。有关更多详细信息,请参阅 DefaultModelBindingMessageProvider。
- 设置 IdentityDescriber 错误消息
所有用户和角色相关消息的本地化,例如“用户已在角色中”、“用户名已存在”等。
有关更多详细信息,请参阅 IdentityErrorDescriber。
-
设置 OnRedirectTo... 事件
当用户被自动重定向到登录、注销或访问拒绝页面时,会触发这些事件。自动重定向不处理区域性值,因此必须手动配置。
有关更多详细信息,请参阅 https://github.com/LazZiya/ExpressLocalization/issues/6
- 设置视图本地化
本地化 Razor 页面中的文本/HTML。
有关更多详细信息,请参阅 ViewLocalization。
-
设置客户端验证脚本
本地化客户端验证消息至关重要,表单将在提交前进行验证。必须本地化客户端验证脚本,以便用户看到本地化的消息,例如:字段是必需的,密码必须匹配等。
还有一点很重要,那就是验证本地化的十进制数字,一些区域性使用句点,另一些区域性使用逗号作为十进制数字,例如(1,2)和(1.2),这种情况应在客户端验证中仔细处理。
更重要的是:一些区域性可能使用完全不同的数字系统;例如,阿拉伯区域性使用数字,如“٠١٢٣٤٥٦٧٨٩”,而拉丁区域性使用
"0123456789"
。如果数字系统设置不正确,将出现验证错误。(请参阅 本文 了解如何更改客户端验证的数字系统。)有关更多详细信息,请参阅 Client side validation 和本地化 GitHub 相关问题。
-
为每种区域性创建本地化的资源文件
视图、数据批注、模型绑定和身份错误都要求有本地化的资源。这一步需要花费大量时间和精力!
所有这些步骤都需要大量工作并花费过多时间。因此,LazZiya.ExpressLocalization
nuget 包的优势就在于此,它只需几行简单的代码即可消除本地化设置的时间和精力。
创建项目
让我们开始创建一个基本的 ASP.NET Core 网站应用程序(我使用的是 VS2019)
- 通过选择 ASP.NET Core Web Application 创建新项目
- 点击 Next,给项目一个友好的名称,然后点击 Create
- 选择 Web Application,将目标框架设置为任何 ASP.NET Core 版本(3、2 或 1),并确保将身份验证更改为 Individual User Accounts。
- 点击 Create,等待解决方案创建基本模板,完成后,您可以通过在解决方案资源管理器中选择项目名称,然后按(Ctrl + Shift + B)构建项目,然后按(Ctrl + Shift + W)在浏览器中运行而不调试来测试。
安装 LazZiya.ExpressLocalization
- 在解决方案资源管理器中,在项目名称下,右键单击 Dependencies,然后选择 "Manage Nuget Packages"。
- 转到 Browse 选项卡,搜索 "
LazZiya
",选择 "LazZiya.ExpressLocalization
" 并点击 "Install",选择最新版本并安装它。
创建本地化资源
我已经为项目准备好了本地化资源,因此您不必花费时间创建本地化资源。
在项目根目录下,创建一个新文件夹并命名为 "LocalizationResources"
在 LocalizationResources 文件夹下,创建一个新的 public
类并命名为 "ViewLocalizationResource
",这个类将用于对视图本地化资源文件进行分组。
namespace ExpressLocalizationSample.LocalizationResources
{
public class ViewLocalizationResource
{
}
}
在 LocalizationResources 文件夹下,创建一个新的 public
类并命名为 "ExpressLocalizationResource
",这个类将用于对身份、模型绑定和数据批注的资源文件进行分组。
namespace ExpressLocalizationSample.LocalizationResources
{
public class ExpressLocalizationResource
{
}
}
我们将使用这两个类将资源类型传递给 Express Localization 方法。
注意:在本示例中,我将使用两个资源文件来存储本地化字符串,但您可以根据需要使用一个、两个或多个本地化资源文件来存储所有本地化字符串。在 AddExpressLocalization
的不同变体之间切换,以查看可用的选项。 在 GitHub 上阅读更多内容。
最后,请从这个 仓库文件夹 下载相关的区域性资源。请注意,您需要为每种区域性下载两个文件,例如(ExpressLocalizationResource.tr.resx 和 ViewLocalizationResource.tr.resx)。将下载的文件复制到 "LocalizationResources" 文件夹。
Using the Code
最后,我们准备好进行本地化设置了。 :)
打开 startup.cs 文件并添加所需的命名空间。
using LazZiya.ExpressLocalization;
然后在 ConfigureServices
方法中,定义支持的区域性并添加本地化设置,如下所示:
var cultures = new[]
{
new CultureInfo("tr"),
new CultureInfo("ar"),
new CultureInfo("hi"),
new CultureInfo("en"),
};
services.AddRazorPages()
.AddExpressLocalization<ExpressLocalizationResource, ViewLocalizationResource>(
ops =>
{
ops.ResourcesPath = "LocalizationResources";
ops.RequestLocalizationOptions = o =>
{
o.SupportedCultures = cultures;
o.SupportedUICultures = cultures;
o.DefaultRequestCulture = new RequestCulture("en");
};
});
注意:根据项目模式(MVC 或 Razor 页面)和版本,服务实现可能会更改为 services.AddMvc()
或 services.AddControllersWithViews()
或 services.AddRazorPages().
然后在 Configure
方法中,配置应用程序以使用请求本地化。
app.UseRequestLocalization();
在不同的 .NET Core 版本和项目类型中设置
.NET Core 的不同版本(1、2、3)可能具有不同的服务设置步骤,ExpressLocalization 可与所有版本和模式变体配合使用。
services.AddMvc().AddExpressLocalization(...);
services.AddRazorPages().AddExpressLocalization(...);
services.AddControllersWithViews().AddExpressLocalization(...);
如果您在 startup 中定义了路由,则需要在路由表中添加区域性参数。
app.UseRequestLocalization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{culture=en}/{controller=Home}/{action=Index}/{id?}");
});
或者,如果您在控制器上使用路由属性,请将区域性路由参数添加到路由属性中。
["{culture}/Home"]
public HomeController : Controller
{
...
}
添加语言导航
此步骤需要另一个 nuget 包 LazZiya.TagHelpers
,也可以从 nuget 中安装。
在 Pages 文件夹下,打开 _ViewImports.cshtml 文件并添加 LazZiya.TagHelpers
,这将有助于创建语言导航。
@addTagHelper *, LazZiya.TagHelpers
然后打开 Pages/Shared/_Layout.cshtml 文件,并在 _LoginPartial
标签下方添加语言导航标签助手,如下所示:
<partial name="_LoginPartial" />
<language-nav></language-nav>
设置区域性 Cookie
ExpressLocalization 按以下顺序使用所有区域性提供程序:
- RouteSegmentCultureProvider
- QueryStringRequestCultureProvider
- CookieRequestCultureProvider
- AcceptedLanguageHeaderRequestCultureProvider
- 使用 startup 设置中的默认请求区域性
要设置 Cookie 值,我们需要在 IndexPage
或主页中创建一个处理程序,该处理程序将为应用程序设置 Cookie 区域性值。
public class IndexModel : PageModel
{
// ...
public IActionResult OnGetSetCultureCookie(string cltr, string returnUrl)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(cltr)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
);
return LocalRedirect(returnUrl)
}
}
然后,我们可以按如下方式配置我们的语言导航:
<language-nav cookie-handler-url="@Url.Page("/Index", "SetCultureCookie",
new { area="", cltr="{0}", returnUrl="{1}" })">
</language-nav>
占位符 "{0}
" 和 "{1}
" 将被语言标签助手替换,并引用每个列出的区域性。
添加 LanguageNav
标签助手后,我们就可以进行首次运行了。
很好,到目前为止,我们有了支持区域性的导航,但我们仍然需要本地化视图文本才能看到本地化版本。
访问 LanguageTagHelper wiki 以获取更多详细信息。
本地化视图
在下载的文件中的 "ViewLocalizationResource.xx.resx" 中已提供了默认项目的本地化文本。如果您需要为视图添加更多自定义文本,请将其添加到 "ViewLocalizationResource.xx.resx" 文件中。
选项 1
在这里,我们将使用 LazZiya.ExpressLocalization 随附的 LocalizeTagHelper
,它提供了一个简单清晰的 HTML 标签来本地化视图。
打开 Pages/_ViewImports.cshtml 文件并添加本地化标签助手。
@addTagHelper *, LazZiya.ExpressLocalization
使用 LocalizeTagHelper 非常简单,只需向任何 HTML 标签添加 "localize-contents
" 属性,或用 "<localize>
" 标签将任何 HTML 内容括起来。
然后打开 Pages/Index.cshtml 并使用 Localize 标签助手来本地化文本/HTML。
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
var locArgs = new[] { "https://docs.microsoft.com/aspnet/core" };
}
<div class="text-center">
<h1 class="display-4" localize-content>Welcome</h1>
<p localize-args="@locArgs">Learn about
<a href="{0}">building Web apps with ASP.NET Core</a>.</p>
</div>
对其他视图中的所有文本使用相同的过程进行本地化。
有关更多详细信息,请参阅 实时演示页面 和 LocalizeTagHelper wiki。
选项 2
打开 Pages/_ViewImports.cshtml 文件并注入 ISharedCultureLocalizer
,该文件随 ExpressLocalization
一起提供。
@using LazZiya.ExpressLocalization
@inject ISharedCultureLocalizer _loc
然后打开 Pages/Index.cshtml 并为文本使用 localizer 函数。
@page
@model IndexModel
@{
ViewData["Title"] = _loc.GetLocalizedString("Home page");
}
<div class="text-center">
<h1 class="display-4">@_loc.GetLocalizedString("Welcome")</h1>
<p>@_loc.GetLocalizedHtmlString("Learn about
<a href='{0}'> building Web apps with ASP.NET Core</a>",
new[]{"https://docs.microsoft.com/aspnet/core"}).</p>
</div>
对其他视图中的所有文本使用相同的过程进行本地化。
本地化 URL
当页面处于非默认区域性时,如果您点击 Privacy、Login 或 Register 链接,您会注意到我们丢失了选定的区域性,这是因为我们没有将区域性路由值添加到链接中。
打开 Pages/_ViewImports.cshtml 并添加对 System.Globalization
的引用。
@using System.Globalization
然后打开 Pages/_LoginPartial.cshtml 并在页面顶部添加一个 culture
参数,如下所示:
@{
var culture = CultureInfo.CurrentCulture.Name;
}
使用此参数为所有链接提供 culture
路由值,如下所示:
<a class="nav-link text-dark"
asp-area="Identity"
asp-page="/Account/Register"
asp-route-culture="@culture"
localize-content>Register</a>
对项目中的所有视图执行此操作。
本地化身份视图
身份相关内容,如登录、注册和配置文件,需要被覆盖才能修改。
右键单击项目名称,选择 Add --> New Scaffolded Item...
选择 Identity 并点击 Add
选择 "Override all files" 并选择 "ApplicationDbContext
"
当您点击 Add 时,将创建一个新的 Areas 文件夹,其中包含所有身份相关的视图。
Identity area 包含三个 _ViewImports 文件夹。
- Areas/Identity/Pages/_ViewImports.cshtml
- Areas/Identity/Pages/Account/_ViewImports.cshtml
- Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml
将以下代码添加到所有这些文件中,就像我们之前为 Pages/_ViewImports.cshtml 所做的那样:
@using System.Globalization
@addTagHelper *, LazZiya.TagHelpers
@addTagHelper *, LazZiya.ExpressLocalization
遍历视图并使用我们之前用于本地化视图的步骤来本地化,并添加 culture
路由参数。以下是 Register.cshtml 页面:
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
var culture = CultureInfo.CurrentCulture.Name;
}
<h1 localize-content>Register</h1>
<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="@Model.ReturnUrl"
method="post" asp-route-culture="@culture">
<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" />
}
如果您运行页面并输入无效输入,您会注意到验证消息是英文的,因此我们需要本地化数据批注消息,例如 Required
、StringLength
等。
打开 Areas/Identity/Pages/Account/Register.cshtml.cs 文件并在页面顶部添加对 "LazZiya.ExpressLocalization.DataAnnotations
" 的引用;它提供了 express 属性,这些属性已生成本地化的错误消息。
@using LazZiya.ExpressLocalization.DataAnnotations;
然后修改 Input 模型,使其如下所示:
public class InputModel
{
[ExRequired]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[ExRequired]
[ExStringLength(100, MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[ExCompare("Password"]
public string ConfirmPassword { get; set; }
}
编译并运行项目,您将看到本地化的数据批注错误消息。
本地化自定义后端消息
来自后端的任何自定义消息都可以使用 LazZiya.ExpressLocalization
提供的 ISharedCultureLocalizer
进行本地化。要本地化任何自定义后端消息,请注入 ISharedCultureLocalizer
并调用本地化方法,如下所示(MVC 和 RazorPages 中的过程相同):
public IndexModel : PageModel
{
private readonly ISharedCultureLocalizer _loc;
public IndexModel(ISharedCultureLocalizer loc)
{
_loc = loc;
}
public void OnGet()
{
//...
var msg = _loc.GetLocalizedString("This is a custom backend message.");
// ...
}
}
后端消息的本地化文本必须与包含视图本地化文本的资源文件相同。
ISharedCultureLocalizer
还有其他变体,允许您指定目标区域性和目标资源文件。浏览和测试函数以查看其他可能性。
Client Side Validation
服务器端验证工作正常,但我们仍然需要添加客户端验证,以便在提交表单之前在客户端验证输入字段。
客户端验证的一个主要问题是验证本地化输入,如数字、日期等。例如,如果您使用十进制输入,您会看到本地化数字的验证错误,例如 1.3 在英语区域性中是有效的,但在土耳其区域性中是无效的,因为它应该是 1,3(逗号而不是句点)。
在这里,我们将使用另一个有用的标签助手 LocalizationValidatonScripts,它来自 LazZiya.TagHelpers
。
在 startup 中注册标签助手。
services.AddTransient<ITagHelperComponent, LocalizationValidationScriptsTagHelperComponent>();
打开 Register.cshtml 页面,并在默认验证脚本部分下方添加标签助手。
@section Scripts {
<partial name="_ValidationScriptsPartial" />
<localization-validation-scripts></localization-validation-scripts>
}
就完成了,现在具有本地化输入的字段将根据当前区域性进行验证,例如十进制输入使用逗号或句点进行验证。
示例项目
您可以从 GitHub 下载包含超过 19 种区域性的示例项目。
- 下载示例 - 5 MB
- https://github.com/LazZiya/ExpressLocalizationSampleCore3 (Core 3.x Razor 页面 & Mvc)
参考文献
在此处阅读有关使用的 nuget 包的更多详细信息:
- LazZiya.TagHelpers
- LazZiya.ExpressLocalization
- GitHub 仓库:ExpressLocalization Sample Core 2
- GitHub 仓库:ExpressLocalization Sample Core 3
- 手动安装客户端本地化验证脚本
- 手动创建语言下拉导航
- 本地化 ASP.NET Core 2.1 的详细教程
- 我的网站 http://ziyad.info 上还有更多内容。
历史
- 2019 年 6 月 3 日
- 初始版本
- 2019 年 6 月 17 日
- 使用
LazZiya.TagHelpers.Localization
更新的版本
- 使用
- 2019 年 6 月 22 日
- 更新示例,对本地化
ModelBinding
和身份消息中的一些问题进行了热修复(更新LazZiya.ExpressLocalization
至 v2.0.1)
- 更新示例,对本地化
- 2019 年 10 月 2 日
- DotNet Core 3.0 支持
- MVC 和 Razor 页面设置
- 配置身份验证 Cookie 重定向路径
- 添加了两个下载示例(.NET Core 3.0 和 .NET Core 2.2)
- 将 nuget 包更新到最新版本
- 2019 年 10 月 3 日
LazZiya.TagHelpers ViewContext
更新通知
- 2020 年 2 月 22 日
- 更新到最新版本的 ExpressLocalization 和 TagHelpers
- 用于区域性值的 Cookie 处理程序
- 2020 年 2 月 22 日
- 下载示例已更新