Mensagens de exceção em inglês?

298

Estamos registrando quaisquer exceções que ocorram em nosso sistema, escrevendo o Exception.Message em um arquivo. No entanto, eles são escritos na cultura do cliente. E erros turcos não significam muito para mim.

Então, como podemos registrar qualquer mensagem de erro em inglês sem alterar a cultura do usuário?

Carra
fonte
8
Por que você não pode mudar assim: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // lança nova exceção aqui => A cultura está em inglês Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra 16/10/08
93
Eu sei que nenhum desenvolvedor, que está feliz por mensagens de exceção não-inglês: S ..
Zéiksz
3
@ Zéiksz Olhe além dos países de língua inglesa e você encontrará muitos deles: D. Problema não é um texto em inglês, o problema é um idioma que você não consegue entender. Mensagens na sua língua nativa (supondo tradução adequada) estão perfeitamente corretas.
Alejandro
31
@Alejandro Ter que traduzir uma mensagem de exceção de um idioma nativo para o inglês para o google é uma dor ainda maior. Na minha humilde opinião.
Antoine Meltzheim
18
Qual idiota da Microsoft teve a ideia de traduzir mensagens de erro que são apenas para desenvolvedores. Até termos usados ​​na linguagem de programação, como uma chave em um dicionário, são traduzidos. (A chave não foi encontrada no dicionário torna-se Sleutel in niet gevonden in de bibliotheek em holandês). Eu não quero mudar o idioma do sistema operacional para este ...
Roel

Respostas:

66

Esse problema pode ser parcialmente contornado. O código de exceção do Framework carrega as mensagens de erro de seus recursos, com base no código do idioma do encadeamento atual. No caso de algumas exceções, isso acontece no momento em que a propriedade Message é acessada.

Para essas exceções, você pode obter a versão completa da mensagem em inglês dos EUA, alternando brevemente o código do idioma do encadeamento para en-US enquanto o registra (salvando o código do idioma original do usuário antes e restaurando-o imediatamente depois).

Fazer isso em um thread separado é ainda melhor: isso garante que não haverá efeitos colaterais. Por exemplo:

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

Onde a classe ExceptionLogger se parece com:

class ExceptionLogger
{
  Exception _ex;

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

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

No entanto, como Joe aponta corretamente em um comentário em uma revisão anterior desta resposta, algumas mensagens já são (parcialmente) carregadas dos recursos de idioma no momento em que a exceção é lançada.

Isso se aplica à parte 'parâmetro não pode ser nulo' da mensagem gerada quando uma exceção ArgumentNullException ("foo") é lançada, por exemplo. Nesses casos, a mensagem ainda aparecerá (parcialmente) localizada, mesmo ao usar o código acima.

Além de usar hacks impraticáveis, como executar todo o código que não é da interface do usuário em um thread com localidade en-US, não parece haver muito o que você possa fazer sobre isso: o código de exceção do .NET Framework não tem recursos para substituir o código de idioma da mensagem de erro.

mdb
fonte
10
Seu exemplo funciona para uma FileNotFoundException, porque o recurso de mensagem é recuperado quando a propriedade Message é acessada, não quando a exceção é lançada. Mas isso não é verdade para todas as exceções (por exemplo, tentar lance novo ArgumentNullException ( "paramName"))
Joe
3
Estou confuso. Eu tentei seguir sua resposta e para testá-lo eu queria que meu exceção em francês, então eu fiz t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");e t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");ainda, a exceção resultante era em Inglês ...
VitalyB
7
@VitalyB Os textos de exceção localizados fazem parte dos pacotes de idiomas da estrutura .NET. Portanto, se você não tiver o pacote de idiomas francês instalado, não receberá os textos traduzidos.
31514 Daniel
7
Pelo menos com o .NET 4.5, todas as exceções são instanciadas Environment.GetResourceString("...")para que sua solução não funcione mais. O melhor é lançar uma exceção personalizada com seu próprio texto de mensagem (em inglês) e usar a propriedade InnerException para manter a antiga.
Webber2k6 15/05
1
A reflexão para obter os nomes dos tipos de exceção pode se tornar útil.
Guillermo Prandi
67

Você pode procurar a mensagem de exceção original em unlocalize.com

