Reputation: 2780
We are getting an strange behavior in multi-language development in ASP.NET Core Razor pages based application, IStringLocalizer object that we are using in .cshtml pages is recognizing the currently selected culture and translating all elements correctly those are on .cshtml file as per selected culture's resource files, but same object used inside page models (i.e. .cshtml.cs) files, is always translating into browser default language when requested through AJAX GET or POST method. Its not able to recognize currently selected culture. Used QueryStringRequestCultureProvider.
This is what working in .cshtml page and its translating as per the culture selected in String
@page
@inject IStringLocalizer<IndexModel> localizer
@model IndexModel
@{
ViewData["Title"] = "Home page";
var requestCultureFeature = HttpContext.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
}
<div class="text-center">
<h1 class="display-4">@localizer["Welcome"]</h1>
</div>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"></script>
<script lang="javascript">
$(document).ready(function () {
$("#btnnsubmit").click(function () {
var obj = {};
obj.name = "name";
//url
$.ajax({
type: "Get",
url: '/Index?handler=callingAjax',
data: obj,
dataType: "html",
contentType: "application/json; charset=utf-8",
success: function () {
debugger;
},
error: function () {
}
});
});
});
</script>
This is what I have done in page models (i.e. in .cshtml.cs pages) and it always translating into browser's default language.
public class IndexModel : PageModel
{
public string Message { get; set; }
private readonly ILogger log;
private readonly IStringLocalizer<IndexModel> localizer;
public IndexModel(ILogger<IndexModel> log, IStringLocalizer<IndexModel> _localizer)
{
this.log = log;
localizer = _localizer;
}
public void OnGet()
{
// Called on page load without AJAX
//Localization is working here, gives translation based on selected
//language
string str = _localizer["InvalidLoginAttempt"];
}
public IActionResult OnGetCallingAjax()
{
int MaxThreads = 1;
// Called using AJAX
//Localization is not working here, always gives translation based on
//browsers default language,
string str1 = _localizer["InvalidLoginAttempt"];
string message = "SUCCESS";
return new JsonResult(new
{
Error = false,
Message = message,
// lstlang = lstlanguage
});
}
}
Below are the Startup file setting.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("de"),
new CultureInfo("fr"),
new CultureInfo("en"),
new CultureInfo("nl"),
};
options.DefaultRequestCulture = new RequestCulture("de");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders = new List<IRequestCultureProvider>
{
new QueryStringRequestCultureProvider(),
new CookieRequestCultureProvider()
};
});
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(30); //default is 20 min
});
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMemoryCache();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net();
Log4NetFilters.Set( // filter out the standard log messages with source "Microsoft"
source: "Microsoft",
filteredLogLevel: LogLevel.Information);
ILogger logger = loggerFactory.CreateLogger<Program>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStaticFiles();
//app.UseRouting();
app.UseSession();
app.UseCookiePolicy();
app.UseHttpsRedirection();
var localizationOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization(localizationOptions);
app.UseMvc();
}
Upvotes: 0
Views: 1921
Reputation: 189
From the comments, seems that the issue is that you were just providing the culture in the query string of the initial request and not storing it anywhere, hence the culture isn't used in posterior requests, AJAX ones included.
Putting the culture in the query string everywhere works, but it's probably not ideal.
In your Startup
, you're setting up CookieRequestCultureProvider
, so you can make use of that instead of putting things in the query string every time.
As an example, you could create an action that can be invoked to store the culture preferences in a cookie:
public class CultureController : Controller
{
[HttpPost]
public IActionResult SelectCulture(string culture, string returnUrl)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
);
return LocalRedirect(returnUrl);
}
}
Doing this, the CookieRequestCultureProvider
would pick up the user preference.
Upvotes: 1