Pregunta

Estamos registrando cualquier excepción que ocurra en nuestro sistema escribiendo Exception.Message en un archivo. Sin embargo, están escritos en la cultura del cliente. Y los errores turcos no significan mucho para mí.

Entonces, ¿cómo podemos registrar cualquier mensaje de error en inglés sin cambiar la cultura de los usuarios?

¿Fue útil?

Solución

Este problema puede solucionarse parcialmente. El código de excepción de Framework carga los mensajes de error de sus recursos, en función de la configuración regional de subproceso actual. En el caso de algunas excepciones, esto sucede en el momento en que se accede a la propiedad Mensaje.

Para esas excepciones, puede obtener la versión completa del mensaje en inglés de EE. UU. cambiando brevemente la configuración regional del hilo a en-US mientras la registra (guardando la configuración regional original del usuario de antemano y restaurándola inmediatamente después).

Hacer esto en un hilo separado es aún mejor: esto asegura que no habrá efectos secundarios. Por ejemplo:

try
{
  System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
  Console.WriteLine(ex.ToString()); //Will display localized message
  ExceptionLogger el = new ExceptionLogger(ex);
  System.Threading.Thread t = new System.Threading.Thread(el.DoLog);
  t.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
  t.Start();
}

Donde la clase ExceptionLogger se parece a:

class ExceptionLogger
{
  Exception _ex;

  public ExceptionLogger(Exception ex)
  {
    _ex = ex;
  }

  public void DoLog()
  {
    Console.WriteLine(_ex.ToString()); //Will display en-US message
  }
}

Sin embargo, como Joe señala correctamente en un comentario sobre una revisión anterior de esta respuesta, algunos mensajes ya están ( parcialmente) cargado de los recursos del idioma en el momento en que se produce la excepción.

Esto se aplica a la parte 'parámetro no puede ser nulo' del mensaje generado cuando se genera una excepción ArgumentNullException (" foo "), por ejemplo. En esos casos, el mensaje seguirá apareciendo (parcialmente) localizado, incluso cuando se use el código anterior.

Aparte de utilizar hacks poco prácticos, como ejecutar todo el código que no sea de UI en un hilo con configuración regional en-EE. UU., para empezar, no parece haber mucho que pueda hacer al respecto: la excepción de .NET Framework el código no tiene facilidades para anular la configuración regional del mensaje de error.

Otros consejos

Puede buscar el mensaje de excepción original en unlocalize.com

Quizás sea un punto polémico, pero en lugar de establecer la cultura en en-US , puede establecerlo en Invariante . En la cultura Invariant , los mensajes de error están en inglés.

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

Tiene la ventaja de no parecer sesgada, especialmente para los idiomas de habla no inglesa. (también conocido como evita comentarios sarcásticos de colegas)

Windows necesita tener instalado el idioma de la IU que desea utilizar. Si no es así, no tiene forma de saber mágicamente cuál es el mensaje traducido.

En un Windows 7 ultimate en-US, con pt-PT instalado, el siguiente código:

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;

Produce mensajes en pt-PT, en-US y en-US. Como no hay archivos de cultura francesa instalados, el valor predeterminado es el idioma predeterminado de Windows (¿instalado?).

Aquí hay una solución que no requiere ninguna codificación y funciona incluso para textos de excepciones que se cargan demasiado pronto para que podamos cambiar por código (por ejemplo, aquellos en mscorlib).

Puede que no siempre sea aplicable en todos los casos (depende de su configuración, ya que necesita poder crear un archivo .config aparte del archivo .exe principal), pero eso funciona para mí. Entonces, simplemente cree un app.config en dev, (o un [myapp] .exe.config o web.config en producción) que contiene las siguientes líneas, por ejemplo:

<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>

Lo que esto hace es decirle al marco que redirija los enlaces de ensamblaje para los recursos de mscorlib y los recursos de System.Xml , para versiones entre 1 y 999, en francés (la cultura se establece en " fr ") en un ensamblaje que ... no existe (una versión arbitraria 999).

Entonces, cuando el CLR buscará recursos en francés para estos dos ensamblados (mscorlib y System.xml), no los encontrará y recurrirá al inglés con gracia. Dependiendo de su contexto y pruebas, es posible que desee agregar otros ensamblados a estos redireccionamientos (ensamblajes que contienen recursos localizados).

Por supuesto, no creo que Microsoft lo admita, así que úselo bajo su propio riesgo. Bueno, en caso de que detecte un problema, puede eliminar esta configuración y verificar que no esté relacionada.

