ASP.NET Core 全球化和本地化系列二

我们在实际的工作中会经常使用ASP.NET Core的Globalization & Localization 特性以及资源文件,资源文件(.resx)是用来从代码中分隔语言字符串的方法,这些文件包含key/values项,可以使用vs来创建该文件,例如: 你的website支持3种文化-法语,西班牙,英语,因此你必须创建2个类型的资源文件,例如法语和西班牙语

在这节我将展示从website不同的区域如何实现本地化和全球化

1 控制器使用IStringLocalizer对象

2 Data Annotations 错误消息

3 客户自定义验证错误消息

4 视图使用IViewLocalizer

我们基于英语,法语和西班牙语实现工作申请表单多语言

1 配置启动项

第一步告诉应用程序website将支持的语言文化,并且在应用程序中添加Localization服务和另外一些设置,进入Program类添加下面命名空间:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Options;
using System.Globalization;

接下来添加下面代码:

builder.Services.AddControllersWithViews()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
                .AddDataAnnotationsLocalization();


builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
            new CultureInfo("en-US"),
            new CultureInfo("fr"),
            new CultureInfo("es")
        };
    options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
});

这段代码做了2件事情:

1. 给Data Annotations和Views添加本地化特性

2. 你网站支持3种文化-法语,西班牙语,英语被定义为默认

在应用程序中允许使用Localization 服务

var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);

使用资源文件在ASP.NET Core中创建全球化&本地化特性

2 使用资源文件DataAnnotations本地化

首先创建一个Model用来呈现应用程序工作申请表单,接着在Models文件夹下创建一个新的类并且命名为JobApplication.cs,这个类包含如下属性:Name, Email Address, DOB 等,将特性应用到这些字段上,像 [Required],[RegularExpression],[Range],[Display]

代码如下:

using AspNetCore.GlobalLocalResFiles.Infrastructure;
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;


namespace AspNetCore.GlobalLocalResFiles.Models
{
    public class JobApplication
    {
        [Required(ErrorMessage = "Please provide your name")]
        [Display(Name = "Job applicant name")]
        public string Name { get; set; }


        [RegularExpression("^[a-zA-Z0-9_\\.-]+@([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", ErrorMessage = "E-mail is not valid")]
        [Display(Name = "Job applicant email")]
        public string Email { get; set; }
        [CustomDate]
        [Display(Name = "Date of Birth")]
        public DateTime DOB { get; set; }
        [Required(ErrorMessage = "Please select your sex")]
        [Display(Name = "Job applicant sex")]
        public string Sex { get; set; }
        [Range(2, 4, ErrorMessage = "{0} must be a number between {1} and {2}")]
        [Display(Name = "Job applicant experience")]
        public int Experience { get; set; }
        [Range(typeof(bool), "true", "true", ErrorMessage = "You must accept the Terms")]
        [Display(Name = "Terms")]
        public bool TermsAccepted { get; set; }
    }
}

接下来,创建资源文件用来存储错误消息和显示名称,因此在Models文件夹下创建两个资源文件并且和JobApplication类在相同的目录下:JobApplication.es.resx,JobApplication.fr.resx

注意:资源文件的名称我使用.es作为西班牙语和.fr作为法语

在这些资源文件你可以添加字符串(例如:错误消息和显示的名称)和他们各自法语和西班牙语字符串

如下图所示,展示两个资源文件:

3ac26c2bd8eefc958a4d6b62fb524e42.png

873f5cb3984f8472bffd0f4c87556878.png

3 客户自定义验证本地化字符

我们创建了客户自定义特性叫[CustomDate]针对出生日期,在DOB字段上指定客户验证

[CustomDate]
[Display(Name = "Date of Birth")]
public DateTime DOB { get; set; }

在Infrastructure文件夹创建一个新类叫CustomDate.cs,该类负责验证因此你必须继承自ValidationAttribute类,代码如下:

