Reputation: 16290
I set up localization in Startup.cs
:
services.AddLocalization(options => options.ResourcesPath = "Resources");
and:
var supportedCultures = new[] { "en-US", "de-DE", "sv-SE" };
app.UseRequestLocalization(supportedCultures);
I also added the following in the body
section of the _Host.cshtml
file:
@{
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(
CultureInfo.CurrentCulture,
CultureInfo.CurrentUICulture)),
new CookieOptions {
Expires = DateTimeOffset.UtcNow.AddYears(1),
SameSite = SameSiteMode.None
}
);
}
I created a culture controller:
[Route("[controller]/[action]")]
public class CultureController : Controller
{
public IActionResult Set(string culture, string redirectUri)
{
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)),
new CookieOptions {
Expires = DateTimeOffset.UtcNow.AddYears(1),
SameSite = SameSiteMode.None
}
);
}
return LocalRedirect(redirectUri);
}
}
And a razor component which has a method to set the culture by doing:
private void Navigate(CultureInfo info)
{
var uri = new Uri(navigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(info.Name);
var uriEscaped = Uri.EscapeDataString(uri);
navigationManager.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
Whilst debugging, the controller action is called with the correct parameters as expected. However, the localization cookie is not being created (checked the Application tab in the Developer tools in Chrome).
The cookie options are:
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
I am also using a custom ticket store for authentication cookies and it is setup as follows:
services.AddSingleton<ITicketStore, CookieMemoryTicketStore>();
services.AddOptions<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme)
.Configure<ITicketStore>((options, store) => {
options.ExpireTimeSpan = TimeSpan.FromDays(14);
options.SlidingExpiration = true;
options.SessionStore = store;
});
EDIT
A blank Blazor server-side app with localization can be found in this Github repo. Changing locale still doesn't work.
UPDATE
The problem lies with the CookiePolicyOptions
above. Culture cookie creation works if the cookie options are changed as follows:
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
});
Which obviously I don't want to do. I need to implement the cookie consent.
How can I implement the cookie policy options and use the culture cookie too?
Upvotes: 3
Views: 1155
Reputation: 11
This worked for me:
builder.Services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
});
Controller:
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)), new CookieOptions { Expires = DateTime.UtcNow.AddYears(1), SameSite = SameSiteMode.Lax });
}
return LocalRedirect(redirectUri);
Upvotes: 1
Reputation: 102
It could be that the context your app is being run in is blocking the cookie. For example, I have noticed that my Blazor app being run within a Microsoft Teams client blocks the setting of the .AspNetCore.Culture cookie. When I go to the Blazor app through the browser directly, I can see it being set correctly.
If this is the case for you, unfortunately, I have no solution for the cookie approach to work. As a workaround, what you could do is manually set the CurrentCulture and CurrentUICulture properties on the current thread wherever localization is relevant. Preferably, this should be somewhere on a top-level thread. You can set it like so:
public static class ThreadExtensions
{
public static void SetCulture(this Thread thread, string culture)
{
if (string.IsNullOrWhiteSpace(culture)) return;
var cultureInfo = new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
In Blazor, I've seen the need to add this at the top of your component HTML area like
@{
Thread.CurrentThread.SetCulture(_culture);
<div>@Localizer["Title"];</div>
}
Upvotes: -1
Reputation: 2032
Try this code:
Add function for RequestLocalizationOptions
in startup:
private RequestLocalizationOptions GetLocalizationOptions()
{
var supportedCultures = new[] { "en-US", "de-DE", "sv-SE" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture("de-DE")
.AddSupportedCultures(supportedCultures )
.AddSupportedUICultures(supportedCultures );
return localizationOptions;
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseRequestLocalization(GetLocalizationOptions());
Continue with your code...
Upvotes: 0