Get CultureInfo from current visitor and setting resources based on that?

How can I (in ASP .NET MVC) get the CultureInfo of the current visitor (based on his/her browser languages)?

I have no idea where to start. I tried looking into the "Accept-Languages" header sent by the browser. But is that the best way of doing it?


Solution 1:

Request.UserLanguages is the property you're looking for. Just keep in mind that this array may contain arbitrary (even non-exsitent) languages as set by request headers.

UPDATE

Example:

// Get Browser languages.
var userLanguages = Request.UserLanguages;
CultureInfo ci;
if (userLanguages.Count() > 0)
{
    try
    {
        ci = new CultureInfo(userLanguages[0]);
    }
    catch(CultureNotFoundException)
    {
         ci = CultureInfo.InvariantCulture;
    }
}
else
{
    ci = CultureInfo.InvariantCulture;
}
// Here CultureInfo should already be set to either user's prefereable language
// or to InvariantCulture if user transmitted invalid culture ID

Solution 2:

Asp.Net Core version: using RequestLocalization ie the culture is retrieved form the HTTP Request.

in Startup.cs - Configure

app.UseRequestLocalization();

Then in your Controller/Razor Page.cs

var locale = Request.HttpContext.Features.Get<IRequestCultureFeature>();
var BrowserCulture = locale.RequestCulture.UICulture.ToString();

Solution 3:

You can use code similar to the following to get various details from your user (including languages):

MembershipUser user = Membership.GetUser(model.UserName);
string browser = HttpContext.Request.Browser.Browser;
string version = HttpContext.Request.Browser.Version;
string type = HttpContext.Request.Browser.Type;
string platform = HttpContext.Request.Browser.Platform;
string userAgent = HttpContext.Request.UserAgent;
string[] userLang = HttpContext.Request.UserLanguages

Solution 4:

It appears Request.UserLanguages is not available in later mvc versions (Asp.net core mvc 2.0.2 didn't have it.)

I made an extension method for HTTPRequest. Use it as follows:

var requestedLanguages = Request.GetAcceptLanguageCultures();

The method will give you the cultures from the Accept-Language header in order of preference (a.k.a. "quality").

public static class HttpRequestExtensions
{
    public static IList<CultureInfo> GetAcceptLanguageCultures(this HttpRequest request)
    {
        var requestedLanguages = request.Headers["Accept-Language"];
        if (StringValues.IsNullOrEmpty(requestedLanguages) || requestedLanguages.Count == 0)
        {
            return null;
        }

        var preferredCultures = requestedLanguages.ToString().Split(',')
            // Parse the header values
            .Select(s => new StringSegment(s))
            .Select(StringWithQualityHeaderValue.Parse)
            // Ignore the "any language" rule
            .Where(sv => sv.Value != "*")
            // Remove duplicate rules with a lower value
            .GroupBy(sv => sv.Value).Select(svg => svg.OrderByDescending(sv => sv.Quality.GetValueOrDefault(1)).First())
            // Sort by preference level
            .OrderByDescending(sv => sv.Quality.GetValueOrDefault(1))
            .Select(sv => new CultureInfo(sv.Value.ToString()))
            .ToList();

        return preferredCultures;
    }
}

Tested with ASP.NET Core MVC 2.0.2

It's similar to @mare's answer, but a bit more up-to-date and the q (quality) is not ignored. Also, you may want to append the CultureInfo.InvariantCulture to the end of the list, depending on your usage.

Solution 5:

I am marking this question for myself with a star and sharing here some code that essentially turns the Request.UserLanguages into an array of CultureInfo instances for further use in your application. It is also more flexible to work with CultureInfo than just the ISO codes, because with CultureInfo you get access to all the properties of a culture (like Name, Two character language name, Native name, ...):

        // Create array of CultureInfo objects
        string locale = string.Empty;
        CultureInfo[] cultures = new CultureInfo[Request.UserLanguages.Length + 1];
        for (int ctr = Request.UserLanguages.GetLowerBound(0); ctr <= Request.UserLanguages.GetUpperBound(0);
                 ctr++)
        {
            locale = Request.UserLanguages[ctr];
            if (!string.IsNullOrEmpty(locale))
            {

                // Remove quality specifier, if present.
                if (locale.Contains(";"))
                    locale = locale.Substring(0, locale.IndexOf(';'));
                try
                {
                    cultures[ctr] = new CultureInfo(locale, false);
                }
                catch (Exception) { continue; }
            }
            else
            {
                cultures[ctr] = CultureInfo.CurrentCulture;
            }
        }
        cultures[Request.UserLanguages.Length] = CultureInfo.InvariantCulture;

HTH