• .NET Core如何实现多语言(本地化)功能
  • 发布于 2个月前
  • 248 热度
    0 评论
  • 小熊
  • 0 粉丝 30 篇博客
  •   

这系列文章我们主要为我们网站设置多语言以及ASP.NET Core全球化与本地化,这里我们将学习多语言站点,我们将支持三种不同语言和文化,英语,法语和西班牙语。


一. 设置站点为多语言
要使一个网站实现全球化,首要步骤是能够根据客户浏览器发送的每个请求来确定请求的语言或文化背景,之后,需要一个机制来根据客户的文化选择内容,使用下面步骤你将实现一个网站的全球化。

1.1 配置全球化&本地化在Program类
确保Program.cs类中包含如下命名空间:
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Options;
接下来,在应用程序中添加如下服务,这个通过AddLocalization()方法完成
builder.Services.AddControllersWithViews()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
你需要在应用程序中指定支持的语言和文化,在AddLocalization() 方法之后配置添加如下代码配置:
// 堆代码 duidaima.com
// AddLocalization method
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;
});

CultureInfo类是非常重要,该类提供了具体文化信息,例如:语言、子语言,国家/区域,日历和特定文化关联的信息。我们创建了一个数组支持三种语言文化en-us, fr & es (英语, 法语, 西班牙),并且在数组中设置SupportedCultures 和SupportedUICultures 属性,我们通过使用DefaultRequestCulture属性设置了应用程序默认文化为en-us 。


注意:我们使用的语言文化为en-us, 该例子中我们使用us作为国家/区域也可以类似的设置en-GB为英国或者en-za为南非等。
客户端浏览器发出的当前文化请求使用Localization中间件设置,这个中间件在Configure方法中启用,因此在Program类中添加下面代码:
var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);
Localization中间件必须配置在所有的中间件之前,Localization中间件使用了RequestCultureProviders组件确定当前客户端请求语言文化
系统提供了3个RequestCultureProviders:
QueryStringRequestCultureProvider – 在请求参数中传递culture和ui-culture
CookieRequestCultureProvider – 在ASP.NET Core Culture的Cookie中设置多语言

AcceptLanguageHeaderRequestCultureProvider – 获取用户在客户浏览器中设置的语言,注意:在后面的章节中,我们将展示如何使用这3个RequestCultureProviders 。


1.2 设置请求Culture
我们现在创建一个功能允许用户从下拉框中选择他们文化,因此添加如下代码:
@{
    ViewData["Title"] = "Home Page";
}
@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.Extensions.Options
@inject IOptions<RequestLocalizationOptions> LocOptions
@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}
<form id="cultureForm" asp-action="Index">
    <label>语言:</label>
    <select onchange="SetCulture(this.value)" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
    </select>
</form>
<table class="table culture-table">
    <tr>
        <td>Culture</td>
        <td>
            @requestCulture.RequestCulture.Culture.Name
        </td>
    </tr>
    <tr>
        <td>UICulture</td>
        <td>
            @requestCulture.RequestCulture.UICulture.Name
        </td>
    </tr>
    <tr>
        <td>Date</td>
        <td>
            @DateTime.Now.ToLongDateString()
        </td>
    </tr>
    <tr>
        <td>Currency</td>
        <td>
            @(98765.00.ToString("c"))
        </td>
    </tr>
    <tr>
        <td>Number</td>
        <td>
            @(987.87m.ToString("F2"))
        </td>
    </tr>
</table>
<script>
    function SetCulture(selectedValue) {
        var culture = "/?culture=" + selectedValue + "&ui-culture=" + selectedValue;
        document.getElementById("cultureForm").action = culture;
        document.getElementById("cultureForm").submit();
    }
</script>
首先引入必要的命名空间并且注入IOptions对象到视图,将从Program类获取RequestLocalizationOptions对象,我们获取到了在Program类中设置的所有语言文化的值。
@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.Extensions.Options
@inject IOptions<RequestLocalizationOptions> LocOptions
接下来,使用Context.Features.Get() 获取客户端请求文化, 在List中填充支持的文化
@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}
接下来,创建一个表单,表单的id为cultureForm并且这个表单内部有选择控件,该控件绑定了cultureItems,这个下拉框显示所有的支持的语言文化"en-us", "fr" & "es"
<form id="cultureForm" asp-action="Index">
    <label>Language:</label>
    <select onchange="SetCulture(this.value)" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
    </select>