user461128
fonte
5
Tentei pesquisar algumas mensagens de exceção em chinês, sempre me dizia No records found.
Tyler Longo
1
Má escolha. Quando envio minhas exceções para o Google Analytics (ou outro serviço em nuvem), terei diferentes grupos de exceções para a mesma exceção, mas com idiomas diferentes. E eu não vou ser capaz de classificar por contagem de cada exceção, porque não reflete a contagem real (100 em Inglês, 77 em chinês, 80 em coreano ... etc)
Artemious
Lembro-me de encontrar esse site bonito muitas vezes quando simplesmente despejei mensagens de exceção localizadas no Google, agora não está mais disponível.
Martin Braun
40

Um ponto controverso, talvez, mas em vez de definir a cultura en-US, você pode configurá-lo Invariant. Na Invariantcultura, as mensagens de erro estão em inglês.

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

Ele tem a vantagem de não parecer tendencioso, especialmente para locais que não falam inglês. (também evita comentários maliciosos dos colegas)

MPelletier
fonte
1
Onde devemos escrever essas linhas em nosso projeto ASP.NET? Obrigado.
jason
2
Vou sugerir no topo, em Application_Start. Isso fará com que todo o projeto seja executado em inglês. Se você quiser apenas as mensagens de erro, poderá criar uma função de capa e chamá-la em cada uma catch.
MPelletier
5
Isso também não fará com que os botões padrão das caixas de mensagens estejam em inglês? Esse pode não ser o comportamento desejado.
21417 Nyerguds
12

Aqui está uma solução que não requer codificação e funciona mesmo para textos de exceções carregados muito cedo para que possamos alterar por código (por exemplo, os do mscorlib).

Pode não ser sempre aplicável em todos os casos (depende da sua configuração, pois você precisa criar um arquivo .config além do arquivo .exe principal), mas isso funciona para mim. Portanto, basta criar um app.configin dev, (ou um [myapp].exe.configou web.configem produção) que contenha as seguintes linhas, por exemplo:

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

O que isso faz é dizer à estrutura para redirecionar as ligações de assembly para mscorlibos recursos e System.Xmlrecursos de, para versões entre 1 e 999, em francês (a cultura é definida como " fr") para um assembly que ... não existe (um arbitrário versão 999).

Portanto, quando o CLR procurará recursos em francês para esses dois assemblies (mscorlib e System.xml), ele não os encontrará e retornará ao inglês normalmente. Dependendo do contexto e dos testes, convém adicionar outros assemblies a esses redirecionamentos (assemblies que contêm recursos localizados).

Claro que não acho que isso seja suportado pela Microsoft, portanto, use por seu próprio risco. Bem, caso você detecte um problema, basta remover essa configuração e verificar se não está relacionada.

Simon Mourier
fonte
1
Funciona quando é necessário saída em inglês das ferramentas test-runner.
smg
Tentei isso, mas não funcionou para mim. Existem outros arquivos de recursos no .net? Onde posso encontrá-los?
BluE 15/10/19
1
Procure em c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Todo idioma tem uma pasta de 2 letras lá. Lembre-se de substituir "fr" na resposta acima pelo idioma real que está sendo usado. "não" para norueguês, "da" para dinamarquês, "sv" para sueco etc.
Wolf5 17/10/18
Para criar uma lista COMPLETA, dê uma olhada nessa pasta. São cerca de 120 arquivos de recursos. Adicione cada um deles na configuração. Essa parece ser a única solução para o Windows 10 e mais recente no momento, já que não há mais como desinstalar os pacotes de idiomas .Net nas janelas mais recentes (parte do sistema operacional). Ele ainda está no GAC agora, portanto, a remoção dessas pastas de idiomas parece não funcionar.
precisa saber é o seguinte
10

O Windows precisa ter o idioma da interface do usuário que você deseja usar instalado. Não tem, não tem como saber magicamente qual é a mensagem traduzida.

Em um Windows 7 final nos EUA, com o pt-PT instalado, o seguinte código:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("pt-PT");
string msg1 = new DirectoryNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
string msg2 = new FileNotFoundException().Message;

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
string msg3 = new FileNotFoundException().Message;

