¿Mensajes de excepción en inglés?

298

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?

Carra
fuente
8
¿Por qué no puedes nadar así: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // lanzar una nueva excepción aquí => La cultura está en inglés Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra
93
No conozco ningún desarrollador, que es feliz para mensajes de excepción no estén en inglés: S ..
Zéiksz
3
@ Zéiksz Mire más allá de los países de habla inglesa y encontrará muchos de ellos: D. El problema no es texto en inglés, el problema es un idioma que no puedes entender. Los mensajes en su idioma nativo (suponiendo una traducción adecuada) están perfectamente bien.
Alejandro
31
@Alejandro Tener que traducir un mensaje de excepción de un idioma nativo al inglés para googlear es un dolor aún mayor en el culo. En mi humilde opinión.
Antoine Meltzheim
18
Qué idiota de Microsoft tuvo la idea de traducir mensajes de error que son solo para desarrolladores. Incluso los términos que se usan en el lenguaje de programación como una clave en un diccionario se traducen. (La clave no se encuentra en el Diccionario se convierte en Sleutel en niet gevonden en de bibliotheek en holandés). No quiero cambiar el idioma del sistema operativo para esto ...
Roel

Respuestas:

66

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 del usuario original 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) cargados 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 produce 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 usar hacks poco prácticos, como ejecutar todo su código que no sea de UI en un hilo con configuración regional en EE. UU., No parece haber mucho que pueda hacer al respecto: el código de excepción de .NET Framework no tiene facilidades para anular la configuración regional del mensaje de error.

mdb
fuente
10
Su ejemplo funciona para una FileNotFoundException, porque el recurso del mensaje se recupera cuando se accede a la propiedad Mensaje, no cuando se lanza la excepción. Pero esto no es cierto para todas las excepciones (por ejemplo, intente lanzar una nueva ArgumentNullException ("paramName"))
Joe
3
Estoy confundido. Intenté seguir tu respuesta y para probarla, quería mi excepción en francés, así que lo hice t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");y t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");, sin embargo, la excepción resultante fue en inglés ...
VitalyB
77
@VitalyB Los textos de excepción localizados son parte de los paquetes de idiomas de .NET Framework. Entonces, si no tiene instalado el paquete de idioma francés, no recibirá los textos traducidos.
Daniel Rose
77
Al menos con .NET 4.5 se instancian todas las excepciones Environment.GetResourceString("...")para que su solución ya no funcione. Lo mejor es lanzar una excepción personalizada con su propio texto de mensaje (en inglés) y usar la propiedad InnerException para mantener la anterior.
webber2k6
1
La reflexión para obtener los nombres de los tipos de excepción podría ser útil.
Guillermo Prandi
67

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

usuario461128
fuente
55
Intenté buscar algunos mensajes de excepción chinos, siempre me lo dijeron No records found.
Tyler Long
1
Mala elección. Cuando envíe mis excepciones a Google Analytics (u otro servicio en la nube), tendré diferentes grupos de excepciones para la misma excepción, pero en diferentes idiomas. Y no podré ordenar por conteo de cada excepción, porque no refleja el conteo real (100 en inglés, 77 en chino, 80 en coreano ... etc.)
Artemious
Recuerdo encontrar este hermoso sitio web muchas veces cuando simplemente descargué mensajes de excepción localizados en Google, ahora ya no está disponible.
Martin Braun
40

Quizás sea un punto polémico, pero en lugar de establecer la cultura en-US, puede configurarlo Invariant. En la Invariantcultura, 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 entornos de habla inglesa no estadounidenses. (también conocido como evita comentarios sarcásticos de colegas)

MPelletier
fuente
1
¿Dónde deberíamos escribir estas líneas en nuestro proyecto ASP.NET? Gracias.
Jason
2
Voy a sugerir en la parte superior, en Application_Start. Eso hará que todo el proyecto se ejecute en inglés. Si es solo para mensajes de error que desea, puede hacer que una función de cobertura y llamar a cada uno catch.
MPelletier
55
Sin embargo, ¿esto no hará que los botones estándar de los cuadros de mensaje estén en inglés? Ese puede no ser el comportamiento deseado.
Nyerguds
12

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

Es posible 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, solo cree un app.configin dev (o a [myapp].exe.configo web.configen producción) que contenga 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 mscorliblos recursos y System.Xmllos recursos de, para las versiones entre 1 y 999, en francés (la cultura se establece en " fr") a un ensamblaje que ... no existe (un arbitrario versión 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.

Simon Mourier
fuente
1
Funciona cuando se necesita salida en inglés de herramientas de prueba de ejecución.
smg
Intenté esto, pero no funcionó para mí. ¿Hay otros archivos de recursos en .net? ¿Donde puedo encontrarlos?
BluE
1
Busque en c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Cada idioma tiene una carpeta de 2 letras allí. Recuerde reemplazar "fr" en la respuesta anterior con el idioma real que se está utilizando. "no" para noruego, "da" para danés, "sv" para sueco, etc.
Wolf5
Para crear una lista COMPLETA, eche un vistazo en esa carpeta. Son unos 120 archivos de recursos. Agregue cada uno de ellos a la configuración. Esta parece ser la única solución para Windows 10 y más reciente por ahora, ya que no hay forma de desinstalar los paquetes de idioma .Net en ventanas más nuevas (es parte del sistema operativo). Incluso ahora se coloca en el GAC, por lo que eliminar esas carpetas de idiomas no parece funcionar.
Wolf5
10

Windows necesita tener instalado el idioma de la interfaz de usuario que desea utilizar. Si no lo hace, 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 idioma predeterminado de Windows es (¿instalado?).

danobrega
fuente
Eso resolvió el problema. IU polaco en mi situación, instalado en paquetes de idioma MUI ~ 260MB, usando el programa Vistalizator.
Krzysztof Szynter
5

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 en este momento no tengo acceso a un sistema de idioma extranjero para probar 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.

Bárbaro
fuente
55
No funciona Tengo un InvalidOperationException, arrojado por System.Xml.XmlWellFormedWriter. Intenta adivinar qué error específico ocurrió sin leer el mensaje. Podrían ser mil cosas diferentes.
Nyerguds
4
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 :)


