Messages d'exception en anglais?

298

Nous enregistrons toutes les exceptions qui se produisent dans notre système en écrivant Exception.Message dans un fichier. Cependant, ils sont écrits dans la culture du client. Et les erreurs turques ne signifient pas grand-chose pour moi.

Alors, comment pouvons-nous enregistrer des messages d'erreur en anglais sans changer la culture des utilisateurs?

Carra
la source
8
Pourquoi ne pouvez-vous pas swith comme ceci: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // lance une nouvelle exception ici => La culture est en anglais Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra
93
Je ne connais aucun développeur, qui soit satisfait des messages d'exception non anglais: S ..
Zéiksz
3
@ Zéiksz Regardez au-delà des pays anglophones et vous en trouverez beaucoup: D. Le problème n'est pas du texte non anglais, le problème est une langue que vous ne pouvez pas comprendre. Les messages dans votre langue maternelle (en supposant une traduction appropriée) sont parfaitement corrects.
Alejandro
31
@Alejandro Devoir traduire un message d'exception d'une langue maternelle vers l'anglais pour google c'est encore plus pénible. A mon humble avis.
Antoine Meltzheim
18
Quel idiot chez Microsoft a eu l'idée de traduire des messages d'erreur qui ne sont destinés qu'aux développeurs. Même les termes utilisés dans le langage de programmation comme une clé dans un dictionnaire sont traduits. (La clé ne se trouve pas dans le dictionnaire devient Sleutel in niet gevonden in de bibliotheek en néerlandais). Je ne veux pas changer la langue du système d'exploitation pour cela ...
Roel

Réponses:

66

Ce problème peut être partiellement résolu. Le code d'exception Framework charge les messages d'erreur à partir de ses ressources, en fonction des paramètres régionaux du thread actuel. Dans le cas de certaines exceptions, cela se produit au moment de l'accès à la propriété Message.

Pour ces exceptions, vous pouvez obtenir la version complète en anglais américain du message en basculant brièvement les paramètres régionaux du thread sur en-US pendant la journalisation (en enregistrant les paramètres régionaux de l'utilisateur d'origine au préalable et en les restaurant immédiatement après).

Faire cela sur un thread séparé est encore mieux: cela garantit qu'il n'y aura pas d'effets secondaires. Par exemple:

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

Où la classe ExceptionLogger ressemble à quelque chose:

class ExceptionLogger
{
  Exception _ex;

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

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

Cependant, comme Joe le souligne correctement dans un commentaire sur une révision antérieure de cette réponse, certains messages sont déjà (partiellement) chargés à partir des ressources linguistiques au moment où l'exception est levée.

Cela s'applique à la partie 'le paramètre ne peut pas être nul' du message généré lorsqu'une exception ArgumentNullException ("foo") est levée, par exemple. Dans ces cas, le message apparaîtra (partiellement) localisé, même lorsque vous utilisez le code ci-dessus.

En dehors de l'utilisation de hacks impraticables, tels que l'exécution de tout votre code non UI sur un thread avec des paramètres régionaux en-US pour commencer, il ne semble pas que vous puissiez faire grand-chose à ce sujet: le code d'exception .NET Framework n'a pas fonctionnalités pour remplacer les paramètres régionaux du message d'erreur.

mdb
la source
10
Votre exemple fonctionne pour une FileNotFoundException, car la ressource de message est récupérée lors de l'accès à la propriété Message, et non lorsque l'exception est levée. Mais cela n'est pas vrai pour toutes les exceptions (par exemple, essayez de lancer une nouvelle ArgumentNullException ("paramName"))
Joe
3
Je suis confus. J'ai essayé de suivre votre réponse et de la tester, je voulais mon exception en français, donc je l'ai fait t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");et t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");pourtant, l'exception résultante était en anglais ...
VitalyB
7
@VitalyB Les textes d'exception localisés font partie des modules linguistiques du framework .NET. Donc, si vous n'avez pas installé le pack de langue française, vous n'obtiendrez pas les textes traduits.
Daniel Rose
7
Au moins avec .NET 4.5, toutes les exceptions sont instanciées avec Environment.GetResourceString("...")afin que votre solution ne fonctionne plus. La meilleure chose est de lever une exception personnalisée avec votre propre texte de message (anglais) et d'utiliser la propriété InnerException pour conserver l'ancienne.
webber2k6
1
La réflexion pour obtenir les noms des types d'exceptions pourrait devenir pratique.
Guillermo Prandi
67

