ASP.NET Core设置CultureInfo与RequestCultureFeature后语言未变更问题
问题分析
你遇到的核心问题是:运行时切换语言后,当前请求内的本地化资源仍使用旧区域设置,仅重启应用后新设置才生效。关键原因有三点:
StringLocalizer实例缓存:自定义的JsonStringLocalizer通常是范围(Scoped)实例,请求初期已根据初始文化加载资源,切换文化后未重新获取适配新文化的实例。- 当前请求Claims未更新:
RefreshSignInAsync生成新的认证Cookie,但当前请求的HttpContext.User在请求开始时已解析完成,不会自动刷新,导致CustomRequestCultureProvider仍读取旧的PreferredLanguage声明。 - 文化变更未触发资源重载:手动设置
CultureInfo和IRequestCultureFeature后,已初始化的StringLocalizer不会自动感知文化变更,无法加载新资源。
解决方案
1. 修改JsonStringLocalizerFactory支持动态文化切换
让工厂类根据当前UICulture生成缓存键,确保不同文化对应不同的本地化实例:
public class JsonStringLocalizerFactory : IStringLocalizerFactory { private readonly IHostingEnvironment _hostingEnv; private readonly IMemoryCache _cache; public JsonStringLocalizerFactory(IHostingEnvironment hostingEnv, IMemoryCache cache) { _hostingEnv = hostingEnv; _cache = cache; } public IStringLocalizer Create(Type resourceSource) { return Create(resourceSource.FullName, resourceSource.Assembly.GetName().Name); } public IStringLocalizer Create(string baseName, string location) { // 用当前UICulture作为缓存键的一部分,避免跨文化缓存冲突 var cacheKey = $"{baseName}_{location}_{CultureInfo.CurrentUICulture.Name}"; return _cache.GetOrCreate(cacheKey, entry => { entry.SlidingExpiration = TimeSpan.FromMinutes(10); return new JsonStringLocalizer(_hostingEnv, baseName, location); }); } }
2. 在ChangeLanguage端点重新获取StringLocalizer
切换文化后,从服务容器重新获取本地化实例,确保使用新的文化配置:
[HttpPost] public async Task<IActionResult> ChangeLanguage([FromBody] LanguageRequest languageRequest) { if (string.IsNullOrEmpty(languageRequest.LanguageCode)) { return BadRequest("Language code is required."); } var user = await userManager.GetUserAsync(User); if (user == null) return Unauthorized(); user.PreferredLanguage = languageRequest.LanguageCode; var result = await userManager.UpdateAsync(user); if (!result.Succeeded) return BadRequest(result.Errors); await signInManager.RefreshSignInAsync(user); // 设置当前请求的文化 var culture = new CultureInfo(languageRequest.LanguageCode); CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = culture; var requestCultureFeature = new RequestCultureFeature(new RequestCulture(culture), null); HttpContext.Features.Set<IRequestCultureFeature>(requestCultureFeature); // 手动更新当前请求的Claims(可选,若业务依赖User声明) var identity = User.Identity as ClaimsIdentity; identity?.RemoveClaim(identity.FindFirst("PreferredLanguage")); identity?.AddClaim(new Claim("PreferredLanguage", languageRequest.LanguageCode)); HttpContext.User = new ClaimsPrincipal(identity); // 重新获取本地化实例,验证新资源 var localizer = HttpContext.RequestServices.GetRequiredService<IStringLocalizer<YourController>>(); var testLocalizedText = localizer["SampleKey"]; return Ok(new { success = true, preview = testLocalizedText }); }
3. 调整中间件执行顺序
确保RequestLocalizationMiddleware在UserCultureMiddleware之前执行,避免文化设置冲突:
// Program.cs app.UseRequestLocalization(); app.UseMiddleware<UserCultureMiddleware>();
验证要点
- 检查切换文化后,重新获取的
StringLocalizer是否返回目标语言的资源。 - 确认控制台输出的
CultureInfo.CurrentUICulture.Name为目标语言代码。 - 验证后续新请求是否自动应用新的语言设置。
内容的提问来源于stack exchange,提问作者Soner Kochan
相关产品推荐
相关产品推荐