Produz mensagens em pt-PT, en-US e en-US. Como não há arquivos de cultura francesa instalados, o padrão é o idioma padrão do Windows (instalado?).

danobrega
fonte
Isso resolveu o problema. UI polonesa na minha situação, instalada em pacotes de idiomas MUI ~ 260 MB, usando o programa Vistalizator.
Krzysztof Szynter
5

Sei que esse é um tópico antigo, mas acho que minha solução pode ser bastante relevante para qualquer um que o encontre em uma pesquisa na web:

No registrador de exceções, você pode registrar ex.GetType.ToString, o que salvaria o nome da classe de exceção. Eu esperaria que o nome de uma classe devesse ser independente do idioma e, portanto, sempre seria representado em inglês (por exemplo, "System.FileNotFoundException"), embora, atualmente, não tenha acesso a um sistema de idioma estrangeiro para testar o idéia.

Se você realmente deseja o texto da mensagem de erro, pode criar um dicionário com todos os nomes possíveis de classes de exceção e suas mensagens equivalentes no idioma que preferir, mas, para o inglês, acho que o nome da classe é perfeitamente adequado.

bárbaro
fonte
5
Não funciona Eu tenho um InvalidOperationException, jogado por System.Xml.XmlWellFormedWriter. Você tenta adivinhar qual erro específico ocorreu sem ler a mensagem. Pode haver mil coisas diferentes.
precisa saber é o seguinte
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;

Sem soluções alternativas.

Tks :)


fonte
você esqueceu o;
KansaiRobot
4

A configuração Thread.CurrentThread.CurrentUICultureserá usada para localizar as exceções. Se você precisar de dois tipos de exceções (uma para o usuário e outra para você), poderá usar a função a seguir para converter a mensagem de exceção. Ele está pesquisando nos recursos do .NET-Libraries o texto original para obter a chave do recurso e retornar o valor traduzido. Mas há um ponto fraco que ainda não encontrei uma boa solução: As mensagens que contêm {0} em recursos não serão encontradas. Se alguém tiver uma boa solução, ficaria 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)
}
Vortex852456
fonte
Isso não funcionará se a exceção contiver um parâmetro formatado.
quer
Sim, como eu disse: "Mas há uma fraqueza que ainda não encontrei uma boa solução: as mensagens que contêm {0} em recursos não serão encontradas. Se alguém tiver uma boa solução, ficaria grato."
Vortex852456
3

A estrutura .NET vem em duas partes:

  1. A própria estrutura .NET
  2. Os pacotes de idiomas da estrutura .NET

Todos os textos (por exemplo, mensagens de exceção, rótulos de botão em uma MessageBox etc.) estão em inglês no próprio .NET framework. Os pacotes de idiomas têm os textos localizados.

Dependendo da sua situação exata, uma solução seria desinstalar os pacotes de idiomas (ou seja, instruir o cliente a fazer isso). Nesse caso, os textos de exceção serão em inglês. Observe, no entanto, que todos os outros textos fornecidos pela estrutura também serão em inglês (por exemplo, os rótulos de botão em uma MessageBox, atalhos de teclado para ApplicationCommands).

Daniel Rose
fonte
Obrigado!! Acho irônico que a caixa de diálogo de desinstalação esteja no idioma do pacote de desinstalação e não no idioma local. Nota lateral: os pacotes de idiomas parecem retornar a cada poucos meses. Eu não tenho trabalhado por que, mas eu estou supondo que uma atualização / upgrade
Choco Smith
@ChocoSmith Com todas as atualizações do .NET Framework via Windows Update, o pacote de idiomas é instalado novamente.
Daniel Rose
5
Pedir aos clientes para desinstalar os pacotes de idiomas para o seu próprio idioma não é uma solução viável.
precisa saber é o seguinte
2

Eu imaginaria uma dessas abordagens:

  1. As exceções são lidas apenas por você, ou seja, não são um recurso do cliente; portanto, você pode usar cadeias não localizadas conectadas que não serão alteradas quando você executar no modo turco.

  2. Inclua um código de erro, por exemplo, 0x00000001com cada erro, para que você possa procurá-lo facilmente em uma tabela em inglês.

morechilli
fonte
9
Isso não ajudará muito quando forem exceções geradas por componentes internos da estrutura .net . Todo esse problema não se aplica às exceções que você lança; obviamente, o programador escolhe qual mensagem incluir nesses itens .
Nyerguds
1

