我们通过编写Exception来记录系统中发生的任何异常。消息发送到文件。但是,它们是在客户端的文化中编写的。土耳其语的错误对我来说意义不大。

那么,我们如何在不改变用户文化的情况下用英语记录错误消息呢?


当前回答

这可能是一个有争议的观点,但是与其将区域性设置为en-US,不如将其设置为Invariant。在“不变区域性”中,错误消息是英文的。

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;

它的优点是看起来没有偏见,特别是对于非美式英语地区。(也就是避免同事的冷嘲热讽)

其他回答

关于。net Core和以上,线程文档。CurrentUICulture推荐使用CultureInfo。属性检索和设置当前区域性。

CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;

在一个相关的GitHub问题上,Tarek Mahmoud Sayed建议使用CultureInfo。defaultthreadcurrentuicculture以确保稍后创建的其他线程也将获得相同的区域性:

CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

后者只在。net Framework 4.5(和。net Core 1.0)之后才可用。

我知道这是一个古老的话题,但我认为我的解决方案可能与任何在网络搜索中偶然发现它的人非常相关:

在异常记录器中,您可以记录ex.GetType。ToString,它将保存异常类的名称。我希望类的名称应该是独立于语言的,因此总是用英语表示(例如。“system . filenotfoundexception”),尽管目前我还没有一个外语系统来测试这个想法。

如果您真的想要错误消息文本,您可以创建一个字典,其中包含所有可能的异常类名称及其等效消息,无论您喜欢哪种语言,但对于英语,我认为类名已经足够了。

Windows需要安装你想要使用的UI语言。如果没有,它没有办法神奇地知道翻译后的信息是什么。

在安装了pt-PT的en-US windows 7 ultimate中,以下代码:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("pt-PT");
string msg1 = new DirectoryNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
string msg2 = new FileNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
string msg3 = new FileNotFoundException().Message;

生成pt-PT, en-US和en-US格式的消息。由于没有安装法语文化文件,它默认为windows默认(已安装?)语言。

这里有一个解决方案,不需要任何编码,甚至适用于异常的文本加载过早,我们能够通过代码更改(例如,那些在mscorlib)。

它可能并不总是适用于每一种情况(这取决于你的设置,因为你需要能够创建一个。config文件之外的主。exe文件),但这对我来说是可行的。因此,只需在dev中创建一个app.config,(或[myapp].exe。Config或web。Config in production),包含以下行,例如:

<configuration>
  ...
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="mscorlib.resources" publicKeyToken="b77a5c561934e089"
                          culture="fr" /> <!-- change this to your language -->

        <bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Xml.resources" publicKeyToken="b77a5c561934e089"
                          culture="fr" /> <!-- change this to your language -->

        <bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
      </dependentAssembly>

      <!-- add other assemblies and other languages here -->

    </assemblyBinding>
  </runtime>
  ...
</configuration>

它的作用是告诉框架将mscorlib的资源和System.Xml的资源的程序集绑定重定向到一个程序集,用于版本介于1到999之间的法语(文化设置为“fr”)。不存在(任意版本999)。

因此,当CLR为这两个程序集(mscorlib和System.xml)寻找法语资源时,它不会找到它们,而是优雅地回退到英语。根据上下文和测试,您可能希望将其他程序集添加到这些重定向(包含本地化资源的程序集)。

当然,我认为微软不支持这个功能,所以请自行承担使用风险。好吧,如果您发现了问题,您可以删除这个配置并检查它是否无关。

基于Undercover1989答案,但考虑参数以及当消息由多个资源字符串组成时(如参数异常)。

public static string TranslateExceptionMessage(Exception exception, CultureInfo targetCulture)
{
    Assembly a = exception.GetType().Assembly;
    ResourceManager rm = new ResourceManager(a.GetName().Name, a);
    ResourceSet rsOriginal = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true);
    ResourceSet rsTranslated = rm.GetResourceSet(targetCulture, true, true);

    var result = exception.Message;

    foreach (DictionaryEntry item in rsOriginal)
    {
        if (!(item.Value is string message))
            continue;

        string translated = rsTranslated.GetString(item.Key.ToString(), false);

        if (!message.Contains("{"))
        {
            result = result.Replace(message, translated);
        }
        else
        {
            var pattern = $"{Regex.Escape(message)}";
            pattern = Regex.Replace(pattern, @"\\{([0-9]+)\}", "(?<group$1>.*)");

            var regex = new Regex(pattern);

            var replacePattern = translated;
            replacePattern = Regex.Replace(replacePattern, @"{([0-9]+)}", @"${group$1}");
            replacePattern = replacePattern.Replace("\\$", "$");

            result = regex.Replace(result, replacePattern);
        }
    }

    return result;
}