Sé que este es un tema antiguo, pero creo que mi solución puede ser bastante relevante para cualquiera que se encuentre con ella en una búsqueda en la web:

En el registrador de excepciones, puede registrar ex.GetType.ToString, lo que guardaría el nombre de la clase de excepción. Esperaría que el nombre de una clase sea independiente del idioma y, por lo tanto, siempre esté representado en inglés (por ejemplo, "System.FileNotFoundException"), aunque actualmente no tengo acceso a un sistema de idioma extranjero para probar la idea.

Si realmente desea también el texto del mensaje de error, puede crear un diccionario de todos los posibles nombres de clase de excepción y sus mensajes equivalentes en el idioma que prefiera, pero para el inglés creo que el nombre de la clase es perfectamente adecuado.

CultureInfo oldCI = Thread.CurrentThread.CurrentCulture;

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en-US");
Thread.CurrentThread.CurrentUICulture=new CultureInfo("en-US");
try
{
  System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
  Console.WriteLine(ex.ToString())
}
Thread.CurrentThread.CurrentCulture = oldCI;
Thread.CurrentThread.CurrentUICulture = oldCI;

Sin WORKAROUNDS.

Tks :)

El marco .NET viene en dos partes:

  1. El marco .NET en sí
  2. Los paquetes de idioma del framework .NET

Todos los textos (por ejemplo, mensajes de excepción, etiquetas de botones en un cuadro de mensaje, etc.) están en inglés en el propio marco .NET. Los paquetes de idiomas tienen los textos localizados.

Dependiendo de su situación exacta, una solución sería desinstalar los paquetes de idioma (es decir, decirle al cliente que lo haga). En ese caso, los textos de excepción estarán en inglés. Sin embargo, tenga en cuenta que el resto del texto proporcionado por el marco también estará en inglés (por ejemplo, las etiquetas de los botones en un cuadro de mensaje, métodos abreviados de teclado para los comandos de aplicación).

La configuración de Thread.CurrentThread.CurrentUICulture se utilizará para localizar las excepciones. Si necesita dos tipos de excepciones (una para el usuario y otra para usted), puede usar la siguiente función para traducir el mensaje de excepción. Está buscando en los recursos de las Bibliotecas .NET el texto original para obtener la clave de recursos y luego devuelve el valor traducido. Pero hay una debilidad que todavía no encontré una buena solución: los mensajes que contienen {0} en recursos no se encontrarán. Si alguien tiene una buena solución, se lo agradecería.

public static string TranslateExceptionMessage(Exception E, CultureInfo targetCulture)
{
    try
    {
        Assembly a = E.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);
        foreach (DictionaryEntry item in rsOriginal)
            if (item.Value.ToString() == E.Message.ToString())
                return rsTranslated.GetString(item.Key.ToString(), false); // success

    }
    catch { }
    return E.Message; // failed (error or cause it's not intelligent enough to locale '{0}'-patterns
}

Me imagino uno de estos enfoques:

1) Las excepciones solo son leídas por usted, es decir, no son una característica del cliente, por lo que puede usar cadenas cableadas no localizadas que no cambiarán cuando se ejecute en modo turco.

2) Incluya un código de error, por ejemplo. 0X00000001 con cada error para que pueda buscarlo fácilmente en una tabla en inglés.

He tenido la misma situación, y todas las respuestas que encontré aquí y en otros lugares no ayudaron o no fueron satisfactorias:
Forzar idioma de excepciones en inglés
C # - Obteniendo mensajes de excepción en ¿Inglés cuando la aplicación está en otro idioma?
Cómo cambiar el idioma de los mensajes de excepción de Visual Studio al inglés durante la depuración
¿Cómo manejar la traducción del mensaje de excepción?
Cómo evitar completamente los mensajes de excepción .NET localizados

El Thread.CurrentUICulture cambia el idioma de las excepciones .net, pero no lo hace para Win32Exception , que utiliza recursos de Windows en el idioma de la interfaz de usuario de Windows. Así que nunca logré imprimir los mensajes de Win32Exception en inglés en lugar de alemán, ni siquiera usando FormatMessage () como se describe en
¿Cómo obtener Win32Exception en inglés?

Por lo tanto, creé mi propia solución, que almacena la mayoría de los mensajes de excepción existentes para diferentes idiomas en archivos externos. No recibirá el mensaje exacto en su idioma deseado, pero recibirá un mensaje en ese idioma, que es mucho más de lo que actualmente recibe (que es un mensaje en un idioma que probablemente no entienda).