Com base na resposta Undercover1989, mas leva em consideração parâmetros e quando as mensagens são compostas por várias seqüências de recursos (como exceções de argumento).

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

Eu tive a mesma situação e todas as respostas que encontrei aqui e em outros lugares não ajudaram ou não foram satisfatórias:

A Thread.CurrentUICulturealtera o idioma das exceções .net, mas ele faz não para Win32Exception, que utiliza recursos do Windows na linguagem da própria interface do usuário do Windows. Portanto, nunca consegui imprimir as mensagens Win32Exceptionem inglês em vez de alemão, nem mesmo usando FormatMessage()o descrito em
Como obter o Win32Exception em inglês?

Portanto, criei minha própria solução, que armazena a maioria das mensagens de exceção existentes para diferentes idiomas em arquivos externos. Você não receberá a mensagem exata no idioma desejado, mas receberá uma mensagem nesse idioma, que é muito mais do que recebe atualmente (que é uma mensagem em um idioma que você provavelmente não entende).

As funções estáticas dessa classe podem ser executadas em instalações do Windows com diferentes idiomas: CreateMessages()cria os textos específicos da cultura e os
SaveMessagesToXML()salva em tantos arquivos XML quantos idiomas são criados ou carregados
LoadMessagesFromXML()carrega todos os arquivos XML com mensagens específicas do idioma

Ao criar os arquivos XML em diferentes instalações do Windows com diferentes idiomas, em breve você terá todos os idiomas necessários.
Talvez você possa criar textos para diferentes idiomas no Windows 1 quando tiver vários pacotes de idiomas MUI instalados, mas ainda não testei isso.

Testado com o VS2008, pronto para uso. Comentários e sugestões são bem-vindos!

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
fonte
1
O Thread.CurrentUICulture também altera o idioma da interface do usuário, tornando-se uma terrível opção. Um exemplo clássico são os botões Sim / Não / OK / Cancelar na caixa de mensagem.
21917 Nyerguds
0

Mensagens de exceção em inglês

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

vá para a pasta Localização e coloque-a em projectName.xml e adicione

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

Você deve registrar a pilha de chamadas em vez de apenas a mensagem de erro (IIRC, exceção simples. ToString () deve fazer isso por você). A partir daí, você pode determinar exatamente de onde a exceção se originou e geralmente deduzir qual exceção é.

Branko Dimitrijevic
fonte
3
Estamos registrando a mensagem e o rastreamento de pilha. Mas é muito mais fácil se a mensagem estiver clara.
Carra 28/05
-1

Substituir mensagem de exceção no bloco catch usando o método de extensão. A mensagem de verificação emitida é do código ou não, conforme mencionado abaixo.

    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
fonte
1
Como eu disse antes ... InvalidOperationException. Divirta-se descobrindo o que isso significa sem a própria mensagem. Uma nova instância não a terá magicamente.
Nyerguds
-1

Para fins de log, certos aplicativos podem precisar buscar a mensagem de exceção em inglês (além de exibi-la na UICulture do cliente habitual).

Para esse efeito, o seguinte código

  1. altera a UICulture atual
  2. recria o objeto de exceção lançado usando "GetType ()" e "Activator.CreateInstance (t)"
  3. exibe a mensagem do novo objeto de exceção no novo UICuture
  4. e, finalmente, altera a UICulture atual novamente para a UICulture anterior.

        try
        {
            int[] a = { 3, 6 };
            Console.WriteLine(a[3]); //Throws index out of bounds exception
    
            System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
            throw new System.IO.IOException();
    
        }
        catch (Exception ex)
        {
    
            Console.WriteLine(ex.Message);
            Type t = ex.GetType();
    
            CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
    
            object o = Activator.CreateInstance(t);
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
    
    
            Console.WriteLine(((Exception)o).Message.ToString());
            Console.ReadLine();
    
         }
Ron16
fonte
1
isso não garante que a mensagem de exceção do novo objeto seja a mesma que a exceção lançada. Pode ser totalmente diferente e, geralmente, é totalmente diferente. É por isso que precisamos da mensagem de exceção.
Artemious 24/09/17