在ASP.NET Core中获取浏览器语言?

22

我正在尝试从浏览器中获取默认语言,我使用以下代码来获取:

var languages = HttpContext.Request.UserLanguages;

由于以上内容不支持 .NET Core 2,因此我进行了测试:

var requestContext = Request.HttpContext.Features.Get<IRequestCultureFeature>();

然而,它返回了null。获取语言的正确方式或替代方法是什么?


1
你添加了本地化中间件吗? - DavidG
5个回答

44

IRequestCultureFeature 提供了应用程序支持的第一个匹配语言。支持的语言的声明在 Startup 类的 Configure() 方法中定义(参见示例)。如果您仍需要所有已接受的语言作为简单的 string[],类似于旧的 Request.UserLanguages 属性,则可以使用 Microsoft.AspNetCore.Http 命名空间中定义的 HeaderDictionaryTypeExtensions.GetTypedHeaders() 扩展。

// In your action method.
var languages = Request.GetTypedHeaders()
                       .AcceptLanguage
                       ?.OrderByDescending(x => x.Quality ?? 1) // Quality defines priority from 0 to 1, where 1 is the highest.
                       .Select(x => x.Value.ToString())
                       .ToArray() ?? Array.Empty<string>();

languages数组包含根据优先级参数q接受的语言列表。优先级最高的语言排在第一位。要获取默认语言,请取languages数组的第一个元素。

作为扩展方法:

using System.Collections.Generic;
using System.Linq;

using Microsoft.AspNetCore.Http;

public static class HttpRequestExtensions
{
    public static string[] GetUserLanguages(this HttpRequest request)
    {
        return request.GetTypedHeaders()
            .AcceptLanguage
            ?.OrderByDescending(x => x.Quality ?? 1)
            .Select(x => x.Value.ToString())
            .ToArray() ?? Array.Empty<string>();
    }
}

点赞。我不明白为什么有人会踩它,因为这是一个好答案。 - Jérôme MEVEL
1
@JérômeMEVEL 可能是因为我给被接受的答案点了踩,所以他们报复性地给我点了踩。 - Evgeni Nabokov
2
谢谢,这很有用。我不明白的是为什么在Core中事情变得如此复杂? - Mmm
@嗯,我同意。我想知道文档上说了什么,但是很难找到。更容易的方法是在客户端中获取语言,并将其作为自定义标头发送到服务器,可能在相同的“accept-language”标头中,但是如果NetCore需要那个可怕的查询来读取它,我不会干扰NetCore正在尝试做的任何事情。 - zameb

13

您需要添加本地化中间件才能获取 IRequestCultureFeature 特性:

public void Configure(IApplicationBuilder app)
{
    //...

    //Add this:
    app.UseRequestLocalization();

    //...
}

现在你可以在你的控制器中像这样请求该功能:

var requestCulture = Request.HttpContext.Features.Get<IRequestCultureFeature>();

这不是答案。IRequestCultureFeature不是string[]。 - Evgeni Nabokov
@EvgeniNabokov 当然它不是一个字符串,它是一个实现了IRequestCultureFeature接口的服务,就像OP在问题中使用的那样。 OP认为这是正确的,并接受了它,所以感谢你的投票! - DavidG
@DavidG 如何使用此功能获取可接受的语言列表?我曾经使用过 Request.UserLanguages,它返回一个字符串数组。 - Evgeni Nabokov
@EvgeniNabokov 像我上面说的那样,使用 requestCulture 对象。所以类似于 var requestedCulture = requestCulture.RequestCulture; 这样的东西。 - DavidG
2
@DavidG 首先,从你的示例中不清楚如何从IRequestCultureFeature获取任何语言。请提供更详细的示例。 其次,IRequestCultureFeature不能替换UserLanguages。我有一些接口需要使用用户语言作为字符串数组。我无法更改接口,也无法仅从Culture或UICulture创建一个1元素数组(与第一个支持的语言匹配),因为我需要传递所有接受的语言。我得出结论,我必须手动解析accept-languages头(如Carlos Tenorio所写)。这很遗憾。 - Evgeni Nabokov
显示剩余3条评论

7
你可以从请求头中获取浏览器语言。
在你的控制器中编写如下内容:
//For example --> browserLang = 'en-US'
var browserLang= Request.Headers["Accept-Language"].ToString().Split(";").FirstOrDefault()?.Split(",").FirstOrDefault();

4
放弃优先级参数"q"是一个不好的想法。 - Evgeni Nabokov

0
也许我的解决方案对某些人有用。不同之处在于,如果标题没有Accept-Language,则使用默认语言。
此代码适用于NET 6。
builder.Services.Configure<RequestLocalizationOptions>(config =>
{
    CultureInfo en = new CultureInfo("en");
    CultureInfo ru = new CultureInfo("ru");
    var langs = new List<CultureInfo> { en, ru };
    config.DefaultRequestCulture = new RequestCulture(en);
    config.SupportedCultures = langs;
    config.SupportedUICultures = langs;
});

app.UseRequestLocalization();

public IActionResult Index()
{
    var languageRequest = HttpContext.Features.Get<IRequestCultureFeature>()?.RequestCulture.Culture.Name;

    // use switch with languageRequest or another your logic
}

另外,您不能使用builder.Services.Configure,否则在languageRequest中您将收到语言的完整名称。例如:"en-En","ru-RU"等...


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接