Vous pouvez rechercher le message d'exception d'origine sur unlocalize.com

user461128
la source
5
J'ai essayé de rechercher des messages d'exception chinois, m'a toujours dit No records found.
Tyler Long
1
Mauvais choix. Lorsque j'envoie mes exceptions à Google Analytics (ou à un autre service cloud), j'ai différents groupes d'exceptions pour la même exception, mais différentes langues. Et je ne pourrai pas trier par nombre de chaque exception, car il ne reflète pas le nombre réel (100 en anglais, 77 en chinois, 80 en coréen ... etc)
Artemious
Je me souviens d'avoir trouvé ce beau site Web à plusieurs reprises lorsque je simplement simplement vidé des messages d'exception localisés dans Google, maintenant il n'est plus disponible.
Martin Braun
40

Un point litigieux peut-être, mais au lieu de définir la culture en-US, vous pouvez le définir Invariant. Dans la Invariantculture, les messages d'erreur sont en anglais.

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

Il a l'avantage de ne pas sembler biaisé, en particulier pour les régions anglophones non américaines. (aka évite les remarques sournoises de ses collègues)

MPelletier
la source
1
Où devrions-nous écrire ces lignes dans notre projet ASP.NET? Merci.
jason
2
Je vais suggérer en haut, dans Application_Start. Cela fera que tout le projet se déroulera en anglais. Si ce n'est que pour les messages d'erreur que vous le souhaitez, vous pouvez créer une fonction de couverture et l'appeler dans chacun d'eux catch.
MPelletier
5
Cela ne rendra-t-il pas également les boutons de boîte de message standard en anglais? Ce n'est peut-être pas le comportement souhaité.
Nyerguds
12

Voici une solution qui ne nécessite aucun codage et fonctionne même pour les textes d'exceptions qui sont chargés trop tôt pour que nous puissions les modifier par code (par exemple, ceux de mscorlib).

Il ne peut pas toujours être applicable dans tous les cas (cela dépend de votre configuration car vous devez pouvoir créer un fichier .config à côté du fichier .exe principal) mais cela fonctionne pour moi. Donc, créez simplement un app.configin dev, (ou un [myapp].exe.configou web.configen production) qui contient les lignes suivantes par exemple:

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

Cela indique au framework de rediriger les liaisons d'assembly pour mscorlibles ressources et System.Xmlles ressources, pour les versions entre 1 et 999, en français (la culture est définie sur " fr") vers un assembly qui ... n'existe pas (un arbitraire version 999).

Ainsi, lorsque le CLR recherchera des ressources en français pour ces deux assemblys (mscorlib et System.xml), il ne les trouvera pas et se rabattra sur l'anglais avec élégance. Selon votre contexte et vos tests, vous souhaiterez peut-être ajouter d'autres assemblys à ces redirections (assemblys contenant des ressources localisées).

Bien sûr, je ne pense pas que cela soit pris en charge par Microsoft, alors utilisez-le à vos risques et périls. Eh bien, si vous détectez un problème, vous pouvez simplement supprimer cette configuration et vérifier qu'elle n'est pas liée.

