Domanda

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?

È stato utile?

Soluzione

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 del messaggio cambiando brevemente le impostazioni locali del thread in en-US e registrandole (salvando prima le impostazioni locali dell'utente originale e ripristinandole immediatamente dopo).

Farlo su un thread separato è ancora meglio: questo assicura che non ci siano effetti collaterali. Ad 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 Joe sottolinea correttamente in un commento su una precedente revisione di questa risposta, alcuni messaggi sono già ( parzialmente) caricato dalle risorse della lingua nel momento in cui viene generata l'eccezione.

Ciò si applica alla parte 'parametro non può essere nullo' del messaggio generato quando viene generata un'eccezione ArgumentNullException (" foo "), ad esempio. In questi casi, il messaggio apparirà comunque (parzialmente) localizzato, anche quando si utilizza il codice sopra.

A parte l'utilizzo di hack non 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: l'eccezione di .NET Framework il codice non ha possibilità di sovrascrivere le impostazioni internazionali del messaggio di errore.

Altri suggerimenti

Puoi cercare il messaggio di eccezione originale su unlocalize.com

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

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

Ha il vantaggio di non sembrare distorto, specialmente per i locali di lingua inglese non americani. (a.k.a. evita commenti sgradevoli da parte dei colleghi)

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 sono installati file di cultura francese, per impostazione predefinita è la lingua predefinita di Windows (installata?).

Ecco una soluzione che non richiede alcuna codifica e funziona anche per i testi delle eccezioni che sono caricati troppo presto per consentirci di cambiare 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.config in dev, (o un [myapp] .exe.config o web.config in 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>

Ciò che fa è dire al framework di reindirizzare i binding di assembly per le risorse di mscorlib e System.Xml , per le versioni tra 1 e 999, in francese (la cultura è impostata su " fr ") su un assembly che ... non esiste (una versione arbitraria 999).

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

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

So che questo è un vecchio argomento, ma penso che la mia soluzione possa essere abbastanza pertinente 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 es. "System.FileNotFoundException"), sebbene al momento non ho accesso a un sistema di lingua straniera per testare l'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 qualunque lingua tu preferisca, ma per l'inglese penso che il nome della classe sia perfettamente adeguato.

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

Tks :)

Il framework .NET è diviso in due parti:

  1. Lo stesso framework .NET
  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).

L'impostazione di Thread.CurrentThread.CurrentUICulture verrà 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. Sta cercando nelle risorse .NET Libraries il testo originale per ottenere la chiave di risorsa e quindi restituisce 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 te ne sarei grato.

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
}

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) Includere un codice di errore ad es. 0X00000001 con ogni errore in modo da poterlo facilmente consultare in una tabella inglese.

Ho avuto la stessa situazione e tutte le risposte che ho trovato qui e altrove non mi hanno aiutato o non sono state soddisfacenti:
Forza la lingua delle eccezioni in inglese
C # - Ricezione di messaggi di eccezione in Inglese quando l'applicazione è in un'altra lingua?
Come modificare la lingua dei messaggi delle eccezioni di Visual Studio in inglese durante il debug
Come gestire la traduzione del messaggio di eccezione?
Come evitare completamente i messaggi di eccezione .NET localizzati

Thread.CurrentUICulture cambia la lingua delle eccezioni .net, ma non per Win32Exception , che utilizza le risorse di Windows nella lingua dell'interfaccia utente di Windows stessa. Quindi non sono mai riuscito a stampare i messaggi di Win32Exception in 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
SaveMessagesToXML () li salva in tanti 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");
  }
}

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 = <*>quot;{Regex.Escape(message)}";
            pattern = Regex.Replace(pattern, @"\\{([0-9]+)\}", "(?<group$1>.*)");

            var regex = new Regex(pattern);

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

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

    return result;
}

Dovresti registrare lo stack di chiamate anziché solo un 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 è.

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

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 usando " GetType () " & Amp; & Quot; Activator.CreateInstance (t) "
  3. visualizza il messaggio del nuovo oggetto eccezione nella nuova UICuture
  4. e infine ripristina 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();
    
         }
    
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top