Las funciones estáticas de esta clase se pueden ejecutar en instalaciones de Windows con diferentes idiomas: CreateMessages () crea los textos específicos de la cultura
SaveMessagesToXML () los guarda en tantos archivos XML como idiomas se crean o cargan
LoadMessagesFromXML () carga todos los archivos XML con mensajes específicos del idioma

Al crear los archivos XML en diferentes instalaciones de Windows con diferentes idiomas, pronto tendrá todos los idiomas que necesita.
Tal vez pueda crear los textos para diferentes idiomas en 1 Windows cuando tenga instalados varios paquetes de idiomas MUI, pero aún no lo he probado.

Probado con VS2008, listo para usar. ¡Comentarios y sugerencias son bienvenidos!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Xml;

public struct CException
{
  //----------------------------------------------------------------------------
  public CException(Exception i_oException)
  {
    m_oException = i_oException;
    m_oCultureInfo = null;
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  public CException(Exception i_oException, string i_sCulture)
  {
    m_oException = i_oException;
    try
    { m_oCultureInfo = new CultureInfo(i_sCulture); }
    catch
    { m_oCultureInfo = CultureInfo.InvariantCulture; }
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  public CException(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    m_oException = i_oException;
    m_oCultureInfo = i_oCultureInfo == null ? CultureInfo.InvariantCulture : i_oCultureInfo;
    m_sMessage = null;
  }

  //----------------------------------------------------------------------------
  // GetMessage
  //----------------------------------------------------------------------------
  public string GetMessage() { return GetMessage(m_oException, m_oCultureInfo); }

  public string GetMessage(String i_sCulture) { return GetMessage(m_oException, i_sCulture); }

  public string GetMessage(CultureInfo i_oCultureInfo) { return GetMessage(m_oException, i_oCultureInfo); }

  public static string GetMessage(Exception i_oException) { return GetMessage(i_oException, CultureInfo.InvariantCulture); }

  public static string GetMessage(Exception i_oException, string i_sCulture)
  {
    CultureInfo oCultureInfo = null;
    try
    { oCultureInfo = new CultureInfo(i_sCulture); }
    catch
    { oCultureInfo = CultureInfo.InvariantCulture; }
    return GetMessage(i_oException, oCultureInfo);
  }

  public static string GetMessage(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    if (i_oException == null) return null;
    if (i_oCultureInfo == null) i_oCultureInfo = CultureInfo.InvariantCulture;

    if (ms_dictCultureExceptionMessages == null) return null;
    if (!ms_dictCultureExceptionMessages.ContainsKey(i_oCultureInfo))
      return CreateMessage(i_oException, i_oCultureInfo);

    Dictionary<string, string> dictExceptionMessage = ms_dictCultureExceptionMessages[i_oCultureInfo];
    string sExceptionName = i_oException.GetType().FullName;
    sExceptionName = MakeXMLCompliant(sExceptionName);
    Win32Exception oWin32Exception = (Win32Exception)i_oException;
    if (oWin32Exception != null)
      sExceptionName += "_" + oWin32Exception.NativeErrorCode;
    if (dictExceptionMessage.ContainsKey(sExceptionName))
      return dictExceptionMessage[sExceptionName];
    else
      return CreateMessage(i_oException, i_oCultureInfo);
  }

  //----------------------------------------------------------------------------
  // CreateMessages
  //----------------------------------------------------------------------------
  public static void CreateMessages(CultureInfo i_oCultureInfo)
  {
    Thread oTH = new Thread(new ThreadStart(CreateMessagesInThread));
    if (i_oCultureInfo != null)
    {
      oTH.CurrentCulture = i_oCultureInfo;
      oTH.CurrentUICulture = i_oCultureInfo;
    }
    oTH.Start();
    while (oTH.IsAlive)
    { Thread.Sleep(10); }
  }

  //----------------------------------------------------------------------------
  // LoadMessagesFromXML
  //----------------------------------------------------------------------------
  public static void LoadMessagesFromXML(string i_sPath, string i_sBaseFilename)
  {
    if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;

    string[] asFiles = null;
    try
    {
      asFiles = System.IO.Directory.GetFiles(i_sPath, i_sBaseFilename + "_*.xml");
    }
    catch { return; }

    ms_dictCultureExceptionMessages.Clear();
    for (int ixFile = 0; ixFile < asFiles.Length; ixFile++)
    {
      string sXmlPathFilename = asFiles[ixFile];

      XmlDocument xmldoc = new XmlDocument();
      try
      {
        xmldoc.Load(sXmlPathFilename);
        XmlNode xmlnodeRoot = xmldoc.SelectSingleNode("/" + msc_sXmlGroup_Root);

        string sCulture = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Info + "/" + msc_sXmlData_Culture).Value;
        CultureInfo oCultureInfo = new CultureInfo(sCulture);

        XmlNode xmlnodeMessages = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Messages);
        XmlNodeList xmlnodelistMessage = xmlnodeMessages.ChildNodes;
        Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(xmlnodelistMessage.Count + 10);
        for (int ixNode = 0; ixNode < xmlnodelistMessage.Count; ixNode++)
          dictExceptionMessage.Add(xmlnodelistMessage[ixNode].Name, xmlnodelistMessage[ixNode].InnerText);
        ms_dictCultureExceptionMessages.Add(oCultureInfo, dictExceptionMessage);
      }
      catch
      { return; }
    }
  }

