Localization - qidot/YunstpNetCore GitHub Wiki

多语言的使用

介绍了如何在[ApiController]模式下使用多语言的方式

  1. 资源文件命名规范
  2. 配置使用
  3. controller中使用
  4. 数据校验中使用
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);
}

示例采用了在请求头中设置了当前请求的语言

中文请求示例图

image-20190902161309771

英文请求示例图

image-20190902161218065

法文请求示例图

image-20190902161405559

从以上的请求示例中可以看出,确实实现了不同语言的区分

第二: 我们熟悉的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
}

中文请求示例图

image-20190902162502395

英文请求示例图

image-20190902162434203

法文请求示例图

image-20190902162524516

至此,在前后分离的模式下,多语言的相关演示就告一段落了。后续还会结合统一异常捕捉来补充剩余的多语言部分,对相关错误信息的返回同样是需要多语言处理的。至于前端的处理,就交个vue或者react的机制去处理了