Culture & URL Routing
On a multi-language portal, where the active language lives in the URL — and how switching language behaves — is configurable with a single option, UrlCultureStrategy. It governs the whole stack consistently: the server's request routing, the Blazor document's base href and SEO tags, and the <LanguageDropdown /> on both Blazor and React all agree on where the language belongs. Single-language portals are unaffected — there is nothing to negotiate, so every strategy behaves identically.
How the language appears in the URL
Three strategies are available. The default preserves the behavior that shipped before the option existed, so existing portals need no changes.
PathPrefix (default)
The default language is served at bare URLs and every other language under a /{culture} path prefix:
/contacts— the default language, with no prefix./fr/contacts— any non-default language, under its culture prefix.- A prefixed default-language URL (
/en/contacts) permanently redirects to the bare form, and a first-time visitor whose browserAccept-Languagematches a supported non-default language is redirected to that language's prefixed URL — so every page has one canonical, crawlable address per language.
PathPrefixAll
Every language is prefixed, including the default — /en/contacts, /fr/contacts — for a single, symmetric URL shape with no special unprefixed default. A bare page URL redirects to the resolved language's prefix (taken from the culture cookie or Accept-Language, falling back to the default language).
CookieOnly
The language never appears in the URL. It is resolved from the .AspNetCore.Culture cookie (falling back to Accept-Language) and applied in place — no redirects, no path rewriting. Best for SPA-style portals that switch language without navigating.
Choosing a strategy
Set the strategy on LocalizationOptions where you configure localization in your host. It defaults to PathPrefix, so this is opt-in:
builder.Services
.Configure<LocalizationOptions>(options =>
{
// Default is PathPrefix; PathPrefixAll prefixes every language, CookieOnly keeps it out of the URL
options.UrlCultureStrategy = UrlCultureStrategy.PathPrefixAll;
});
That is the only wiring needed — the same option drives the Blazor and React hosts (both configure LocalizationOptions identically), and everything below follows from it.
Base href, canonical & hreflang — handled for you
Whatever strategy you pick, the framework keeps each page's URL-identity markup in sync with it, so search engines and the Blazor circuit always agree on where a language lives:
- Base href — the document's
<base href>tracks the request's path base, so the prerendered page and the Blazor Server circuit resolve the same application root under any prefix. - Canonical URL — each page advertises its canonical address in the active language, prefixed or bare per the strategy.
- hreflang alternates — one alternate link per supported language plus
x-default, each pointing at that language's URL for the current page.
Two framework components emit this markup — <CultureBaseHref /> for the base href and <CultureAlternateLinks /> for the canonical, hreflang, and Open Graph locale tags. Both live in PowerPortalsPro.Web.Blazor.Components and are strategy-aware out of the box; the demo wires them into its App.razor and SEO head component:
@using PowerPortalsPro.Web.Blazor.Components
<head>
<CultureBaseHref />
...
</head>
<CultureAlternateLinks />
Switching language
The <LanguageDropdown /> on both stacks lists the portal's configured languages and switches the active one when the user picks. It follows the configured strategy automatically:
// Same component, same behavior, on the React stack
import { LanguageDropdown } from '@powerportalspro/react-fluent';
<LanguageDropdown /><LanguageDropdown />Under a prefix strategy the switch navigates to the picked language's URL, so the page reloads at its canonical, correctly-prefixed address. Under CookieOnly it switches in place via the culture cookie, with no navigation. Either way the cookie is set, so any other same-origin surface stays in sync.
Reading the strategy in custom UI
Building your own switcher or language-aware links? Read the active strategy directly — server-side from LocalizationOptions in Blazor, or from the localization manifest in React, where buildLocalePath() turns it into a language's URL for the current page:
// The React client reads the strategy from the localization manifest;
// buildLocalePath() turns it into the target URL for a given language.
import { useUrlCultureStrategy, useDefaultLocale, buildLocalePath } from '@powerportalspro/react';
const strategy = useUrlCultureStrategy();
const defaultLocale = useDefaultLocale();@inject IOptions<LocalizationOptions> Options
@code {
// The configured strategy, anywhere you can inject options
private UrlCultureStrategy Strategy => Options.Value.UrlCultureStrategy;
}Note
Everything above takes effect only when a portal supports more than one UI culture. A single-culture site serves every page at its bare URL regardless of the strategy, so there is no redirect or prefix overhead to pay for languages you do not ship.