  //----------------------------------------------------------------------------
  // SaveMessagesToXML
  //----------------------------------------------------------------------------
  public static void SaveMessagesToXML(string i_sPath, string i_sBaseFilename)
  {
    if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;

    foreach (KeyValuePair<CultureInfo, Dictionary<string, string>> kvpCultureExceptionMessages in ms_dictCultureExceptionMessages)
    {
      string sXmlPathFilename = i_sPath + i_sBaseFilename + "_" + kvpCultureExceptionMessages.Key.TwoLetterISOLanguageName + ".xml";
      Dictionary<string, string> dictExceptionMessage = kvpCultureExceptionMessages.Value;

      XmlDocument xmldoc = new XmlDocument();
      XmlWriter xmlwriter = null;
      XmlWriterSettings writerSettings = new XmlWriterSettings();
      writerSettings.Indent = true;

      try
      {
        XmlNode xmlnodeRoot = xmldoc.CreateElement(msc_sXmlGroup_Root);
        xmldoc.AppendChild(xmlnodeRoot);
        XmlNode xmlnodeInfo = xmldoc.CreateElement(msc_sXmlGroup_Info);
        XmlNode xmlnodeMessages = xmldoc.CreateElement(msc_sXmlGroup_Messages);
        xmlnodeRoot.AppendChild(xmlnodeInfo);
        xmlnodeRoot.AppendChild(xmlnodeMessages);

        XmlNode xmlnodeCulture = xmldoc.CreateElement(msc_sXmlData_Culture);
        xmlnodeCulture.InnerText = kvpCultureExceptionMessages.Key.Name;
        xmlnodeInfo.AppendChild(xmlnodeCulture);

        foreach (KeyValuePair<string, string> kvpExceptionMessage in dictExceptionMessage)
        {
          XmlNode xmlnodeMsg = xmldoc.CreateElement(kvpExceptionMessage.Key);
          xmlnodeMsg.InnerText = kvpExceptionMessage.Value;
          xmlnodeMessages.AppendChild(xmlnodeMsg);
        }

        xmlwriter = XmlWriter.Create(sXmlPathFilename, writerSettings);
        xmldoc.WriteTo(xmlwriter);
      }
      catch (Exception e)
      { return; }
      finally
      { if (xmlwriter != null) xmlwriter.Close(); }
    }
  }

  //----------------------------------------------------------------------------
  // CreateMessagesInThread
  //----------------------------------------------------------------------------
  private static void CreateMessagesInThread()
  {
    Thread.CurrentThread.Name = "CException.CreateMessagesInThread";

    Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(0x1000);

    GetExceptionMessages(dictExceptionMessage);
    GetExceptionMessagesWin32(dictExceptionMessage);

    ms_dictCultureExceptionMessages.Add(Thread.CurrentThread.CurrentUICulture, dictExceptionMessage);
  }

  //----------------------------------------------------------------------------
  // GetExceptionTypes
  //----------------------------------------------------------------------------
  private static List<Type> GetExceptionTypes()
  {
    Assembly[] aoAssembly = AppDomain.CurrentDomain.GetAssemblies();

    List<Type> listoExceptionType = new List<Type>();

    Type oExceptionType = typeof(Exception);
    for (int ixAssm = 0; ixAssm < aoAssembly.Length; ixAssm++)
    {
      if (!aoAssembly[ixAssm].GlobalAssemblyCache) continue;
      Type[] aoType = aoAssembly[ixAssm].GetTypes();
      for (int ixType = 0; ixType < aoType.Length; ixType++)
      {
        if (aoType[ixType].IsSubclassOf(oExceptionType))
          listoExceptionType.Add(aoType[ixType]);
      }
    }

    return listoExceptionType;
  }

