.NET 4.6.2中的多语言数据注释

时间:2016-10-11 12:33:44

标签: .net asp.net-mvc data-annotations .net-4.6.2

我有以下视图模型:

public class LoginViewModel
    {
        [DisplayName("Email Address")]
        [Required(ErrorMessage = "PleaseEnterYourEmail")]
        public string EmailAddress { get; set; }

    }

我有以下资源文件名为:DataAnnotation.Localization.de-DE.resx,这是在App_LocalResources文件夹中

App_LocalResources

Resource file

具有以下属性:

Properties

现在根据blog post announcing.net 4.6.2这应该可行,因为我应该将我的消息的本地化版本返回到视图。

然而,它只是显示:

View

我已经检查了我当前的文化,并将其设置为:de-DE,以便应用知道它需要显示的语言。目标框架也是4.6.2。

我在这里找不到什么东西?

2 个答案:

答案 0 :(得分:2)

最后我找到了解决这个问题的方法。

在这里,我将与其他遇到同样问题的人分享我的解决方案。

将此类添加到您的asp.net核心应用程序:

using System;
using Microsoft.Extensions.Localization;

namespace App.Utilities
{
    public static class StringLocalizerFactoryExtensions
    {
        public static IStringLocalizer CreateConventional<T>(this IStringLocalizerFactory factory)
        {
            return factory.CreateConventional(typeof(T));
        }

        public static IStringLocalizer CreateConventional(this IStringLocalizerFactory factory, Type type)
        {
            if (type.Module.ScopeName != "CommonLanguageRuntimeLibrary")
            {
                string[] parts = type.FullName.Split(new[] { type.Assembly.FullName.Split(',')[0] }, StringSplitOptions.None);

                string name = parts[parts.Length - 1].Trim('.');

                return factory.CreateConventional(name);
            }
            else
            {
                return factory.Create(type);
            }
        }

        public static IStringLocalizer CreateConventional(this IStringLocalizerFactory factory, string resourceName)
        {
            return factory.Create(resourceName, null);
        }

        public static IStringLocalizer CreateDataAnnotation(this IStringLocalizerFactory factory)
        {
            if (type.Module.ScopeName != "CommonLanguageRuntimeLibrary")
            {
                return factory.Create("DataAnnotation.Localization", "App_LocalResources");
            }
            else
            {
                return factory.Create(type);
            }
        }
    }
}

...并在您的Startup.cs文件中替换以下部分:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();

...使用此代码:

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
//The following part includes the change:
.AddDataAnnotationsLocalization(options => options.DataAnnotationLocalizerProvider = (type, factory) => factory.CreateConventional(type));

代码正在处理您的视图模型本地化资源,例如用于视图的资源或可以使用默认IStringLocalizerFactory的任何其他位置。

因此,不再需要DataAnnotation.Localization.de-DE.resx个资源和App_LocalResources文件夹。

  • 只是,使用Models.AccountViewModels.RegisterViewModel.en-US.resx文件夹中的常规命名(Models/AccountViewModels/RegisterViewModel.sv-SE.resxResources创建一系列资源文件,该文件夹通过调用设置services.AddLocalization(options => options.ResourcesPath = "Resources"))你准备好了。 TagHelpers和HtmlHelpers将开始工作并翻译错误消息。

  • 此外,这适用于DisplayAttribute.Name开箱即用。 (v1.1.0-preview1-final + .net v4.6.2)

更新1: 这是我的project.json

