Messaggi di eccezione in inglese?


298

Stiamo registrando eventuali eccezioni che si verificano nel nostro sistema scrivendo Exception.Message in un file. Tuttavia, sono scritti nella cultura del cliente. E gli errori turchi non significano molto per me.

Quindi, come possiamo registrare eventuali messaggi di errore in inglese senza cambiare la cultura degli utenti?


8
Perché non puoi swith in questo modo: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // lancia qui una nuova eccezione => La cultura è in inglese Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra,

93
Non conosco nessuno sviluppatore, è contento per i messaggi di eccezione non inglesi: S ..
Zéiksz,

3
@ Zéiksz Guarda oltre i paesi di lingua inglese e ne troverai molti: D. Il problema non è un testo non inglese, il problema è una lingua che non puoi capire. I messaggi nella tua lingua madre (presupponendo una traduzione adeguata) vanno benissimo.
Alejandro,

31
@Alejandro Dover tradurre un messaggio di eccezione da una lingua madre in inglese per google è un dolore ancora più grande nel culo. A parer mio.
Antoine Meltzheim,

18
Quale idiota di Microsoft ha avuto l'idea di tradurre messaggi di errore che sono solo per gli sviluppatori. Anche i termini utilizzati nel linguaggio di programmazione come una chiave in un dizionario vengono tradotti. (La chiave non si trova nel dizionario diventa Sleutel in niet gevonden in de bibliotheek in olandese). Non voglio cambiare la lingua del sistema operativo per questo ...
Roel,

Risposte:


66

Questo problema può essere parzialmente risolto. Il codice di eccezione Framework carica i messaggi di errore dalle sue risorse, in base alle impostazioni internazionali correnti del thread. Nel caso di alcune eccezioni, ciò accade al momento dell'accesso alla proprietà Message.

Per tali eccezioni, è possibile ottenere la versione inglese completa degli Stati Uniti del messaggio cambiando brevemente le impostazioni internazionali del thread in en-US e registrandole (salvando in precedenza le impostazioni locali dell'utente originale e ripristinandole immediatamente dopo).

Fare questo su un thread separato è ancora meglio: questo assicura che non ci siano effetti collaterali. Per esempio:

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();
}

Dove la classe ExceptionLogger è simile a:

