practices personalized handling exceptions example custom best c# .net exception localization

c# - personalized - ¿Mensajes de excepción en inglés?



throw custom exception c# (15)

Estamos registrando cualquier excepción que ocurra en nuestro sistema escribiendo el mensaje 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?


Basado en la respuesta de 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; }


Debe registrar la pila de llamadas en lugar de solo un mensaje de error (IIRC, simple excepción.ToString () debe hacerlo por usted). Desde allí, puede determinar exactamente de dónde se originó la excepción y, por lo general, deducir qué excepción es.


El framework .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 MessageBox, 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, pedirle al cliente que lo haga). En ese caso, los textos de excepción estarán en inglés. Sin embargo, tenga en cuenta que todos los demás textos proporcionados por el marco también serán en inglés (por ejemplo, las etiquetas de los botones en un cuadro de mensaje, los métodos abreviados de teclado para ApplicationCommands).


Esta es una solución que no requiere codificación y funciona incluso con textos de excepciones que se cargan demasiado pronto para que podamos cambiarlos por código (por ejemplo, los de 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 a un lado del archivo principal .exe) 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 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 los recursos de mscorlib y los recursos de System.Xml , para versiones entre 1 y 999, en francés (cultura está establecida en " fr ") a un ensamblaje que ... No existe (una versión arbitraria 999).

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

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


Este problema se puede solucionar parcialmente. El código de excepción de Framework carga los mensajes de error de sus recursos, según la configuración regional del 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 los EE. UU. Cambiando brevemente la configuración regional de subprocesos a en-EE.

Hacer esto en un hilo separado es aún mejor: esto asegura que no habrá ningún efecto secundario. 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 ve algo como:

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 cargados (parcialmente) de los recursos de idioma en el momento en que se lanza la excepción.

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

Aparte de usar hacks imprácticos, como ejecutar todo su código no de UI en un hilo con la configuración regional en-US, no parece que haya 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.


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

Thread.CurrentUICulture cambia el idioma de las excepciones .net, pero no lo hace para Win32Exception , que utiliza los recursos de Windows en el idioma de la propia interfaz de usuario de Windows. Así que nunca logré imprimir los mensajes de Win32Exception en inglés en lugar de en alemán, ni siquiera utilizando 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 el idioma deseado, pero sí recibirá un mensaje en ese idioma, que es mucho más de lo que recibe actualmente (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 cada cultura.
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 múltiples paquetes de idioma 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"); } }


La configuración de Thread.CurrentThread.CurrentUICulture se utilizará para localizar las excepciones. Si necesita dos tipos de excepciones (una para el usuario, una para usted), puede usar la siguiente función para traducir el mensaje de excepción. Está buscando en los recursos de .NET-Libraries el texto original para obtener la clave de recursos y luego devuelve el valor traducido. Pero hay una debilidad por la que aún no encontré una buena solución: no se encontrarán los mensajes que contengan {0} en los recursos. 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 las puede leer usted, es decir, no son una característica del cliente, por lo que puede usar cadenas no localizadas alámbricas que no cambiarán cuando ejecute en modo turco.

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


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

Para tal efecto, el siguiente código

  1. Cambia la cultura actual.
  2. recrea el objeto Exception lanzado con "GetType ()" & "Activator.CreateInstance (t)"
  3. muestra el nuevo mensaje del objeto de excepción en el nuevo UICuture
  4. y luego finalmente cambia la UICulture actual de nuevo a UICulture 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(); }



Quizás sea un punto polémico, pero en lugar de establecer la cultura en en-US , puede establecerla en Invariant . 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 sesgados, especialmente para los locales que no hablan inglés en Estados Unidos. (también conocido como evita comentarios sarcásticos de colegas)


Reemplace el mensaje de excepción en el bloque catch utilizando el método de extensión. El mensaje de verificación del lanzamiento es 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(); }


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

En el registrador de excepciones, podría registrar ex.GetType.ToString, lo que guardaría el nombre de la clase de excepción. Espero 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 la actualidad no tengo acceso a un sistema de idioma extranjero para probar el idea.

Si realmente desea también el texto del mensaje de error, puede crear un diccionario con 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.


Windows necesita tener instalado el idioma de interfaz de usuario que desea usar. No lo hace, no tiene forma de saber mágicamente qué 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 ningún archivo de cultura francés instalado, el valor predeterminado es el idioma predeterminado de Windows (¿instalado?).


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 soluciones de trabajo.

Tks :)