{
  "userSecretsId": "...",

  "dependencies": {
    "Microsoft.NETCore.Platforms": "1.1.0-preview1-*",
    "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Diagnostics": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.DataProtection": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Mvc": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview3-final",
    "Microsoft.ApplicationInsights.AspNetCore": "1.0.2",
    "Microsoft.AspNetCore.Mvc.Localization": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Mvc.Razor": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Mvc.TagHelpers": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Mvc.DataAnnotations": "1.1.0-preview1-final",
    "Microsoft.Extensions.Configuration.CommandLine": "1.1.0-preview1-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0-preview1-final",
    "Microsoft.AspNet.WebApi.Client": "5.2.3",
    "Microsoft.AspNetCore.Routing": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.StaticFiles": "1.1.0-preview1-final",
    "Microsoft.EntityFrameworkCore": "1.1.0-preview1-final",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.1.0-preview1-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0-preview1-final",
    "Microsoft.Extensions.Configuration.Json": "1.1.0-preview1-final",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.1.0-preview1-final",
    "Microsoft.Extensions.Logging": "1.1.0-preview1-final",
    "Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
    "Microsoft.Extensions.Logging.Debug": "1.1.0-preview1-final",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0-preview1-final",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": "1.0.0-preview3-final",
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": "1.0.0-preview3-final",
    "Microsoft.AspNetCore.Hosting": "1.1.0-preview1-final",
    "Microsoft.AspNetCore.Hosting.WindowsServices": "1.1.0-preview1-final",
    "Loggr.Extensions.Logging": "1.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0-preview1-final",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview3-final",
    "BundlerMinifier.Core": "2.2.296"
  },
  "tools": {
    "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview3-final",
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview3-final",
    "Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final",
    "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview3-final",
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview3-final",
      "imports": [
        "portable-net45+win8"
      ]
    }
  },
  "frameworks": {
    "net462": {}
  },
  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },
  "publishOptions": {
    "include": [
      "wwwroot",
      "**/*.cshtml",
      "appsettings.json",
      "web.config"
    ]
  },
  "scripts": {
    "prepublish": [ "bower install", "dotnet bundle" ],
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

更新2:如果有人希望代码能够按照DataAnnotation.Localization文件夹中App_LocalResourses的承诺工作,我已更新了StringLocalizerFactoryExtensions代码。使用更新的类和Startup.cs类中的以下代码,它应该可以工作。

services.AddLocalization(options => options.ResourcesPath = "Resources");

services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
//The following part includes the change:
.AddDataAnnotationsLocalization(options => options.DataAnnotationLocalizerProvider = (type, factory) => factory.CreateDataAnnotation());

答案 1 :(得分:2)

blog post announcing .NET Framework 4.6.2中所述的新DataAnnotations本地化功能仅为ASP.NET WebForms 开箱即用

的WebForms ...

.NET Framework 4.6.2中的新本地化功能在类System.Web.ModelBinding.DataAnnotationsModelValidator中实现,该类使用StringLocalizerProviders.DataAnnotationStringLocalizerProvider.GetLocalizedString来解析本地化字符串。

System.Web.Mvc.DataAnnotationsModelValidator默认设置为System.Web.Globalization.ResourceFileStringLocalizerProvider。此提供程序尝试在指定网站的Temporary ASP.NET Files文件夹中找到“App_LocalResources.root”dll。

但是,有一个预先检查是否应该使用功能:

private bool UseStringLocalizerProvider {
    get {
        // if developer already uses existing localization feature,
        // then we don't opt in the new localization feature.
        return (!string.IsNullOrEmpty(Attribute.ErrorMessage) &&
            string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) &&
            Attribute.ErrorMessageResourceType == null);
    }
}

以上检查意味着新的本地化功能仅适用于以下情况:

[Required(ErrorMessage = "FirstName is required")]
public string FirstName { get; set; }

设置ErrorMessage值。对于大多数常见用例:

[Required]
public string FirstName { get; set; }

它回归到遗留名称解析。

在MVC 5中,功能不起作用,因为......

MVC 5使用它自己的特定实现System.Web.Mvc.DataAnnotationsModelValidator。此实现源自Microsoft.AspNet.Mvc版本5.x.x,并且它早于.NET Framework 4.6.2。它没有实现新的本地化功能。

最重要的是,MVC和WebForms的ASP.NET动态编译输出不同,因此WebForms使用的编译资源(例如:de\App_LocalResources.root.q_wjw-ce.resources.dll“)甚至不存在于ASP.NET的App_LocalResources中MVC应用程序。

MVC和WebForms之间的编译输出的这种差异排除了围绕WebForms实现编写包装并在MVC应用程序中“按原样”使用它的可能性。

MVC 6有效,但略有不同......

MVC 6使用第三个实现,Microsoft.AspNetCore.Mvc.DataAnnotations.Internal.DataAnnotationsModelValidator。此实现接受IStringLocalizer stringLocalizer作为构造函数参数。

默认本地化配置可以在Startup.cs中添加为:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc()
        .AddDataAnnotationsLocalization();
}

并且需要Startup.cs Configure(...)方法中的请求本地化,例如:

// Configure the localization options
app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture(new CultureInfo("de-AT")),
    SupportedCultures = new List<CultureInfo>
    {
        new CultureInfo("de")
    },
    SupportedUICultures = new List<CultureInfo>
    {
        new CultureInfo("de-AT")
    }
});

如果我们创建ViewModel:

using System.ComponentModel.DataAnnotations;

namespace WebApplication1.Models
{
    public class User
    {
        [Required(ErrorMessage = "First name is required.")]
        public string FirstName { get; set; }
    }
}

我们必须在Models.User.{culture}.resx的根目录中添加WebApplication文件,并输入一个“名字是必需的”。和本地化验证 - 错误消息。

Model.User.resx file.

尽管MVC 6具有不同的实现,但与WebForms中的ValidationAttribute相同的条件适用。必须定义ErrorMessage,而不应使用ErrorMessageResourceNameErrorMessageResourceType