Open Source Web Application Framework for ASP.NET Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

10 KiB

//[doc-seo]
{
    "Description": "Learn how to use ABP's URL-based localization to embed culture in the URL path, enabling SEO-friendly and shareable localized URLs."
}

URL-Based Localization

ABP supports embedding the current culture directly in the URL path, for example /tr/products or /en/about. This approach is widely used by documentation sites, e-commerce platforms, and any site that needs SEO-friendly, shareable localized URLs.

By default, ABP detects language from QueryString (?culture=tr), Cookie, and Accept-Language header. URL path detection is opt-in and fully backward-compatible.

Enabling URL-Based Localization

Configure the AbpRequestLocalizationOptions in your module class:

Configure<AbpRequestLocalizationOptions>(options =>
{
    options.UseRouteBasedCulture = true;
});

That's all you need. The framework automatically handles the rest.

What Happens Automatically

When you set UseRouteBasedCulture to true, ABP automatically registers the following:

  • RouteDataRequestCultureProvider — A built-in ASP.NET Core provider that reads {culture} from route data. ABP inserts it after QueryStringRequestCultureProvider and before CookieRequestCultureProvider.
  • {culture}/{controller}/{action} route — A conventional route for MVC controllers. The {culture} parameter uses a custom route constraint (AbpCultureRouteConstraint) that only matches culture values configured in AbpLocalizationOptions.Languages, so URLs like /enterprise/products are not mistaken for culture-prefixed routes.
  • AbpCultureRoutePagesConvention — An IPageRouteModelConvention that adds {culture}/... route selectors to all Razor Pages.
  • AbpCultureRouteUrlHelperFactory — Replaces the default IUrlHelperFactory to auto-inject culture into Url.Page() and Url.Action() calls.
  • AbpCultureMenuItemUrlProvider — Prepends the culture prefix to navigation menu item URLs (MVC / Blazor Server).
  • AbpWasmCultureMenuItemUrlProvider — Prepends the culture prefix to menu item URLs in Blazor WebAssembly (reads the UseRouteBasedCulture flag from /api/abp/application-configuration).

You do not need to configure these individually.

URL Generation

When a request has a {culture} route value, all URL generation methods automatically include the culture prefix:

// In a Razor Page — culture is auto-injected, no manual parameter needed
@Url.Page("/About")         // Generates: /zh-Hans/About
@Url.Action("About", "Home") // Generates: /zh-Hans/Home/About

Menu items registered via IMenuContributor also automatically get the culture prefix. No changes are needed in your menu contributors or theme.

Language Switching

ABP's built-in language switcher (the /Abp/Languages/Switch action) automatically replaces the culture segment in the returnUrl. The controller reads the culture from the request cookie to identify the current page culture and replaces it with the new one:

Before switching After switching to English
/tr/products /en/products
/tenant-a/zh-Hans/about /tenant-a/en/about
/home?culture=tr&ui-culture=tr /home?culture=en&ui-culture=en
/about (no prefix) /about (unchanged)

No changes are needed in any theme or language switcher component.

MVC / Razor Pages

MVC and Razor Pages have the most complete support. Everything works automatically when UseRouteBasedCulture = true — route registration, URL generation, menu links, and language switching. No code changes are needed in your pages or controllers.

Blazor Server

Blazor Server uses SignalR (WebSocket) for the interactive circuit. The HTTP middleware pipeline only runs on the initial page load — subsequent interactions happen over the WebSocket connection. ABP handles this by persisting the detected URL culture to a Cookie on the first request, so the entire Blazor circuit uses the correct language.

Culture detection, cookie persistence, menu URLs, and language switching all work automatically. No additional configuration is needed beyond the UseRouteBasedCulture option.

What requires manual changes

Blazor component routes: ASP.NET Core does not provide an IPageRouteModelConvention equivalent for Blazor components. You must manually add the {culture} route to each page:

@page "/"
@page "/{culture}"

@code {
    [Parameter]
    public string? Culture { get; set; }
}
@page "/About"
@page "/{culture}/About"

@code {
    [Parameter]
    public string? Culture { get; set; }
}

This applies to your own application pages. ABP built-in module pages (Identity, Tenant Management, Settings, Account, etc.) already include @page "/{culture}/..." routes out of the box — you do not need to add them manually.

Blazor WebAssembly (WebApp)

