---
title: Setting up culture detection
related:
  - https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/configuring-urls-for-multilingual-websites.md
  - https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites.md
  - https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/localizing-content.md
  - https://docs.kentico.com/13/multilingual-websites/setting-up-a-multilingual-user-interface/localizing-builder-components.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

A critical step when setting up multilingual projects is to ensure that the system knows the correct content culture when processing page requests.

Culture detection greatly depends on the [routing scheme](https://docs.kentico.com/13/developing-websites/implementing-routing.md) of your website:

- If your site uses [content tree-based routing](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing.md), the system automatically detects and sets the current culture for each request.
- If your site uses [conventional ASP.NET](https://docs.kentico.com/13/developing-websites/implementing-routing/custom-routing-using-url-patterns.md) routing, you need to set up and handle the functionality for detecting and setting the current culture manually.

With culture detection set up correctly, you can [assign cultures to your site](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites.md) in Xperience, and [localize the content](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/localizing-content.md) displayed on the site's pages. Finally, content editors can then [edit and translate the content](https://docs.kentico.com/13/multilingual-websites/editing-the-content-of-multilingual-websites.md) of individual pages.

## Projects with content tree-based routing

<!-- dev-model:mvc start -->

**MVC 5 development model.** Applies only when building with ASP.NET MVC 5. If this page also covers ASP.NET Core, that version is in its own block.

Once you have enabled and set up [content tree-based](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing/enabling-content-tree-based-routing.md) routing, the functionality for detecting and setting the current culture for each request **is handled automatically** by the system.

<!-- dev-model:mvc end -->

<!-- dev-model:core start -->

**ASP.NET Core development model.** Applies only when building with ASP.NET Core. If this page also covers MVC 5, that version is in its own block.

Once you have enabled and set up [content tree-based](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing/enabling-content-tree-based-routing.md) routing, the current culture for each request is detected and set automatically. The only requirement is for the system's localization middleware to be registered in your project's middleware pipeline. The middleware is registered as part of the **UseKentico** call, which should always be present in your application's pipeline.

```csharp title="Application startup class"

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Registers the localization middleware
    app.UseKentico();
    ...
}

```

By default, the middleware ensures the correct culture for requests handled by the system ([preview URLs](https://docs.kentico.com/13/developing-websites/retrieving-content/adding-preview-mode-support.md), [content tree-based routing](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing.md), [form](https://docs.kentico.com/13/developing-websites/form-builder-development.md) and [page](https://docs.kentico.com/13/developing-websites/page-builder-development.md) builder features).

<!-- dev-model:core end -->

You can then:

- Configure the format of the generated URLs, behavior of redirects to the home page, or enforce lowercase URLs, by setting up the [URL settings](https://docs.kentico.com/13/configuring-xperience/managing-sites/configuring-settings-for-sites/settings-urls-and-seo.md). See [Configuring URLs for multilingual websites](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/configuring-urls-for-multilingual-websites.md).
- [Assign cultures to your site](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites.md) in Xperience.
- [Localize content](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/localizing-content.md) displayed on the site's pages.
- Content editors can [edit and translate content](https://docs.kentico.com/13/multilingual-websites/editing-the-content-of-multilingual-websites.md) of the individual pages.

> **Info:** In addition to the routing handled by the system, you can also set up routing for pages not represented in the content tree by registering routes using conventional routing provided by ASP.NET. That is, pages not matched by the system router can always be matched by custom routes.
>
> For more information about how to set up custom routing, see [Combining content tree-based and ASP.NET routing](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing/combining-content-tree-based-and-asp-net-routing.md) and the section below.

## Projects with custom routing

To serve content in multiple languages on sites that use a custom routing scheme (i.e., [conventional ASP.NET](https://docs.kentico.com/13/developing-websites/implementing-routing/custom-routing-using-url-patterns.md) routing) or for features that you define manually in your live site application, you need to set up functionality that detects and sets the current culture for each request.

<!-- dev-model:core start -->

**ASP.NET Core development model.** Applies only when building with ASP.NET Core. If this page also covers MVC 5, that version is in its own block.

Register and configure the .NET framework's [Request culture providers](http://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization#implement-a-strategy-to-select-the-languageculture-for-each-request), which tell the system where to search for the culture under which the current request should be served.

Add culture providers via  **KenticoRequestLocalizationOptions** – the class behaves identically to [RequestLocalizationOptions](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.requestlocalizationoptions)  provided by ASP.NET Core, but hides configuration handled for the Core application by Xperience. For example, you do not need to provide the list of supported application and UI cultures at compile-time, since you [control](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites.md) UI cultures from the connected Xperience administration application.

For example, the following code snippet registers a **RouteDataRequestCultureProvider** that looks for the culture parameter in a request's "_culture_" route data parameter.

```csharp title="Application startup class"

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<KenticoRequestLocalizationOptions>(options =>
    {
        // Registers a culture provider that sets the request culture from the "culture" route data parameter
        // (e.g., for routes in the following format: {culture}/{controller}/{action})
        options.RequestCultureProviders.Add(new RouteDataRequestCultureProvider
        {
            RouteDataStringKey = "culture",
            UIRouteDataStringKey = "culture"
        });
    });

    ...
}

```

<!-- dev-model:core end -->

<!-- dev-model:mvc start -->

**MVC 5 development model.** Applies only when building with ASP.NET MVC 5. If this page also covers ASP.NET Core, that version is in its own block.

At the beginning of every request, you need to:

1. Retrieve or determine the correct culture to be used in the current request.
   - The way you detect the culture depends on the implementation of your multilingual site. For example, you can use language prefixes in URLs, culture-specific domains, or custom cookies.
2. Set the **Thread.CurrentThread.CurrentUICulture** and **Thread.CurrentThread.CurrentCulture** properties of the current thread (available in the _System.Threading_ namespace).

   > **Tip:** If you detect culture using **language prefixes in URLs** or using **culture-specific domains**, we recommend using the **SiteCultureConstraint** (_Kentico.Content.Web.Mvc_ namespace) provided by the Xperience API. The constraint supplies the culture for the current thread automatically based on the following process:
   >
   > - detect and validate the culture against site cultures,
   > - determine default culture according to the following priorities (first that applies):
   >   - [visitor culture](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/setting-default-languages-for-users-and-visitors.md) of the site
   >   - [preferred culture](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/setting-default-languages-for-users-and-visitors.md) of the user
   >   - browser culture
   >   - default culture (from application settings),
   > - set the _CurrentUICulture_ and _CurrentCulture_ properties of the current thread.Moreover, the constraint allows you to hide the language prefix in URLs for the default content culture:
   >
   > 1. Set the constraint's _HideLanguagePrefixForDefaultCulture_ property to true.
   > 2. Register a custom route without a culture parameter in the URL pattern for the default culture URLs.
   > 3. Manually set the _CurrentUICulture_ and _CurrentCulture_ properties for the custom route. See the [Example](#example) below.
   > 4. (Optional) If you use [URL language prefixes together with culture aliases](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/configuring-urls-for-multilingual-websites.md#changing-the-language-prefix-text), you also need to register a custom route with a constraint that detects your aliases and sets the appropriate culture. **SiteCultureConstraint** does not work with culture aliases.

> **Note:** **Note**: _Thread.CurrentThread.CurrentUICulture_ and _Thread.CurrentThread.CurrentCulture_ are properties of the .NET framework and use the _System.Globalization.CultureInfo_ type. They are not directly comparable with the _CMS.Localization.CultureInfo_ type, or the _CurrentUICulture_ and _CurrentCulture_ properties of the _CMS.Localization.LocalizationContext_ class provided by the Xperience API.

The Xperience localization API then automatically works with the given culture (for example when resolving [resource strings](https://docs.kentico.com/13/multilingual-websites/setting-up-a-multilingual-user-interface/working-with-resource-strings.md)).

You can now:

- [Assign cultures to your site](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites.md) in Xperience
- [Localize content](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/localizing-content.md) displayed on your site's pages
- [Edit and translate content](https://docs.kentico.com/13/multilingual-websites/editing-the-content-of-multilingual-websites.md) of individual pages

### Example

One common way to determine the culture of requests is to use language prefixes in your site's routes. For example:

- English – _www.example.com/**en-us**/path_
- Spanish – _www.example.com/**es-es**/path_

This example shows how to parse the culture from the route prefix and set the current culture for the MVC application using the system constraint **SiteCultureConstraint**. It also demonstrates how to hide language prefixes in URLs for the site's default content culture (e.g. if English is set as the default culture, the URL _www.example.com/en-us/path_ becomes _www.example.com/path_).

```csharp title="Example - RouteConfig.cs"

using System.Web.Mvc;
using System.Web.Routing;

public static void RegisterRoutes(RouteCollection routes)
{
    ...

    // Matches a URL containing a culture route prefix
    routes.MapRoute(
        name: "Default",
        url: "{culture}/{controller}/{action}",
        defaults: new { controller = "Home", action = "Index" },
        constraints: new { culture = new SiteCultureConstraint() { HideLanguagePrefixForDefaultCulture = true} }
    );

    // Matches a URL with a hidden culture prefix
    // This route needs to be registered AFTER the route which strips the culture parameter from the URL ("Default" in this example)
    routes.MapRoute(
        name: "DefaultWithoutCulturePrefix",
        url: "{controller}/{action}",
        defaults: new { },
        constraints: new { culture = new SetDefaultCultureConstraint() }
     );

}


```

```csharp title="Example - SetDefaultCultureConstraint"

using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.Routing;

using CMS.Helpers;
using CMS.SiteProvider;

// Constraint for a route that parses URLs with a hidden culture prefix for the default culture
public class SetDefaultCultureConstraint : IRouteConstraint
{
    // Propagates default culture into the current thread
    public bool Match(HttpContextBase httpContext, 
                    Route route, 
                    string parameterName, 
                    RouteValueDictionary values, 
                    RouteDirection routeDirection)
    {
        var defaultCultureCode = CultureHelper.GetDefaultCultureCode(SiteContext.CurrentSiteName);
        var culture = new CultureInfo(defaultCultureCode);

        Thread.CurrentThread.CurrentUICulture = culture;
        Thread.CurrentThread.CurrentCulture = culture;

        return true; 
    }
}


```

> **Tip:** You can use the _SiteCultureConstraint_ constraint equally for **when you detect cultures using culture-specific domains**. When the constraint parameter ("culture" in this case) is not found in the URL scheme, the _SiteCultureConstrain&#x74;_&#x65;nsures the culture will be detected from the URL's domain.
>
> ```csharp title="SiteCultureConstraint with culture-specific domains"
>
> ...
>
>     var route = routes.MapRoute(
>         name: "Default",
>         url: "{controller}/{action}",
>         defaults: new { controller = "Home", action = "Index" },
>         constraints: new { culture = new SiteCultureConstraint() }
>     );
>
> ...
>
> ```

<!-- dev-model:mvc end -->