Simon Mourier
la source
1
Fonctionne lorsque vous avez besoin d'une sortie en anglais des outils du testeur.
smg
J'ai essayé ça, mais ça n'a pas marché pour moi. Existe-t-il d'autres fichiers de ressources dans .net? Où puis-je les trouver?
BluE
1
Regardez dans c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Chaque langue possède un dossier de 2 lettres. N'oubliez pas de remplacer "fr" dans la réponse ci-dessus par la langue réelle utilisée. "non" pour le norvégien, "da" pour le danois, "sv" pour le suédois, etc.
Wolf5
Pour créer une liste COMPLÈTE, jetez un œil dans ce dossier. C'est environ 120 fichiers de ressources. Ajoutez chacun d'eux dans la config. Cela semble être la seule solution pour Windows 10 et plus récente pour l'instant, car il n'y a plus aucun moyen de désinstaller les modules linguistiques .Net dans les fenêtres plus récentes (sa partie du système d'exploitation). Il est même placé dans le GAC maintenant, donc la suppression de ces dossiers de langue ne semble pas fonctionner.
Wolf5
10

Windows doit avoir installé la langue de l'interface utilisateur que vous souhaitez utiliser. Si ce n'est pas le cas, il n'a aucun moyen de savoir par magie quel est le message traduit.

Dans un Windows 7 Ultimate en-US, avec pt-PT installé, le code suivant:

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;

Produit des messages en pt-PT, en-US et en-US. Puisqu'il n'y a pas de fichiers de culture français installés, il s'agit par défaut de la langue par défaut de Windows (installée?).

danobrega
la source
Cela a résolu le problème. Interface utilisateur polonaise dans ma situation, installé en packages de langue MUI ~ 260 Mo, en utilisant le programme Vistalizator.
Krzysztof Szynter
5

Je sais que c'est un vieux sujet, mais je pense que ma solution peut être tout à fait pertinente pour quiconque tombe dessus lors d'une recherche sur le Web:

Dans le journal des exceptions, vous pouvez vous connecter ex.GetType.ToString, ce qui enregistrerait le nom de la classe d'exception. Je m'attendrais à ce que le nom d'une classe soit indépendant de la langue et soit donc toujours représenté en anglais (par exemple "System.FileNotFoundException"), bien qu'à l'heure actuelle je n'ai pas accès à un système de langue étrangère pour tester la idée.

Si vous voulez également le texte du message d'erreur, vous pouvez créer un dictionnaire de tous les noms de classe d'exception possibles et de leurs messages équivalents dans la langue que vous préférez, mais pour l'anglais, je pense que le nom de classe est parfaitement approprié.

Barbare
la source
5
Ça ne marche pas. J'en ai un InvalidOperationException, jeté par System.Xml.XmlWellFormedWriter. Vous essayez de deviner quelle erreur spécifique s'est produite sans lire le message. Ça pourrait être mille choses différentes.
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;

Sans CONTOURNEMENT.

Tks :)


la source
vous avez oublié le;
KansaiRobot
4

Le paramètre Thread.CurrentThread.CurrentUICulturesera utilisé pour localiser les exceptions. Si vous avez besoin de deux types d'exceptions (une pour l'utilisateur, une pour vous), vous pouvez utiliser la fonction suivante pour traduire le message d'exception. Il recherche dans les ressources .NET-Libraries le texte d'origine pour obtenir la clé de ressource, puis renvoie la valeur traduite. Mais il y a une faiblesse pour laquelle je n'ai pas encore trouvé de bonne solution: les messages contenant {0} dans les ressources ne seront pas trouvés. Si quelqu'un a une bonne solution, je vous en serais reconnaissant.