Blazor WebAssembly (WASM) runs in the browser. On the first page load, the server renders the page via SSR, and the culture is detected from the URL. After WASM downloads, subsequent renders run in the browser. The WASM app fetches /api/abp/application-configuration from the server to get the current culture, so the culture stays consistent.

Culture detection, cookie persistence, menu URLs, and language switching all work automatically. The WASM client reads the UseRouteBasedCulture flag from the server via /api/abp/application-configuration, so no client-side configuration is needed.

What requires manual changes

Same as Blazor Server — you must manually add @page "/{culture}/..." routes to your Blazor pages.

Angular

The ABP Angular UI runs in the browser. The server still applies UseRouteBasedCulture; the client reads localization.useRouteBasedCulture from /api/abp/application-configuration (same payload as other UI types). There is no separate Angular setting.

Routing

Angular does not add a culture segment to your route config automatically. Use withOptionalRouteCulturePrefix from @abp/ng.core so one route tree matches both /identity/users and /en/identity/users (the first path segment is matched only when it looks like a culture code, e.g. en, tr, zh-Hans).

import { Routes } from '@angular/router';
import { withOptionalRouteCulturePrefix } from '@abp/ng.core';

const appRoutesCore: Routes = [
  // ... your routes (path: '', 'account', 'identity', lazy children, etc.)
];

export const appRoutes = withOptionalRouteCulturePrefix(appRoutesCore);

Angular: routes wrapped with optional culture prefix

URL → session language

When useRouteBasedCulture is true, RouteBasedCultureService (from @abp/ng.core) keeps the session language aligned with the first URL segment after navigation. This runs during application bootstrap and on each NavigationEnd.

Menu paths from RoutesService are usually without a culture prefix (/identity/users). Use the abpRouteCultureUrl pipe on routerLink (or RouteBasedCultureUrlService.prefixPathWithCulture) so links navigate to /en/identity/users when route-based culture is enabled. The Basic theme navigation and Theme Shared breadcrumb links follow this pattern.

Angular: culture-prefixed menu or URL bar

Language switcher (toolbar)

If the user selects a language in the UI, call RouteBasedCultureUrlService.applyLanguageSelection(cultureName) (or navigateToUrlWithCulture) instead of only updating the session language. That rewrites the current URL’s culture segment (or prepends it) so the address bar and session stay consistent; RouteBasedCultureService then picks up the culture from the URL after navigation.

Active menu, breadcrumbs, and route matching

The browser URL may be /en/identity/users while menu items and RoutesService paths stay /identity/users. For comparisons (active state, findRoute, permission guard, dynamic layout), normalize the current URL with RouteBasedCultureUrlService.normalizeForMenuMatch (or stripCulturePrefixIfEnabled) or use getRoutePathForMatching where getRoutePath was used.

Configuration refresh

RouteBasedCultureUrlService refreshes its cached useRouteBasedCulture and languages when application configuration is updated (for example after refreshAppState), so hot paths do not query configuration on every change detection cycle.

Multi-Tenancy Compatibility

URL-based localization is fully compatible with multi-tenancy URL routing. The culture route is registered as a conventional route {culture}/{controller}/{action}. If your application uses tenant routing (e.g., /{tenant}/...), the tenant middleware strips the tenant segment before routing, and the culture segment is handled separately.

Language switching also supports tenant-prefixed URLs. For example, /tenant-a/zh-Hans/About correctly switches to /tenant-a/en/About.

API Routes

Routes like /api/products have no {culture} segment, so RouteDataRequestCultureProvider returns null and falls through to the next provider (Cookie → Accept-Language → default). API routes are completely unaffected.

Culture Detection Priority

ASP.NET Core has a built-in RouteDataRequestCultureProvider (in Microsoft.AspNetCore.Localization.Routing) that reads culture from route data, but it is not included in the default provider list. When UseRouteBasedCulture is enabled, ABP inserts it after QueryStringRequestCultureProvider and before CookieRequestCultureProvider. The resulting provider order is:

  1. QueryStringRequestCultureProvider (ASP.NET Core default — useful for debugging and testing)
  2. RouteDataRequestCultureProvider (URL path — inserted by ABP when enabled)
  3. CookieRequestCultureProvider (ASP.NET Core default)
  4. AcceptLanguageHeaderRequestCultureProvider (ASP.NET Core default)

If a URL contains an invalid culture code (e.g. /xyz1234/page), RequestLocalizationMiddleware ignores it and falls through to the next provider. No error is thrown.