class ExceptionLogger
{
  Exception _ex;

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

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

Tuttavia, come sottolinea correttamente Joe in un commento su una precedente revisione di questa risposta, alcuni messaggi sono già (parzialmente) caricati dalle risorse della lingua nel momento in cui viene generata l'eccezione.

Questo vale per la parte "parametro non può essere nulla" del messaggio generato quando viene generata un'eccezione ArgumentNullException ("pippo"), ad esempio. In questi casi, il messaggio apparirà comunque (parzialmente) localizzato, anche quando si utilizza il codice sopra.

A parte l'utilizzo di hack poco pratici, come ad esempio l'esecuzione di tutto il codice non UI su un thread con impostazioni internazionali en-US, non sembra esserci molto da fare al riguardo: il codice di eccezione di .NET Framework non ha strutture per sovrascrivere la locale del messaggio di errore.


10
L'esempio funziona per FileNotFoundException, poiché la risorsa messaggio viene recuperata quando si accede alla proprietà Message, non quando viene generata l'eccezione. Ma questo non è vero per tutte le eccezioni (ad esempio, prova a lanciare il nuovo ArgumentNullException ("paramName"))
Joe,

3
Sono confuso. Ho provato a seguire la tua risposta e per testarla volevo la mia eccezione in francese, così l'ho fatto t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");e t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");tuttavia, l'eccezione risultante era in inglese ...
VitalyB

7
@VitalyB I testi delle eccezioni localizzati fanno parte dei language pack di .NET framework. Quindi, se non hai installato il pacchetto in lingua francese, non otterrai i testi tradotti.
Daniel Rose,

7
Almeno con .NET 4.5 vengono istanziate tutte le eccezioni, Environment.GetResourceString("...")quindi la soluzione non funziona più. La cosa migliore è lanciare un'eccezione personalizzata con il tuo messaggio di testo (inglese) e usare la proprietà InnerException per mantenere quella precedente.
webber2k6,

1
Riflessione per ottenere i nomi dei tipi di eccezione potrebbe essere utile.
Guillermo Prandi,

67

Puoi cercare il messaggio di eccezione originale su unlocalize.com


5
Ho provato a cercare alcuni messaggi di eccezione cinesi, mi ha sempre detto No records found.
Tyler Long,

1
Scelta sbagliata. Quando invio le mie eccezioni a Google Analytics (o altro servizio cloud), avrò diversi gruppi di eccezioni per la stessa eccezione, ma lingue diverse. E non sarò in grado di ordinare in base al conteggio di ogni eccezione, perché non riflette il conteggio reale (100 in inglese, 77 in cinese, 80 in coreano ... ecc.)
Artemious

Ricordo di aver trovato questo bellissimo sito molte volte quando ho semplicemente scaricato su Google i messaggi di eccezione localizzati, ora non è più disponibile.
Martin Braun,

40

Forse un punto controverso, ma invece di impostare la cultura su en-US, è possibile impostarla su Invariant. Nella Invariantcultura, i messaggi di errore sono in inglese.

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

Ha il vantaggio di non sembrare di parte, soprattutto per i locali di lingua inglese non americani. (aka evita le osservazioni ridicole dei colleghi)


1
Dove dovremmo scrivere queste righe nel nostro progetto ASP.NET? Grazie.
Jason,

2
Sto per suggerire in alto, in Application_Start. Ciò farà funzionare l'intero progetto in inglese. Se lo desideri solo per i messaggi di errore, puoi creare una funzione di copertina e chiamarla in ciascuno di essi catch.
MPelletier,

5
Questo non farà anche in modo che i pulsanti standard della finestra di messaggio siano in inglese? Potrebbe non essere il comportamento desiderato.
Nyerguds,

12

Ecco una soluzione che non richiede alcuna codifica e funziona anche per i testi delle eccezioni che sono caricati troppo presto per poter essere modificati in base al codice (ad esempio quelli in mscorlib).

Potrebbe non essere sempre applicabile in ogni caso (dipende dalla configurazione in quanto è necessario essere in grado di creare un file .config a parte il file .exe principale), ma per me funziona. Quindi, basta creare un app.configin dev, (o un [myapp].exe.configo web.configin produzione) che contiene ad esempio le seguenti righe:

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

Quello che fa è dire al framework di reindirizzare i binding di assembly per mscorlible risorse e System.Xmlle risorse, per le versioni tra 1 e 999, in francese (la cultura è impostata su " fr") a un assembly che ... non esiste (un arbitrario versione 999).

Quindi, quando il CLR cercherà le risorse francesi per questi due assiemi (mscorlib e System.xml), non li troverà e tornerà all'inglese con garbo. A seconda del contesto e dei test, è possibile aggiungere altri assembly a questi reindirizzamenti (assembly che contengono risorse localizzate).

Ovviamente non penso che questo sia supportato da Microsoft, quindi utilizzalo a tuo rischio. Bene, nel caso in cui rilevi un problema, puoi semplicemente rimuovere questa configurazione e verificare che non sia correlata.


1
Funziona quando è necessario l'output in inglese dagli strumenti del test-runner.
smg

Ho provato questo, ma non ha funzionato per me. Ci sono altri file di risorse in .net? Dove posso trovarli?
BluE,

1
Cerca in c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Ogni lingua ha una cartella di 2 lettere lì. Ricorda di sostituire "fr" nella risposta sopra con la lingua in uso. "no" per norvegese, "da" per danese, "sv" per svedese ecc.
Wolf5,

Per creare un elenco COMPLETO, dai un'occhiata a quella cartella. Sono circa 120 file di risorse. Aggiungi ciascuno di essi nella configurazione. Questa sembra essere l'unica soluzione per Windows 10 e versioni successive per ora, poiché non è più possibile disinstallare i language pack .Net nelle finestre più recenti (parte del sistema operativo). Ora è persino inserito nel GAC, quindi la rimozione di quelle cartelle di lingue non sembra funzionare.
Wolf5,

10

Windows deve avere la lingua dell'interfaccia utente che si desidera utilizzare installata. In caso contrario, non ha modo di sapere magicamente qual è il messaggio tradotto.

In un Windows 7 ultimate en-US, con pt-PT installato, il seguente codice:

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 messaggi in pt-PT, en-US e en-US. Poiché non è installato alcun file di cultura francese, per impostazione predefinita è la lingua predefinita di Windows (installata?).


Questo è risolto il problema. Interfaccia utente polacca nella mia situazione, installato in pacchetti linguistici MUI ~ 260 MB, usando il programma Vistalizator.
Krzysztof Szynter

5

So che questo è un vecchio argomento, ma penso che la mia soluzione possa essere abbastanza rilevante per chiunque si imbatta in una ricerca web:

Nel logger delle eccezioni è possibile accedere a ex.GetType.ToString, che salverebbe il nome della classe di eccezione. Mi aspetto che il nome di una classe dovrebbe essere indipendente dalla lingua e quindi essere sempre rappresentato in inglese (ad esempio "System.FileNotFoundException"), sebbene al momento non ho accesso a un sistema di lingue straniere per testare il idea.

Se vuoi davvero anche il testo del messaggio di errore potresti creare un dizionario di tutti i possibili nomi di classe di eccezione e i loro messaggi equivalenti in qualsiasi lingua tu preferisca, ma per l'inglese penso che il nome della classe sia perfettamente adeguato.


5
Non funziona Ho ricevuto una InvalidOperationException, lanciata da System.Xml.XmlWellFormedWriter. Si tenta di indovinare quale errore specifico si è verificato senza leggere il messaggio. Potrebbero essere mille cose diverse.
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;

Senza Workaround.

Tks :)