public static string TranslateExceptionMessage(Exception ex, CultureInfo targetCulture)
{
    try
    {
        Assembly assembly = ex.GetType().Assembly;
        ResourceManager resourceManager = new ResourceManager(assembly.GetName().Name, assembly);
        ResourceSet originalResources = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, createIfNotExists: true, tryParents: true);
        ResourceSet targetResources = resourceManager.GetResourceSet(targetCulture, createIfNotExists: true, tryParents: true);
        foreach (DictionaryEntry originalResource in originalResources)
            if (originalResource.Value.ToString().Equals(ex.Message.ToString(), StringComparison.Ordinal))
                return targetResources.GetString(originalResource.Key.ToString(), ignoreCase: false); // success

    }
    catch { }
    return ex.Message; // failed (error or cause it's not smart enough to find texts with '{0}'-patterns)
}
Vortex852456
la source
Cela ne fonctionnera pas si l'exception contient un paramètre formaté.
Nick Berardi
Oui, comme je l'ai dit: "Mais il y a une faiblesse, je n'ai pas encore trouvé de bonne solution: les messages contenant {0} dans les ressources ne seront pas trouvés. Si quelqu'un a une bonne solution, je lui en serais reconnaissant."
Vortex852456
3

Le framework .NET se compose de deux parties:

  1. Le framework .NET lui-même
  2. Les packs de langue du framework .NET

