Core 6.0 Web API 本地化 IStringLocalizer 选择不正确的文化
Core 6.0 Web API Localization IStringLocalizer selecting incorrect culture
我正在使用带有本地化功能的 Core 6.0 开发 Web API 项目。
我使用了一些在线指南,主要是 this one
我正在为资源使用外部库。
Program.cs
:
builder.Services.AddLocalization();
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: "en-US");
options.SupportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("he-IL"),
new CultureInfo("ru-RU")
};
options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider { IndexOfCulture = 3 } };
});
builder.Services.Configure<RouteOptions>(options =>
{
options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
});
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
IOptions<RequestLocalizationOptions>? localizationOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
if (localizationOptions != null)
app.UseRequestLocalization(localizationOptions.Value);
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();
扩展方法:
public class LanguageRouteConstraint : IRouteConstraint
{
public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.ContainsKey("lang"))
return false;
string? culture = values["lang"]?.ToString();
return culture == "en-US" || culture == "he-IL" || culture == "ru-RU";
}
}
public class RouteDataRequestCultureProvider : RequestCultureProvider
{
public int IndexOfCulture;
public override Task<ProviderCultureResult?> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
throw new ArgumentNullException(nameof(httpContext));
string? culture = httpContext.Request.Path.Value is not null && httpContext.Request.Path.Value.Split('/').Length > IndexOfCulture ? httpContext.Request.Path.Value?.Split('/')[IndexOfCulture]?.ToString() : null;
ProviderCultureResult? providerResultCulture = culture is null ? null : new(culture);
return Task.FromResult(providerResultCulture);
}
}
控制器:
[Route("[controller]/[action]/{lang:lang?}")]
[ApiController]
public class AccountController : BaseController
{
public AccountController(IStringLocalizer<LangRes.App> localizer) : base(localizer)
{
}
public async Task<IActionResult> Test()
{
return Ok(GetErrorMessage("TEST"));
}
}
和BaseController:
[Route("")]
[ApiController]
public class BaseController : ControllerBase
{
private readonly IStringLocalizer<LangRes.App> localizer;
public BaseController(IStringLocalizer<LangRes.App> localizer)
{
this.localizer = localizer;
}
public string GetErrorMessage(string result)
{
return localizer.GetString(result);
}
}
外部库LangRes
有空App
class和
App.en-US.resx
以 TEST
键作为 This is english
作为值
App.he-IL.resx
以 TEST
键作为 This is hebrew
作为值
App.ru-RU.resx
键 TEST
作为 This is russian
作为值
当使用options.DefaultRequestCulture = new RequestCulture(culture: "en-US")
时,account/Test/he-IL
和account/Test/ru-RU
都不匹配,定位器使用回退en-US
,所以响应是This is english
.
当使用options.DefaultRequestCulture = new RequestCulture(culture: "he-IL")
时:
account/Test/ru-RU
不匹配,定位器使用回退 he-IL
然而 account/Test/en-US
确实匹配正确,结果是 This is english
!
当使用options.DefaultRequestCulture = new RequestCulture(culture: "ru-RU")
时:
account/Test/he-IL
不匹配,定位器使用回退 ru-RU
然而 account/Test/en-US
确实匹配正确,结果是 This is english
!
调试显示 RouteDataRequestCultureProvider
正在为每个请求返回正确的 ProviderCultureResult
文化。
我在这里错过了什么?这似乎不是预期的行为。
Web API IStringLocalizer
的控制器依赖注入依赖于 UiCulture
,而不是 Culture
。
所以这种不稳定的行为是由于我没有在 RequestLocalizationOptions
的选项中定义 SupportedUICultures
造成的。
在 Program.cs
中完成更改:
List<CultureInfo> supportedCultures = new()
{
new CultureInfo("en-us"),
new CultureInfo("he-il"),
new CultureInfo("ru")
};
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: "ru");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures; // important bit
options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider { IndexOfCulture = 3 } };
});
我正在使用带有本地化功能的 Core 6.0 开发 Web API 项目。
我使用了一些在线指南,主要是 this one
我正在为资源使用外部库。
Program.cs
:
builder.Services.AddLocalization();
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: "en-US");
options.SupportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("he-IL"),
new CultureInfo("ru-RU")
};
options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider { IndexOfCulture = 3 } };
});
builder.Services.Configure<RouteOptions>(options =>
{
options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
});
WebApplication app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
IOptions<RequestLocalizationOptions>? localizationOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();
if (localizationOptions != null)
app.UseRequestLocalization(localizationOptions.Value);
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();
扩展方法:
public class LanguageRouteConstraint : IRouteConstraint
{
public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.ContainsKey("lang"))
return false;
string? culture = values["lang"]?.ToString();
return culture == "en-US" || culture == "he-IL" || culture == "ru-RU";
}
}
public class RouteDataRequestCultureProvider : RequestCultureProvider
{
public int IndexOfCulture;
public override Task<ProviderCultureResult?> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
throw new ArgumentNullException(nameof(httpContext));
string? culture = httpContext.Request.Path.Value is not null && httpContext.Request.Path.Value.Split('/').Length > IndexOfCulture ? httpContext.Request.Path.Value?.Split('/')[IndexOfCulture]?.ToString() : null;
ProviderCultureResult? providerResultCulture = culture is null ? null : new(culture);
return Task.FromResult(providerResultCulture);
}
}
控制器:
[Route("[controller]/[action]/{lang:lang?}")]
[ApiController]
public class AccountController : BaseController
{
public AccountController(IStringLocalizer<LangRes.App> localizer) : base(localizer)
{
}
public async Task<IActionResult> Test()
{
return Ok(GetErrorMessage("TEST"));
}
}
和BaseController:
[Route("")]
[ApiController]
public class BaseController : ControllerBase
{
private readonly IStringLocalizer<LangRes.App> localizer;
public BaseController(IStringLocalizer<LangRes.App> localizer)
{
this.localizer = localizer;
}
public string GetErrorMessage(string result)
{
return localizer.GetString(result);
}
}
外部库LangRes
有空App
class和
App.en-US.resx
以 TEST
键作为 This is english
作为值
App.he-IL.resx
以 TEST
键作为 This is hebrew
作为值
App.ru-RU.resx
键 TEST
作为 This is russian
作为值
当使用options.DefaultRequestCulture = new RequestCulture(culture: "en-US")
时,account/Test/he-IL
和account/Test/ru-RU
都不匹配,定位器使用回退en-US
,所以响应是This is english
.
当使用options.DefaultRequestCulture = new RequestCulture(culture: "he-IL")
时:
account/Test/ru-RU
不匹配,定位器使用回退 he-IL
然而 account/Test/en-US
确实匹配正确,结果是 This is english
!
当使用options.DefaultRequestCulture = new RequestCulture(culture: "ru-RU")
时:
account/Test/he-IL
不匹配,定位器使用回退 ru-RU
然而 account/Test/en-US
确实匹配正确,结果是 This is english
!
调试显示 RouteDataRequestCultureProvider
正在为每个请求返回正确的 ProviderCultureResult
文化。
我在这里错过了什么?这似乎不是预期的行为。
Web API IStringLocalizer
的控制器依赖注入依赖于 UiCulture
,而不是 Culture
。
所以这种不稳定的行为是由于我没有在 RequestLocalizationOptions
的选项中定义 SupportedUICultures
造成的。
在 Program.cs
中完成更改:
List<CultureInfo> supportedCultures = new()
{
new CultureInfo("en-us"),
new CultureInfo("he-il"),
new CultureInfo("ru")
};
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(culture: "ru");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures; // important bit
options.RequestCultureProviders = new[] { new RouteDataRequestCultureProvider { IndexOfCulture = 3 } };
});