hai dimenticato il;
KansaiRobot

4

L'impostazione Thread.CurrentThread.CurrentUICultureverrà utilizzata per localizzare le eccezioni. Se hai bisogno di due tipi di eccezioni (una per l'utente, una per te) puoi usare la seguente funzione per tradurre il messaggio di eccezione. Cerca nelle risorse .NET-Libraries il testo originale per ottenere la chiave di risorsa e quindi restituire il valore tradotto. Ma c'è un punto debole che non ho ancora trovato una buona soluzione: i messaggi che contengono {0} nelle risorse non saranno trovati. Se qualcuno ha una buona soluzione, sarei grato.

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

Ciò non funzionerà se l'eccezione contiene un parametro formattato.
Nick Berardi,

Sì, come ho detto: "Ma c'è un punto debole che non ho ancora trovato una buona soluzione: i messaggi che contengono {0} nelle risorse non saranno trovati. Se qualcuno ha una buona soluzione sarei grato."
Vortex852456,

3

Il framework .NET è diviso in due parti:

  1. Il framework .NET stesso
  2. I language pack di .NET framework

Tutti i testi (es. Messaggi di eccezione, etichette di pulsanti su un MessageBox, ecc.) Sono in inglese nel framework .NET stesso. I language pack hanno i testi localizzati.

A seconda della situazione esatta, una soluzione sarebbe quella di disinstallare i language pack (ovvero dire al client di farlo). In tal caso, i testi delle eccezioni saranno in inglese. Si noti tuttavia che tutto il resto del testo fornito dal framework sarà anche in inglese (es. Le etichette dei pulsanti su un MessageBox, le scorciatoie da tastiera per ApplicationCommands).


Grazie!! Trovo ironico che la finestra di dialogo di disinstallazione sia nella lingua del pacchetto di disinstallazione e non nella lingua locale. Nota a margine: i language pack sembrano tornare ogni pochi mesi. non ho capito perché, ma sto indovinando un aggiornamento / aggiornamento
Choco Smith

@ChocoSmith Con ogni aggiornamento di .NET Framework tramite Windows Update, il language pack viene nuovamente installato.
Daniel Rose,

5
Chiedere ai clienti di disinstallare i language pack per la propria lingua non è una soluzione praticabile.
Nyerguds,

2

Immagino uno di questi approcci:

  1. Le eccezioni vengono lette sempre e solo da te, ovvero non sono una funzionalità client, quindi puoi utilizzare stringhe cablate non localizzate che non cambieranno quando esegui in modalità turca.

  2. Includi un codice di errore, ad esempio 0x00000001con ogni errore, in modo da poterlo facilmente consultare in una tabella inglese.