  //----------------------------------------------------------------------------
  // GetExceptionMessages
  //----------------------------------------------------------------------------
  private static void GetExceptionMessages(Dictionary<string, string> i_dictExceptionMessage)
  {
    List<Type> listoExceptionType = GetExceptionTypes();
    for (int ixException = 0; ixException < listoExceptionType.Count; ixException++)
    {
      Type oExceptionType = listoExceptionType[ixException];
      string sExceptionName = MakeXMLCompliant(oExceptionType.FullName);
      try
      {
        if (i_dictExceptionMessage.ContainsKey(sExceptionName))
          continue;
        Exception e = (Exception)(Activator.CreateInstance(oExceptionType));
        i_dictExceptionMessage.Add(sExceptionName, e.Message);
      }
      catch (Exception)
      { i_dictExceptionMessage.Add(sExceptionName, null); }
    }
  }

  //----------------------------------------------------------------------------
  // GetExceptionMessagesWin32
  //----------------------------------------------------------------------------
  private static void GetExceptionMessagesWin32(Dictionary<string, string> i_dictExceptionMessage)
  {
    string sTypeName = MakeXMLCompliant(typeof(Win32Exception).FullName) + "_";
    for (int iError = 0; iError < 0x4000; iError++)  // Win32 errors may range from 0 to 0xFFFF
    {
      Exception e = new Win32Exception(iError);
      if (!e.Message.StartsWith("Unknown error (", StringComparison.OrdinalIgnoreCase))
        i_dictExceptionMessage.Add(sTypeName + iError, e.Message);
    }
  }

  //----------------------------------------------------------------------------
  // CreateMessage
  //----------------------------------------------------------------------------
  private static string CreateMessage(Exception i_oException, CultureInfo i_oCultureInfo)
  {
    CException oEx = new CException(i_oException, i_oCultureInfo);
    Thread oTH = new Thread(new ParameterizedThreadStart(CreateMessageInThread));
    oTH.Start(oEx);
    while (oTH.IsAlive)
    { Thread.Sleep(10); }
    return oEx.m_sMessage;
  }

  //----------------------------------------------------------------------------
  // CreateMessageInThread
  //----------------------------------------------------------------------------
  private static void CreateMessageInThread(Object i_oData)
  {
    if (i_oData == null) return;
    CException oEx = (CException)i_oData;
    if (oEx.m_oException == null) return;

    Thread.CurrentThread.CurrentUICulture = oEx.m_oCultureInfo == null ? CultureInfo.InvariantCulture : oEx.m_oCultureInfo;
    // create new exception in desired culture
    Exception e = null;
    Win32Exception oWin32Exception = (Win32Exception)(oEx.m_oException);
    if (oWin32Exception != null)
      e = new Win32Exception(oWin32Exception.NativeErrorCode);
    else
    {
      try
      {
        e = (Exception)(Activator.CreateInstance(oEx.m_oException.GetType()));
      }
      catch { }
    }
    if (e != null)
      oEx.m_sMessage = e.Message;
  }

  //----------------------------------------------------------------------------
  // MakeXMLCompliant
  // from https://www.w3.org/TR/xml/
  //----------------------------------------------------------------------------
  private static string MakeXMLCompliant(string i_sName)
  {
    if (string.IsNullOrEmpty(i_sName))
      return "_";

    System.Text.StringBuilder oSB = new System.Text.StringBuilder();
    for (int ixChar = 0; ixChar < (i_sName == null ? 0 : i_sName.Length); ixChar++)
    {
      char character = i_sName[ixChar];
      if (IsXmlNodeNameCharacterValid(ixChar, character))
        oSB.Append(character);
    }
    if (oSB.Length <= 0)
      oSB.Append("_");
    return oSB.ToString();
  }

