根据文化本地化dataannotation错误消息

时间:2015-10-07 15:11:32

标签: c# .net wpf localization cultureinfo

在我的WPF应用程序中,我将属性定义为以下

[Required(AllowEmptyStrings =false, ErrorMessageResourceName ="Msg1", ErrorMessageResourceType =typeof(*<AssemblyName>*.Resources.*<ResourceFileName>*))]
public string Name
{
    get
    {
        return _name;
    }

    set
    {
        if (_name == value)
        {
            return;
        }
        _name = value;
    }
}

我在单独的程序集中定义了我的错误消息,其中包含不同文化的资源文件,例如Resources.resx,Resources.en-GB.Resx,Resources.fr-FR.Resx,Resources.en-US.Resx等

使用上面的代码,我能够从我的附属程序集中的默认资源文件中检索错误消息,但是我没有看到任何从文化特定资源文件中查找字符串资源的规定。我的意思是如果我的CurrentUICluture设置为英语(英国),那么我想从文件&#34; Resources.en-GB.Resx&#34;中检索资源值。而不是默认文件(即Resources.Resx)。

我没有看到在Required属性定义中传递文化信息的任何方法。此外,我已经测试过它根本不是基于当前文化集查看特定于文化的资源文件。

我想要的是一些使资源检索机制能够识别文化的方法。

谢谢,

3 个答案:

答案 0 :(得分:0)

如果您想要了解您的网站文化,您需要修改system.web元素下web.config中的全球化属性:

Dock

然后它将根据浏览器的首选语言设置查找资源。

或者,您可以明确指定它:

Fill

答案 1 :(得分:0)

最后,我从this link

获得了我的问题的修复程序

在我的应用程序中,我通过在app.xaml.cs文件中放入以下代码来设置启动应用程序时的文化。

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        InitializeCultures();
    }

    private static void InitializeCultures()
    {
        var culture = ConfigurationManager.AppSettings.Get("Culture");
        if (!String.IsNullOrEmpty(culture))
        {
            Thread.CurrentThread.CurrentCulture =  new CultureInfo(culture);
        }

        var UICulture = ConfigurationManager.AppSettings.Get("UICulture");
        if (!String.IsNullOrEmpty(UICulture))
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(UICulture);
        }
    }

然而问题是即使我最初设置了Culture,并非所有线程都会使用我最初设置的相同文化。因此,为我读取资源值的线程仍在使用默认文化,这导致始终从默认文化资源文件而不是文化特定资源文件中读取资源字符串。

所以诀窍是设置我的应用程序中的所有线程使用我最初设置的相同文化。这个

有两个属性
  1. CultureInfo.DefaultThreadCurrentCulture
  2. CultureInfo.DefaultThreadCurrentUICulture
  3. 最初将所需的文化值设置为这两个属性将确保应用程序中使用的所有后续线程都具有与用户设置的相同的文化。这两个属性在当前应用程序域中的所有线程上设置文化。

    一旦正确设置了文化,资源价值的读取本身就会成为文化意识,并从文化特定的资源文件中读取资源值。

    以下是InitializeCulture方法的更新版本:

        private static void InitializeCultures()
        {
            var culture = ConfigurationManager.AppSettings.Get("Culture");
            if (!String.IsNullOrEmpty(culture))
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.DefaultThreadCurrentCulture =  new CultureInfo(culture);
            }
    
            var UICulture = ConfigurationManager.AppSettings.Get("UICulture");
            if (!String.IsNullOrEmpty(UICulture))
            {
                Thread.CurrentThread.CurrentUICulture = CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(UICulture);
            }
        }
    

    P.S。在Web应用程序中使用此修复程序时需要注意。请在原始链接上阅读。

    希望这会有所帮助......

答案 2 :(得分:0)

我想到了一个简单的主意,使我免于单独装饰所有属性。 确实是一个令人讨厌的解决方案,因为它涉及反射但有效。

警告:如果.NET Core团队决定重命名字段或类或内部内容发生更改,则此操作可能会中断,因此请自行决定使用。

首先在应用中创建一个 resx 文件,或者从头开始创建一个文件,或者通过复制thisthis一个文件,将字符串替换为所需的翻译,与其显示的格式相同(请注意{0}占位符及其顺序)。
显然,只要您的应用properly set可以按照所需的区域性进行操作,就可以添加DataAnnotations.en-UK.resx类文件并将其全部翻译。

在您的项目中,在早期启动时调用以下命令:

void InitializeDataAnnotationsCulture()
{
  var sr = 
    typeof(ValidationAttribute)
      .Assembly
      .DefinedTypes
      .Single(t => t.FullName == "System.SR");

  var resourceManager = 
    sr
      .DeclaredFields
      .Single(f => f.IsStatic && f.Name == "s_resourceManager");

  resourceManager
    .SetValue(null, 
      DataAnnotationsResources.ResourceManager, /* The generated RESX class in my proj */
      BindingFlags.NonPublic | BindingFlags.Static, null, null);

  var injected = resourceManager.GetValue(null) == DataAnnotationsResources.ResourceManager;
  Debug.Assert(injected);
}

它的作用是利用this字段将默认的DataAnnotations资源管理器替换为您自己的资源管理器。

它已经过测试并且可以在.NET Core 3.1 WPF中使用,但是您可以浏览任何.NET的.NET源代码以查找资源位置并注入您自己的资源。