Tous les textes (ex. Messages d'exception, libellés de boutons sur un MessageBox, etc.) sont en anglais dans le framework .NET lui-même. Les modules linguistiques contiennent les textes localisés.

Selon votre situation exacte, une solution serait de désinstaller les modules linguistiques (c'est-à-dire de dire au client de le faire). Dans ce cas, les textes d'exception seront en anglais. Notez cependant que tous les autres textes fournis par le framework seront également en anglais (par exemple, les étiquettes des boutons sur une MessageBox, les raccourcis clavier pour ApplicationCommands).

Daniel Rose
la source
Merci!! Je trouve ironique que la boîte de dialogue de désinstallation soit dans la langue du pack de désinstallation et non dans la langue locale. Remarque: les modules linguistiques semblent revenir tous les quelques mois. je n'ai pas compris pourquoi mais je devine une mise à jour / mise à niveau
Choco Smith
@ChocoSmith Avec chaque mise à jour du .NET Framework via Windows Update, le module linguistique est réinstallé.
Daniel Rose
5
Demander aux clients de désinstaller les modules linguistiques pour leur propre langue n'est pas une solution viable.
Nyerguds
2

J'imagine une de ces approches:

  1. Les exceptions ne sont lues que par vous, c'est-à-dire qu'elles ne sont pas une fonctionnalité client, vous pouvez donc utiliser des chaînes câblées non localisées qui ne changeront pas lorsque vous exécutez en mode turc.

  2. Incluez un code d'erreur, par exemple 0x00000001avec chaque erreur, afin de pouvoir le rechercher facilement dans un tableau anglais.

morechilli
la source
9
Cela n'aidera pas beaucoup quand ce sont des exceptions levées par les composants internes du framework .net . Ce problème ne s'applique pas aux exceptions que vous vous lancez; évidemment, le programmeur choisit quel message inclure avec ceux-ci .
Nyerguds
1

Basé sur la réponse Undercover1989, mais prend en compte les paramètres et lorsque les messages sont composés de plusieurs chaînes de ressources (comme les exceptions d'argument).

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;
}
Jan
la source
1

J'ai eu la même situation, et toutes les réponses que j'ai trouvées ici et ailleurs n'ont pas aidé ou n'étaient pas satisfaisantes:

Le Thread.CurrentUICulturechange la langue des exceptions .net, mais ce n'est pas le cas Win32Exception, qui utilise les ressources Windows dans la langue de l'interface utilisateur Windows elle-même. Je n'ai donc jamais réussi à imprimer les messages Win32Exceptionen anglais au lieu de l'allemand, pas même en utilisant FormatMessage()comme décrit dans
Comment obtenir Win32Exception en anglais?

J'ai donc créé ma propre solution, qui stocke la majorité des messages d'exception existants pour différentes langues dans des fichiers externes. Vous n'obtiendrez pas le message très exact dans la langue de votre choix, mais vous obtiendrez un message dans cette langue, ce qui est beaucoup plus que ce que vous obtenez actuellement (qui est un message dans une langue que vous ne comprenez probablement pas).

Les fonctions statiques de cette classe peuvent être exécutées sur des installations Windows avec différentes langues: CreateMessages()crée les textes spécifiques à la culture les
SaveMessagesToXML()enregistre dans autant de fichiers XML que de langues sont créées ou chargées
LoadMessagesFromXML()charge tous les fichiers XML avec des messages spécifiques à la langue

Lors de la création des fichiers XML sur différentes installations Windows avec différentes langues, vous aurez bientôt toutes les langues dont vous avez besoin.
Peut-être que vous pouvez créer des textes pour différentes langues sur 1 Windows lorsque plusieurs modules linguistiques MUI sont installés, mais je ne l'ai pas encore testé.

Testé avec VS2008, prêt à l'emploi. Les commentaires et suggestions sont les bienvenus!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    GetExceptionMessages(dictExceptionMessage);
    GetExceptionMessagesWin32(dictExceptionMessage);

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

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

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

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

    return listoExceptionType;
  }

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

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

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

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

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

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

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

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

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

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

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

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

internal class Program
{
  public static void Main()
  {
    CException.CreateMessages(null);
    CException.SaveMessagesToXML(@"d:\temp\", "emsg");
    CException.LoadMessagesFromXML(@"d:\temp\", "emsg");
  }
}
Tobias Knauss
la source
1
Le change Thread.CurrentUICulture également la langue de l'interface utilisateur, ce qui en fait une option terrible. Un exemple classique sont les boutons Oui / Non / OK / Annuler dans la boîte de message.
Nyerguds
0

Messages d'exception en anglais

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

puis allez dans le dossier Localisation et placez-le dans projectName.xml et ajoutez

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

Vous devez enregistrer la pile d'appels au lieu de simplement un message d'erreur (IIRC, simple exception.ToString () devrait le faire pour vous). De là, vous pouvez déterminer exactement d'où provient l'exception et généralement déduire de quelle exception il s'agit.

Branko Dimitrijevic
la source
3
Nous enregistrons le message et le stacktrace. Mais c'est beaucoup plus facile si le message est clair.
Carra
-1

Remplacez le message d'exception dans le bloc catch à l'aide de la méthode d'extension, le message de vérification provient du code ou non, comme mentionné ci-dessous.

    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();
        }
user3472484
la source
1
Comme je l' ai déjà dit ... InvalidOperationException. Amusez-vous à comprendre ce que cela signifie sans le message lui-même. Une nouvelle instance ne l'aura pas comme par magie.
Nyerguds
-1

À des fins de journalisation, certaines applications peuvent avoir besoin de récupérer le message d'exception en anglais (en plus de l'afficher dans l'UICulture du client habituel).

A cet effet, le code suivant

  1. modifie l'UICulture actuelle
  2. recrée l'objet Exception levé à l'aide de "GetType ()" & "Activator.CreateInstance (t)"
  3. affiche le message du nouvel objet Exception dans la nouvelle UICuture
  4. puis change finalement l'UICulture actuelle à l'UICulture précédente.

        try
        {
            int[] a = { 3, 6 };
            Console.WriteLine(a[3]); //Throws index out of bounds exception
    
            System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
            throw new System.IO.IOException();
    
        }
        catch (Exception ex)
        {
    
            Console.WriteLine(ex.Message);
            Type t = ex.GetType();
    
            CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
    
            object o = Activator.CreateInstance(t);
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
    
    
            Console.WriteLine(((Exception)o).Message.ToString());
            Console.ReadLine();
    
         }
Ron16
la source
1
cela ne garantit pas que le message d'exception du nouvel objet est le même que l'exception levée. Cela peut être totalement différent, et généralement c'est totalement différent. C'est pourquoi nous avons besoin du message d'exception.
Artemious