9
Ciò non sarà di grande aiuto quando si tratta di eccezioni generate da componenti interni del framework .net . L'intero problema non si applica alle eccezioni che ti butti; ovviamente il programmatore sceglie quale messaggio includere con quelli .
Nyerguds,

1

Basato sulla risposta Undercover1989, ma tiene conto dei parametri e quando i messaggi sono composti da più stringhe di risorse (come le eccezioni dell'argomento).

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

1

Ho avuto la stessa situazione e tutte le risposte che ho trovato qui e altrove non mi hanno aiutato o non sono state soddisfacenti:

Il Thread.CurrentUICulturecambia il linguaggio delle eccezioni .net, ma non per i Win32Exception, che utilizza risorse di Windows nella lingua della UI di Windows stesso. Quindi non sono mai riuscito a stampare i messaggi Win32Exceptionin inglese anziché in tedesco, nemmeno usando FormatMessage()come descritto in
Come ottenere Win32Exception in inglese?

Pertanto ho creato la mia soluzione, che memorizza la maggior parte dei messaggi di eccezione esistenti per diverse lingue in file esterni. Non otterrai il messaggio esatto nella lingua desiderata, ma riceverai un messaggio in quella lingua, che è molto più di quello che ricevi attualmente (che è un messaggio in una lingua che probabilmente non capisci).

Le funzioni statiche di questa classe possono essere eseguite su installazioni Windows con lingue diverse: CreateMessages()crea i testi specifici della cultura e
SaveMessagesToXML()li salva in tutti i file XML quante sono le lingue create o caricate
LoadMessagesFromXML()carica tutti i file XML con messaggi specifici della lingua

Quando crei i file XML su diverse installazioni di Windows con lingue diverse, avrai presto tutte le lingue di cui hai bisogno.
Forse puoi creare testi per lingue diverse su 1 Windows quando hai installato più language pack MUI, ma non l'ho ancora testato.

Testato con VS2008, pronto per l'uso. Commenti e suggerimenti sono benvenuti!

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");
  }
}

1
Il Thread.CurrentUICulture anche cambia la lingua dell'interfaccia utente, che lo rende una terribile scelta. Un classico esempio sono i pulsanti Sì / No / OK / Annulla nella finestra di messaggio.
Nyerguds,

0

Messaggi di eccezione in inglese

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

quindi vai alla cartella Localization e inseriscilo in projectName.xml e aggiungi

<text name="ExceptionmessagesinEnglish">Exception Message in English</text>

-1

Dovresti registrare lo stack di chiamate invece del semplice messaggio di errore (IIRC, semplice eccezione. ToString () dovrebbe farlo per te). Da lì, puoi determinare esattamente da dove proviene l'eccezione e di solito dedurre quale eccezione è.


3
Stiamo registrando il messaggio e stacktrace. Ma è molto più semplice se il messaggio è chiaro.
Carra,

-1

Sostituisci il messaggio di eccezione nel blocco catch utilizzando il metodo di estensione, Controlla che il messaggio generato provenga dal codice o meno come indicato di seguito.

    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();
        }

1
Come ho detto prima ... InvalidOperationException. Divertiti a capire cosa significhi senza il messaggio stesso. Una nuova istanza non la avrà magicamente.
Nyerguds,

-1

Ai fini della registrazione, alcune applicazioni potrebbero dover recuperare il messaggio di eccezione inglese (oltre a visualizzarlo nella normale UICulture del client).

A tale scopo, il seguente codice

  1. cambia l'attuale UICulture
  2. ricrea l'oggetto Eccezione generato utilizzando "GetType ()" e "Activator.CreateInstance (t)"
  3. visualizza il messaggio del nuovo oggetto eccezione nella nuova UICuture
  4. e poi finalmente cambia l'attuale UICulture a UICulture precedente.

        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();
    
         }

1
ciò non garantisce che il messaggio di eccezione del nuovo oggetto sia lo stesso dell'eccezione generata. Può essere totalmente diverso e di solito è totalmente diverso. Ecco perché abbiamo bisogno del messaggio di eccezione.
Artemious
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.