fuente
te olvidaste de
KansaiRobot
4

La configuración Thread.CurrentThread.CurrentUICulturese 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 devolver el valor traducido. Pero hay una debilidad que aún 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 ex, CultureInfo targetCulture)
{
    try
    {
        Assembly assembly = ex.GetType().Assembly;
        ResourceManager resourceManager = new ResourceManager(assembly.GetName().Name, assembly);
        ResourceSet originalResources = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, createIfNotExists: true, tryParents: true);
        ResourceSet targetResources = resourceManager.GetResourceSet(targetCulture, createIfNotExists: true, tryParents: true);
        foreach (DictionaryEntry originalResource in originalResources)
            if (originalResource.Value.ToString().Equals(ex.Message.ToString(), StringComparison.Ordinal))
                return targetResources.GetString(originalResource.Key.ToString(), ignoreCase: false); // success

    }
    catch { }
    return ex.Message; // failed (error or cause it's not smart enough to find texts with '{0}'-patterns)
}
Vortex852456
fuente
Eso no va a funcionar si la excepción contiene un parámetro formateado.
Nick Berardi
Sí, como dije: "Pero hay una debilidad que aún no encontré una buena solución: no se encontrarán mensajes que contengan {0} en recursos. Si alguien tiene una buena solución, estaría agradecido".
Vortex852456
3

El marco .NET viene en dos partes:

  1. El propio framework .NET
  2. Los paquetes de idioma de .NET Framework

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 idiomas (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).

Daniel Rose
fuente
¡¡Gracias!! Me parece irónico que el cuadro de diálogo de desinstalación esté en el idioma del paquete de desinstalación y no en el idioma local. Nota al margen: los paquetes de idiomas parecen volver cada pocos meses. No he entendido por qué, pero estoy adivinando una actualización / actualización
Choco Smith
@ChocoSmith Con cada actualización de .NET Framework a través de Windows Update, el paquete de idioma se instala nuevamente.
Daniel Rose
55
Pedir a los clientes que desinstalen paquetes de idioma para su propio idioma no es una solución viable.
Nyerguds
2

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 ejecute en modo turco.

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

morechilli
fuente
99
Eso no ayudará mucho cuando son excepciones lanzadas por componentes internos del marco .net . Todo este problema no se aplica a las excepciones que arrojes tú mismo; obviamente, el programador elige qué mensaje incluir con ellos .
Nyerguds
1

Basado en la respuesta Undercover1989, pero tiene en cuenta los parámetros y cuando los mensajes se componen 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 = $"{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;
}
ene
fuente
1

He tenido la misma situación, y todas las respuestas que encontré aquí y en otros lugares no ayudaron o no fueron satisfactorias:

El Thread.CurrentUICulturecambia el idioma de las excepciones de .NET, pero no para Win32Exception, que utiliza los recursos de Windows en el idioma de la interfaz de usuario de Windows en sí. Así que nunca logré imprimir los mensajes Win32Exceptionen inglés en lugar de en 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, los
SaveMessagesToXML()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.
Quizás 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 bienvenidas!

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");
  }
}
Tobias Knauss
fuente
1
El Thread.CurrentUICulture también cambia el idioma de la interfaz de usuario, por lo que es una terrible opción. Un ejemplo clásico son los botones Sí / No / Aceptar / Cancelar en el cuadro de mensaje.
Nyerguds
0

Mensajes de excepción en inglés

try
{
    ......
}
catch (Exception ex)
{
      throw new UserFriendlyException(L("ExceptionmessagesinEnglish"));
}

luego vaya a la carpeta de localización y colóquelo en projectName.xml y agregue

<text name="ExceptionmessagesinEnglish">Exception Message in English</text>
Nabeel Haxxan
fuente
-1

Debe registrar la pila de llamadas en lugar de solo un mensaje de error (IIRC, excepción simple. 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 qué excepción es.

Branko Dimitrijevic
fuente
3
Estamos registrando el mensaje y stacktrace. Pero es mucho más fácil si el mensaje es claro.
Carra
-1

Anule el mensaje de excepción en el bloque catch mediante 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();
        }
usuario3472484
fuente
1
Como he dicho antes ... InvalidOperationException. Diviértete averiguando qué significa eso sin el mensaje en sí. Una nueva instancia no lo tendrá mágicamente.
Nyerguds
-1

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 ello, el siguiente código

  1. cambia la UICultura actual
  2. recrea el objeto de excepción lanzado usando "GetType ()" y "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();
    
         }
Ron16
fuente
1
Esto no garantiza que el mensaje de excepción del nuevo objeto sea el mismo que la excepción lanzada. Puede ser totalmente diferente, y generalmente es totalmente diferente. Por eso necesitamos el mensaje de excepción.
Artemious