根据区域性本地化数据注释错误消息

本文关键字:注释 错误 消息 数据 本地化 区域性 | 更新日期: 2023-09-27 18:16:23

在我的WPF应用程序中,我定义了如下属性

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

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

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

我看不出有任何方法可以在Required属性定义中传递区域性信息。此外,我还测试了它本身并不会基于当前区域性集查看特定于区域性的资源文件。

我想要的是某种方法使资源检索机制意识到文化。

谢谢,

根据区域性本地化数据注释错误消息

我想出了一个简单的想法,使我免于单独装饰所有属性。确实是一个讨厌的解决方案,因为它涉及反射,但工作。

注意:如果. net Core团队决定重命名字段或类,或者内部内容发生变化,这可能会中断,所以请自行决定使用

首先在你的应用程序中创建一个resx文件,要么从头开始创建一个,要么复制这个或这个,用所需的翻译替换字符串,以相同的格式出现(注意{0}占位符及其顺序)。
显然,你可以添加类似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);
}

它所做的是利用这个字段替换默认的DataAnnotations资源管理器与您自己的

它已经在。net Core 3.1 WPF中进行了测试和工作,但是你可以浏览任何。net的。net源代码来找到资源位置并注入你自己的资源。

如果你想让你的网站有文化意识,你需要修改全球化属性。在系统下配置。web元素:

<globalization fileEncoding="utf-8" requestEncoding="utf-8" culture="auto" uiCulture="auto" enableClientBasedCulture="true" />

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

或者,您可以显式地指定它:

<globalization fileEncoding="utf-8" requestEncoding="utf-8" responseEncoding="" culture="en-US" uiCulture="en-US" />

最后我得到了修复我的问题从这个链接

在我的应用程序中,我在启动应用程序时通过在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);
        }
    }

然而问题是,即使我最初设置文化,并不是所有的线程都将使用我最初设置的相同文化。因此,为我读取资源值的线程仍然使用默认区域性,这导致总是从默认区域性资源文件读取资源字符串,而不是特定于区域性的资源文件。

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

有两个属性
  1. CultureInfo。DefaultThreadCurrentCulture
  2. CultureInfo。DefaultThreadCurrentUICulture

最初为这两个属性设置所需的区域性值将确保应用程序中使用的所有后续线程具有与用户设置的相同的区域性。这两个属性设置当前应用域中所有线程的区域性。

一旦正确设置了区域性,读取资源值本质上就会意识到区域性,并从特定于区域性的资源文件中读取资源值。

所以下面是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);
        }
    }

注:在web应用程序中使用此修复需要注意的是。请在原始链接上阅读。