@ -89,12 +89,12 @@ Blazor WebAssembly (WebApp) is similar. The server renders the first page via SS
### What works automatically
### What works automatically
| Feature | How it works |
| Feature | Blazor Server | Blazor WebApp (WASM) |
|---|---|
|---|---|---|
| **Culture detection** | `RouteDataRequestCultureProvider` reads `{culture}`from the URL on the initial HTTP request (SSR). |
| **Culture detection** | `RouteDataRequestCultureProvider` reads `{culture}` on the initial HTTP request (SSR). | Same — SSR on first load. |
| **Cookie persistence** | The middleware saves the detected culture to the`.AspNetCore.Culture` cookie, which persists across the WebSocket connection. |
| **Cookie persistence** | Middleware saves the culture to`.AspNetCore.Culture` cookie, which persists across the WebSocket connection. | Cookie is set during SSR. WASM reads the `UseRouteBasedCulture` flag from `/api/abp/application-configuration`. |
| **Menu URLs** | `AbpCultureMenuItemUrlProvider` prepends the culture prefix. In Blazor interactive circuits (where `HttpContext` is null — no active HTTP request), it falls back to `CultureInfo.CurrentCulture`. |
| **Menu URLs** | `AbpCultureMenuItemUrlProvider` prepends the culture prefix. Falls back to `CultureInfo.CurrentCulture` in interactive circuits where `HttpContext` is null. | `AbpWasmCultureMenuItemUrlProvider` reads the flag and language list from the cached application configuration. |
| **Language switching** | The built-in `LanguageSwitch` component navigates to `/Abp/Languages/Switch` with `forceLoad: true`, triggering a full HTTP reload. The culture segment in the return URL is automatically replaced. |
| **Language switching** | `LanguageSwitch` navigates to `/Abp/Languages/Switch` with `forceLoad: true`, triggering a full HTTP reload. | `LanguageSwitch` replaces the culture segment in the URL client-side and navigates with `forceLoad: true`. |
### Important: Blazor component route limitation
### Important: Blazor component route limitation
@ -128,40 +128,56 @@ You must **manually** add the `{culture}` route to each of your own Blazor pages
### Language switching uses forceLoad
### Language switching uses forceLoad
Language switching in Blazor triggers a **full page reload** rather than a SPA-style client navigation. This is by design — switching languages requires the server-side middleware to set the new culture, update the cookie, and re-render all localized text (menus, labels, content). This is the same behavior as ABP's built-in `LanguageSwitch` component:
Language switching in Blazor triggers a **full page reload** rather than a SPA-style client navigation. This is by design — switching languages requires re-rendering all localized text (menus, labels, content) with the new culture.
**Blazor Server** navigates to `/Abp/Languages/Switch` on the server, which rewrites the culture segment and redirects back:
// WASM client project — no UseRouteBasedCulture configuration needed.
// The WASM client reads the flag from the server via /api/abp/application-configuration.
```
```
## Multi-Tenancy
## Multi-Tenancy
URL-based localization is fully compatible with ABP's multi-tenant routing. The culture route is handled as a separate routing layer from the tenant. Language switching explicitly supports tenant-prefixed URLs, so `/tenant-a/zh-Hans/About → /tenant-a/en/About` works without any additional configuration.
URL-based localization is fully compatible with ABP's multi-tenant routing. The culture route is handled as a separate routing layer from the tenant. Language switching explicitly supports tenant-prefixed URLs, so `/tenant-a/zh-Hans/About → /tenant-a/en/About` works without any additional configuration.
> For details on combining tenant routing with culture routing, see the [Multi-Tenancy](https://docs.abp.io/en/abp/latest/Multi-Tenancy) documentation.
> For details on combining tenant routing with culture routing, see the [Multi-Tenancy](https://abp.io/docs/latest/framework/architecture/multi-tenancy) documentation.
## UI Framework Support Overview
## UI Framework Support Overview
| UI Framework | Route Registration | URL Generation | Menu URLs | Language Switch | Manual Work |
| UI Framework | Route Registration | URL Generation | Menu URLs | Language Switch | Manual Work |
@ -34,7 +34,8 @@ When you set `UseRouteBasedCulture` to `true`, ABP automatically registers the f
* **`{culture}/{controller}/{action}` route** — A conventional route for MVC controllers.
* **`{culture}/{controller}/{action}` route** — A conventional route for MVC controllers.
* **`AbpCultureRoutePagesConvention`** — An `IPageRouteModelConvention` that adds `{culture}/...` route selectors to all Razor Pages.
* **`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.
* **`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.
* **`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.
You do not need to configure these individually.
@ -68,7 +69,7 @@ Menu items registered via `IMenuContributor` also automatically get the culture
## Language Switching
## Language Switching
ABP's built-in language switcher (the `/Abp/Languages/Switch` action) automatically replaces the culture segment in the `returnUrl`. The controller reads `CultureInfo.CurrentCulture` to identify the current culture and replaces it with the new one:
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 |
| Before switching | After switching to English |
|---|---|
|---|---|
@ -172,8 +173,9 @@ Blazor WebAssembly (WASM) runs in the browser. On the **first page load**, the s
|---|---|
|---|---|
| **SSR culture detection** | Same as Blazor Server — `RouteDataRequestCultureProvider` reads `{culture}` on the initial HTTP request. |
| **SSR culture detection** | Same as Blazor Server — `RouteDataRequestCultureProvider` reads `{culture}` on the initial HTTP request. |
| **Cookie persistence** | The cookie is set during SSR, ensuring the WASM client inherits the correct culture. |
| **Cookie persistence** | The cookie is set during SSR, ensuring the WASM client inherits the correct culture. |
| **Menu URLs** | `AbpCultureMenuItemUrlProvider` handles culture prefix for menu items. |
| **Menu URLs** | `AbpWasmCultureMenuItemUrlProvider` prepends the culture prefix to menu items. The `UseRouteBasedCulture` flag is read from `/api/abp/application-configuration`. |
| **Language switching** | Uses the server's `/Abp/Languages/Switch` endpoint, which rewrites the culture segment in the URL and redirects. |
| **Language switching** | The built-in `LanguageSwitch` component replaces the culture segment in the current URL and navigates with `forceLoad: true`, triggering a full page reload with the new culture. |
| **Login link** | The `LoginDisplay` component automatically prepends the culture prefix to the login URL when route-based culture is active. |
// WASM client project — no special configuration needed
// WASM client project — no special UseRouteBasedCulture configuration needed.
// The WASM client reads the flag from the server via /api/abp/application-configuration.
````
````
### Example middleware pipeline
### Example middleware pipeline
@ -216,29 +219,19 @@ Language switching also supports tenant-prefixed URLs. For example, `/tenant-a/z
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.
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.
## FAQ
## Culture Detection Priority
### What happens with an invalid culture code in the URL?
All request culture providers work together in priority order. When `UseRouteBasedCulture` is enabled, the route-based provider is added as the highest priority:
If `/xyz1234/page` is requested and `xyz1234` is not a valid culture, `RequestLocalizationMiddleware` ignores it and falls through to the default culture. No error is thrown.
### Can I mix URL-based and QueryString-based culture detection?
Yes. All providers work together in priority order:
1. `RouteDataRequestCultureProvider` (URL path — highest priority when enabled)
1. `RouteDataRequestCultureProvider` (URL path — highest priority when enabled)
2. `QueryStringRequestCultureProvider`
2. `QueryStringRequestCultureProvider`
3. `CookieRequestCultureProvider`
3. `CookieRequestCultureProvider`
4. `AcceptLanguageHeaderRequestCultureProvider`
4. `AcceptLanguageHeaderRequestCultureProvider`
### Should I keep both localized and non-localized routes?
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.
Yes. ABP automatically registers both `{culture}/{controller}/{action}` and `{controller}/{action}` routes. The second route handles direct navigation to `/` and any controller action that doesn't have a culture prefix.
### Why do Blazor pages need manual `@page "/{culture}/..."` routes?
ASP.NET Core does not provide an `IPageRouteModelConvention` equivalent for Blazor components. Razor Pages routes are discovered through `PageRouteModel` which supports conventions, but Blazor component routes are compiled from `@page` directives into `[RouteAttribute]` at build time, with no runtime extension point. This is an ASP.NET Core platform limitation.
## Route Registration
### Do I need to add `{culture}` routes to ABP module pages (Identity, Settings, etc.)?
ABP automatically registers both `{culture}/{controller}/{action}` and `{controller}/{action}` routes. The non-prefixed route handles direct navigation to `/` and URLs without a culture segment.
No. ABP built-in module pages already ship with`@page "/{culture}/..."` route variants. You only need to add these routes to your own application pages.
> ABP built-in module pages (Identity, Tenant Management, Settings, Account, etc.) already include`@page "/{culture}/..."` route variants out of the box. You only need to add these routes to your own application pages.