</form>
选择控件的onchange事件调用了JavaScript方法SetCulture,在javascript的代码中我们把选择的值追加到表单的action之后,最后提交表单。
注意:我们使用了查询字符串告诉服务器我们使用什么语言文化,我们在此使用了QueryStringRequestCultureProvider 。
<script>
    function SetCulture(selectedValue) {
        var culture = "/?culture=" + selectedValue + "&ui-culture=" + selectedValue;
        document.getElementById("cultureForm").action = culture;
        document.getElementById("cultureForm").submit();
    }
</script>
接下来创建html表格显示用户选择信息
<table class="table culture-table">
    <tr>
        <td>Culture</td>
        <td>
            @requestCulture.RequestCulture.Culture.Name
        </td>
    </tr>
    <tr>
        <td>UICulture</td>
        <td>
            @requestCulture.RequestCulture.UICulture.Name
        </td>
    </tr>
    <tr>
        <td>Date</td>
        <td>
            @DateTime.Now.ToLongDateString()
        </td>
    </tr>
    <tr>
        <td>Currency</td>
        <td>
            @(98765.00.ToString("c"))
        </td>
    </tr>
    <tr>
        <td>Number</td>
        <td>
            @(987.87m.ToString("F2"))
        </td>
    </tr>
</table>
你能运行应用程序会看到如下所示:


二.  RequestCultureProvider
当用户的浏览器初始化一个请求并发送到服务器端时,我们可以使用一种方式来确定客户端使用的语言文化,这种方式通过使用RequestCultureProviders来完成,系统为我们提供了3个类。

2.1 QueryStringRequestCultureProvider
上面代码使用了QueryStringRequestCultureProvider,这是因为在查询字符串中发送语言文化,查询字符串的key叫culture & ui-culture 。例如当我添加culture=es&ui-culture=es 到查询字符串,告诉服务器我当前语言文化是西班牙语,类似的 culture=fr&ui-culture=fr告诉语言文化是法语。你可以运行应用程序检查并且在浏览器中输入如下url https://localhost:44356/?culture=es&ui-culture=es,你会看到西班牙语日期、货币、数字展示在页面,如下图所示:

2.2 CookieRequestCultureProvider
在该类中使用ASP.NET Core Culture Cookie来设置语言文化,默认Cookie名称是.AspNetCore.Culture 。

让我们使用一个新的方法创建这个Cookie,因此在Controller中添加下面actions方法
public IActionResult Cookie()
{
    return View();
}
[HttpPost]
public IActionResult Cookie(string culture)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddMonths(1) }
    );
    return RedirectToAction("Cookie");
}
这个action方法有一个字符串类型的参数叫culture,这个参数将获取到用户选择文化值,用户从下拉控件中选择文化。我们使用了MakeCookieValue方法创建一个Cookie,CookieRequestCultureProvider, DefaultCookieName 返回默认Cookie名称,使用它来跟踪用户指定的语言信息。
接下来创建一个视图文件叫Cookie,并添加如下代码:
@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.Extensions.Options
@inject IOptions<RequestLocalizationOptions> LocOptions
@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}
<form asp-action="Cookie" method="post">
    <label>Language:</label>
    <select name="culture" onchange="this.form.submit()" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
    </select>
</form>
<table>
    <tr>
        <td>Culture</td>
        <td>
            @requestCulture.RequestCulture.Culture.Name
        </td>
    </tr>
    <tr>
        <td>UICulture</td>
        <td>
            @requestCulture.RequestCulture.UICulture.Name
        </td>
    </tr>
    <tr>
        <td>Date</td>
        <td>
            @DateTime.Now.ToLongDateString()
        </td>
    </tr>
    <tr>
        <td>Currency</td>
        <td>
            @(12345.00.ToString("c"))
        </td>
    </tr>
    <tr>
        <td>Number</td>
        <td>
            @(123.45m.ToString("F2"))
        </td>
    </tr>
