Localization - qidot/YunstpNetCore GitHub Wiki
多语言的使用
介绍了如何在[ApiController]模式下使用多语言的方式
- 资源文件命名规范
- 配置使用
- controller中使用
- 数据校验中使用
1.资源文件命名规范
文件名格式: filename.xx-XX.resx
Filename 文件名部分,如: HomeController,AboutController,Startup,SharedResource 等
xx 语言部分, 如: en = 英语, zh=中文
XX 地域部分, 如: Hans=中国, Hant=台湾
需要特别注意:
中间的[xx-XX]部分,要参考这个: Rfc4646 标准 ,人为修改的是出不来效果的 参考网址2: https://www.haomeili.net/QuYuDetail?wd=zh-hant
2.配置使用
service注入 && 使用一个公用的 SharedResource
public void ConfigureServices(IServiceCollection services)
{
//全球化-本地化
//指定本地化的resx配置的存放目录
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
.AddDataAnnotationsLocalization(options =>
{
//API模式的时候,[这个在校验返回失败的时候,是无效的]
//2.2进行了前置处理,所以需要特殊处理]
options.DataAnnotationLocalizerProvider = (type, factory) =>
factory.Create(typeof(SharedResource));
})
.AddMvcLocalization()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix) //视图的 全球化-本地化
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.ConfigureApiBehaviorOptions(
//配置DataAnnotations的校验行为
options => {
options.InvalidModelStateResponseFactory = context =>
{
//全球化-本地化的驱动器(否则无法自动渲染本地化配置)
var _localizer = context.HttpContext.RequestServices.GetRequiredService<IStringLocalizer<SharedResource>>();
//设定参数校验行为的返回信息
var problemDetails = new ValidationProblemDetails(context.ModelState);
//从本地化中实例错误信息处理
string errstr = "" + problemDetails.Errors.SelectMany(err => err.Value ).Aggregate("", (current, e) => current + "," + _localizer[e]);
//去除掉最后一位的逗号
errstr = errstr.Trim().Trim(',');
//返回通用的信息类
return new JsonResult(new { message=errstr});
};
}
);
//全球化-本地化:::注册本地化服务,用于全局调用(单一实例)
services.AddSingleton<IStringLocalizer>((sp) =>
{
var sharedLocalizer = sp.GetRequiredService<IStringLocalizer<SharedResource>>();
return sharedLocalizer;
});
//全球化-本地化:::自定义支持的语言集合
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("zh-Hans"),
new CultureInfo("fr")
};
options.DefaultRequestCulture = new RequestCulture("zh-Hans");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
}
中间件中设置支持哪些语言
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//....
#region 全球化-本地化
var supportedCultures = new[] {
new CultureInfo("en-US"),
new CultureInfo("zh-Hans"),
new CultureInfo("fr")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("zh-Hans"),
// Formatting numbers, dates, etc.
SupportedCultures = supportedCultures,
// UI strings that we have localized.
SupportedUICultures = supportedCultures
});
#endregion
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseMvc();
}
3.在controller中使用
//定义(注意这里使用的是公用的SharedResource)
private readonly IStringLocalizer _localizer;
//构造函数渲染
public ValuesController(IStringLocalizer localizer) {
_localizer = localizer;
}
//示例方法
[HttpGet("loc")]
public ActionResult loc()
{
string hello = _localizer["hello"];
return Ok(hello);
}
示例采用了在请求头中设置了当前请求的语言
中文请求示例图
英文请求示例图
法文请求示例图
从以上的请求示例中可以看出,确实实现了不同语言的区分
第二: 我们熟悉的zh-CN,并没有看到,而是zh-Hans,这个就要去阅读以下支持标准了
4.数据校验(DataAnnotations)中使用
不论从官方文档,还是去度出来的文章里面,都是讲的是,在视图层是怎么处理的。但是我们现在压根就没有视图,用的是ApiController的模式,怎么办呢?
2.2中把ValidState状态前置了,压根不会进入到controller中,所以根据上方的拿到IStringLocalizer就是扯淡了
所以需要改动一下代码
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.ConfigureApiBehaviorOptions(
//配置DataAnnotations的校验行为
options => {
options.InvalidModelStateResponseFactory = context =>
{
//全球化-本地化的驱动器(否则无法自动渲染本地化配置)
var _localizer = context.HttpContext.RequestServices.GetRequiredService<IStringLocalizer<SharedResource>>();
//设定参数校验行为的返回信息
var problemDetails = new ValidationProblemDetails(context.ModelState);
//从本地化中实例错误信息处理
string errstr = "" + problemDetails.Errors.SelectMany(err => err.Value ).Aggregate("", (current, e) => current + "," + _localizer[e]);
//去除掉最后一位的逗号
errstr = errstr.Trim().Trim(',');
//返回通用的信息类
return new JsonResult(new { message=errstr});
};
}
);
在dto中如下写法:
public class AppDemoDTO
{
//主键
public int Id { set; get; } //int(10) UNSIGNED 自增编号
//这个我们用了多语言看下效果
[Range(-1, 120, ErrorMessage = "age not more.")]
public int Age { set; get; } = -1; //int(10) UNSIGNED 年龄
[Required(ErrorMessage ="不能为空")]
[StringLength(50, MinimumLength = 0, ErrorMessage = "name not empty")]
public string Name { set; get; } //varchar(50) 名称
}
请求内容:
{
"Name":"wangzh",
"age":200
}
中文请求示例图
英文请求示例图
法文请求示例图
至此,在前后分离的模式下,多语言的相关演示就告一段落了。后续还会结合统一异常捕捉来补充剩余的多语言部分,对相关错误信息的返回同样是需要多语言处理的。至于前端的处理,就交个vue或者react的机制去处理了