You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core设置CultureInfo与RequestCultureFeature后语言未变更问题

问题分析

你遇到的核心问题是:运行时切换语言后,当前请求内的本地化资源仍使用旧区域设置,仅重启应用后新设置才生效。关键原因有三点:

  1. StringLocalizer实例缓存:自定义的JsonStringLocalizer通常是范围(Scoped)实例,请求初期已根据初始文化加载资源,切换文化后未重新获取适配新文化的实例。
  2. 当前请求Claims未更新:RefreshSignInAsync生成新的认证Cookie,但当前请求的HttpContext.User在请求开始时已解析完成,不会自动刷新,导致CustomRequestCultureProvider仍读取旧的PreferredLanguage声明。
  3. 文化变更未触发资源重载:手动设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:23:14