</table>
除了表单现在指向提交到Cookie操作方法之外,其它代码都是相同的,选择控件中显示Program类提供的语言文化,分别是"en-us","fr"和 "es"(英语、法语、西班牙语)。
JavaScript代码onchange时间将提交表单:
<form asp-action="Cookie" method="post">
    <label>Language:</label>
    <select name="culture" onchange="this.form.submit()" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
    </select>
</form>
现在运行应用程序并且在浏览器中打开Cookie视图的url,除了文化在Cookie中提供,没有在url中提供之外,其它完全一样。
现在打开Developer Tools在浏览器中并且进入Application 标签页,你会看到这个Cookie


三.AcceptLanguageHeaderRequestCultureProvider
AcceptLanguageHeaderRequestCultureProvider 从浏览器语言设置中获取用户语言文化信息,在浏览器中你可以添加新的语言,打开url- edge://settings/languages 
我们看一下是如何在浏览器中工作的,首先添加French语言并且将该语言移到顶部:           

接下来创建一个Browser的视图并且在内部创建一个html的表格,显示当前日期、当前货币、数字:
<table>
    <tr>
        <td>Date</td>
        <td>
            @DateTime.Now.ToLongDateString()
        </td>
    </tr>
    <tr>
        <td>Currency</td>
        <td>
            @(12345.00.ToString("c"))
        </td>
    </tr>
    <tr>
        <td>Number</td>
        <td>
            @(123.45m.ToString("F2"))
        </td>
    </tr>
</table>
接下来在控制器中添加Browser方法
public IActionResult Browser()
{
    return View();
}
删除.AspNetCore.Culture Cookie从浏览器中。
现在运行应用程序并且打开浏览器的URL ,你将会看到法语值显示在视图上:

四.客户自定义Provider
我们通过2个例子来了解客户自定义的RequestCultureProvider

4.1 在URL最后的段提供语言文化
一些网站在url最后的段中添加语言文化,像https://somewebsite.com/es为西班牙语版本,https:// somewebsite.com/fr 为法语版本,可以通过客户自动Provider来实现。
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;
    options.AddInitialRequestCultureProvider(new CustomRequestCultureProvider(async context =>
    {
        var currentCulture = "en";
        var segments = context.Request.Path.Value.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
        if (segments.Length >= 2)
        {
            string lastSegment = segments[segments.Length - 1];
            currentCulture = lastSegment;
        }
        var requestCulture = new ProviderCultureResult(currentCulture);
        return await Task.FromResult(requestCulture);
    }));
});
我们现在在浏览器中做测试,打开3个url在浏览器:
https://localhost:7011/Home/Browser/en 显示英语
https://localhost:7011/Home/Browser/fr 显示法语
https://localhost:7011/Home/Browser/es 显示西班牙语
如下所示:


4.2 从数据库中获取语言文化
如果你想用户存储语言和文化在数据库中,这也是一个不错的选择,通过添加一个新的客户自定义提供程序更新代码
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;
    options.AddInitialRequestCultureProvider(new MyCultureProvider());
});
MyCultureProvider是自定义类,它将从数据库中获取用户选择的语言文化。
接下来,在应用程序中添加Models文件夹并添加如下类
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Localization;

namespace AspNetCore.GlobalizationLocalization.Models
{
    public class MyCultureProvider : RequestCultureProvider
    {
        public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
        {
            var current_User = await user_Manager.GetUserAsync(HttpContext.User);
            string user_culture = TblUserName.Where(c => c.Id == current_User.Id).Select(c => c.Culture).FirstOrDefault();
            var requestCulture = new ProviderCultureResult(user_culture);
            return Task.FromResult(requestCulture);
        }
    }
}
这段代码相当简单,首先前2行获取当前用户文化从数据库中并且设置ProviderCultureResult类。
数据库表调用TblUserName包含一列叫Culture用来存储文化。
用户评论