public class CustomDate : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var _localizationService = (IStringLocalizer<CustomDate>)validationContext.GetService(typeof(IStringLocalizer<CustomDate>));
        if ((DateTime)value > DateTime.Now)
            return new ValidationResult(_localizationService["Date of Birth cannot be in the future"]);
        else if ((DateTime)value < new DateTime(1980, 1, 1))
            return new ValidationResult(_localizationService["Date of Birth should not be before 1980"]);
        return ValidationResult.Success;
    }
}

在运行时使用了IStringLocalizer对象获取资源类,它是一个服务用来提供存储在资源文件中的本地化字符串

var _localizationService = (IStringLocalizer<CustomDate>)validationContext.GetService(typeof(IStringLocalizer<CustomDate>));

注意我使用下面代码将获取语言指定的字符串从资源文件中

_localizationService["Date of Birth cannot be in the future"]
_localizationService["Date of Birth should not be before 1980"]

接下来,在Custom验证类的目录下创建2个资源文件并且命名为:

CustomDate.es.resx

CustomDate.fr.resx

在资源文件里添加法语和西班牙语文本字符串- Date of Birth cannot be in the future & Date of Birth should not be before 1980

4 控制器使用资源文件进行本地化

当表单提交时控制器调用action方法,提交成功后显示信息在这三种语言中基于用户选择的语言文化

因此,首先我们使用asp.net core依赖注入特性在控制器的构造函数中注入IStringLocalizer对象,然后从资源文件中遍历字符串关联的语言文化,这个消息将展示到用户提交的表单

代码如下:

public class HomeController : Controller
{
    private readonly IStringLocalizer<HomeController> _localizer;
    public HomeController(IStringLocalizer<HomeController> localizer)
    {
        _localizer = localizer;
    }
    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public IActionResult Index(JobApplication jobApplication)
    {
        if (ModelState.IsValid)
            ViewBag.Message = _localizer["Your application is accepted"];
        return View();
    }
}

_localizer 是一个变量包含IStringLocalizer对象,它主要提供给我存储在资源文件中的特定文化字符串

接下来,创建2个资源文件在Controllers文件夹,命名为:HomeController.es.resx,HomeController.fr.resx

由于我只有一个字符串“Your application is accepted”,因此两个资源文件都只有一个条目

下面两张图片是我控制器资源文件:

d1279c33b2e5e84a65761df37a11b012.png

89fb7a2051403c2df2753303be132aaa.png

5 视图使用资源文件进行本地化

IViewLocalizer服务提供针对视图文件进行本地化,可以将它注入到你的视图中,显示如下:

@inject IViewLocalizer Localizer

Job申请表单位于Index视图,首先你添加必要命名空间在你的视图:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.Extensions.Options
@using Microsoft.AspNetCore.Mvc.Localization

然后在视图中注入 IViewLocalizer & IOptions ,代码如下:

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

通过RequestLocalizationOptions 对象,我将使用网站支持的语言文化填充选择控件,用户可以选择他们的文化并且表单将基于选择的文化呈现给用户

接下来添加下面代码创建和填充选择控件项

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}
<label>Language:</label>
<select onchange="SetCulture(this.value)" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
</select>

这一小段的JavaScript代码将跳转到用户选择文化的job申请表单

<script>
    function SetCulture(selectedValue) {
        var url = window.location.href.split('?')[0];
        var culture = "?culture=" + selectedValue + "&ui-culture=" + selectedValue;
        window.location.href = url + culture;
    }
</script>

这里使用 QueryStringRequestCultureProvider,其中用户选择的文化被添加到 url 的查询字符串中,因此法语版本的应用程序表单将给与如下url:

https://localhost:44356/?culture=fr&ui-culture=fr

西班牙版本的表单url如下:

https://localhost:44356/?culture=es&ui-culture=es

英语版本我们不需要在url中添加语言文化

https://localhost:44356