  //----------------------------------------------------------------------------
  private static bool IsXmlNodeNameCharacterValid(int i_ixPos, char i_character)
  {
    if (i_character == ':') return true;
    if (i_character == '_') return true;
    if (i_character >= 'A' && i_character <= 'Z') return true;
    if (i_character >= 'a' && i_character <= 'z') return true;
    if (i_character >= 0x00C0 && i_character <= 0x00D6) return true;
    if (i_character >= 0x00D8 && i_character <= 0x00F6) return true;
    if (i_character >= 0x00F8 && i_character <= 0x02FF) return true;
    if (i_character >= 0x0370 && i_character <= 0x037D) return true;
    if (i_character >= 0x037F && i_character <= 0x1FFF) return true;
    if (i_character >= 0x200C && i_character <= 0x200D) return true;
    if (i_character >= 0x2070 && i_character <= 0x218F) return true;
    if (i_character >= 0x2C00 && i_character <= 0x2FEF) return true;
    if (i_character >= 0x3001 && i_character <= 0xD7FF) return true;
    if (i_character >= 0xF900 && i_character <= 0xFDCF) return true;
    if (i_character >= 0xFDF0 && i_character <= 0xFFFD) return true;
    // if (i_character >= 0x10000 && i_character <= 0xEFFFF) return true;

    if (i_ixPos > 0)
    {
      if (i_character == '-') return true;
      if (i_character == '.') return true;
      if (i_character >= '0' && i_character <= '9') return true;
      if (i_character == 0xB7) return true;
      if (i_character >= 0x0300 && i_character <= 0x036F) return true;
      if (i_character >= 0x203F && i_character <= 0x2040) return true;
    }
    return false;
  }

  private static string msc_sBaseFilename = "exception_messages";
  private static string msc_sXmlGroup_Root = "exception_messages";
  private static string msc_sXmlGroup_Info = "info";
  private static string msc_sXmlGroup_Messages = "messages";
  private static string msc_sXmlData_Culture = "culture";

  private Exception m_oException;
  private CultureInfo m_oCultureInfo;
  private string m_sMessage;

  static Dictionary<CultureInfo, Dictionary<string, string>> ms_dictCultureExceptionMessages = new Dictionary<CultureInfo, Dictionary<string, string>>();
}

internal class Program
{
  public static void Main()
  {
    CException.CreateMessages(null);
    CException.SaveMessagesToXML(@"d:\temp\", "emsg");
    CException.LoadMessagesFromXML(@"d:\temp\", "emsg");
  }
}

Basado en la respuesta Undercover1989, pero tiene en cuenta los parámetros y cuando los mensajes están compuestos de varias cadenas de recursos (como excepciones de argumentos).

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 = <*>quot;{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("\\<*>quot;, "<*>quot;);

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

    return result;
}

Debería registrar la pila de llamadas en lugar de solo un mensaje de error (IIRC, simple excepción. ToString () debería hacerlo por usted). A partir de ahí, puede determinar exactamente de dónde se originó la excepción y, por lo general, deducir de qué excepción se trata.

Anule el mensaje de excepción en el bloque catch utilizando el método de extensión, el mensaje de verificación emitido proviene del código o no como se menciona a continuación.

    public static string GetEnglishMessageAndStackTrace(this Exception ex)
    {
        CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture;
        try
        {

            dynamic exceptionInstanceLocal = System.Activator.CreateInstance(ex.GetType());
            string str;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

            if (ex.Message == exceptionInstanceLocal.Message)
            {
                dynamic exceptionInstanceENG = System.Activator.CreateInstance(ex.GetType());

                str = exceptionInstanceENG.ToString() + ex.StackTrace;

            }
            else
            {
                str = ex.ToString();
            }
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return str;

        }
        catch (Exception)
        {
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return ex.ToString();
        }

Para fines de registro, ciertas aplicaciones pueden necesitar buscar el mensaje de excepción en inglés (además de mostrarlo en la UICultura del cliente habitual).

Para ese fin, el siguiente código

  1. cambia la UICultura actual
  2. recrea el objeto de excepción lanzado usando " GetType () " &erio; " Activator.CreateInstance (t) "
  3. muestra el nuevo mensaje del objeto de excepción en la nueva UICuture
  4. y luego finalmente cambia la UICultura actual a UICultura anterior.

        try
        {
            int[] a = { 3, 6 };
            Console.WriteLine(a[3]); //Throws index out of bounds exception
    
            System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
            throw new System.IO.IOException();
    
        }
        catch (Exception ex)
        {
    
            Console.WriteLine(ex.Message);
            Type t = ex.GetType();
    
            CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
    
            object o = Activator.CreateInstance(t);
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
    
    
            Console.WriteLine(((Exception)o).Message.ToString());
            Console.ReadLine();
    
         }
    
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top