接下来我们将把表单添加到视图:

<form class="m-1 p-1" asp-action="Index" asp-route-culture="@culture" asp-route-ui-culture="@uiculture" method="post">
    <div class="form-group">
        <label asp-for="Name"></label>
        <input asp-for="Name" class="form-control" />
        <span asp-validation-for="Name" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="DOB"></label>
        <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        <span asp-validation-for="DOB" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Sex"></label>
        <div>
            <input asp-for="Sex" type="radio" value="M" />@Localizer["Male"]
            <input asp-for="Sex" type="radio" value="F" />@Localizer["Female"]
        </div>
        <span asp-validation-for="Sex" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Experience"></label>
        <select asp-for="Experience" class="form-control">
            <option value="Select">@Localizer["Select"]</option>
            <option value="0">Fresher</option>
            <option value="1">0-1 years</option>
            <option value="2">1-2 years</option>
            <option value="3">2-3 years</option>
            <option value="4">3-4 years</option>
            <option value="5">4-5 years</option>
        </select>
        <span asp-validation-for="Experience" class="text-danger"></span>
    </div>
    <div class="form-group">
        <input asp-for="TermsAccepted" />
        <label asp-for="TermsAccepted" class="form-check-label">
            @Localizer["I accept the terms & conditions"]
        </label>
        <span asp-validation-for="TermsAccepted" class="text-danger"></span>
    </div>
    <button name="formsubmit" value="Button Control" type="submit" class="btn btn-primary">@Localizer["Submit Application"]</button>
</form>

在视图中我们使用了IViewLocalizer来获取文化关联的字符串,使用代码-@Localizer["SomeString"]

下面为radio控件代码:

<input asp-for="Sex" type="radio" value="M" />@Localizer["Male"]
<input asp-for="Sex" type="radio" value="F" />@Localizer["Female"]

同样,terms标签也做同样的事情:

<label asp-for="TermsAccepted" class="form-check-label">
    @Localizer["I accept the terms & conditions"]
</label>

接下来在与视图相同的目录下创建2个资源文件. 如下:

Index.es.resx

Index.fr.resx

在文件中添加必要的字符串,如下所示

ed845922f519df2fa78201321879b36b.png

6d76180d5cd08508644e51ba9d18e3fc.png

6 测试

接下来让我们做个测试,第一个将显示用户选择的文化,并且和其关联的文化表单将显示在浏览器:

0d3669ac534219c71de0e75337a550e0.png

e5ab85201fae3c98b22c259088efb663.png

接下来将展示data annotation信息用西班牙&法语版本

b43a52cda5a3b99762aa85b037169a74.png

69a8b9664e0942f27d20603e515a5d90.png

7 资源文件位置

你可以在启动项中使用如下代码改变资源文件的位置

services.AddLocalization(options => options.ResourcesPath = "Resources");

在这种情况下,HomeController 的资源文件应位于以下 2 个位置中的任意一个:

1. Resources/Controllers/ 目录里面:

    Resources/Controllers/HomeController.es.resx

    Resources/Controllers/HomeController.fr.resx

2. Resources目录里面:

    Resources/Controllers.HomeController.es.resx

    Resources/Controllers.HomeController.fr.resx

Data Annotations 资源文件位于以下2个位置中的任意一个:

Resources/Models.JobApplication.es.resx

Resources/Models.JobApplication.fr.resx

或者

Resources/Models/JobApplication.es.resx

Resources/Models/JobApplication.fr.resx

视图资源文件位于以下2个位置中的任意一个:

Resources/Views.Home.Index.es.resx

Resources/Views.Home.Index.fr.resx

或者

Resources/Views/Home/Index.es.resx

Resources/Views/Home/Index.fr.resx

源代码地址:

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.GlobalizationLocalization/AspNetCore.GlobalLocalResFiles

参考文献

https://www.yogihosting.com/globalization-localization-resource-files-aspnet-core/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值