영어로 된 예외 메시지?


298

Exception.Message를 파일에 작성하여 시스템에서 발생하는 모든 예외를 로깅합니다. 그러나 그들은 고객의 문화로 작성되었습니다. 터키의 실수는 나에게 큰 의미가 없습니다.

그렇다면 사용자 문화를 바꾸지 않고 어떻게 오류 메시지를 영어로 기록 할 수 있습니까?


8
왜 이런 식으로 질주 할 수 없습니까? CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ( "en"); // 여기에 새로운 예외를 던져라 => 문화는 영어입니다 Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra

93
영어가 아닌 예외 메시지에 만족하는 개발자는 없습니다 : S ..
Zéiksz

3
@ Zéiksz 영어권 국가를 넘어 서면 많은 나라를 찾을 수 있습니다 : D. 영어가 아닌 텍스트가 아닌 문제는 이해할 수없는 언어입니다. 모국어로 된 메시지 (적절한 번역으로 가정)는 완벽합니다.
Alejandro

31
@Alejandro 구글을 위해 하나의 모국어에서 영어로 예외 메시지를 번역 해야하는 것은 arse에서 훨씬 더 큰 고통입니다. 임호.
Antoine Meltzheim

18
Microsoft의 어떤 바보가 개발자에게만 해당되는 오류 메시지를 번역하려고 생각했습니다. 사전의 키와 같이 프로그래밍 언어에서 사용되는 용어조차도 번역됩니다. (사전의 키는 네덜란드어의 bibliotheek의 niet gevonden에서 Sleutel이됩니다). OS 언어를 변경하고 싶지 않습니다.
Roel

답변:


66

이 문제는 부분적으로 해결 될 수 있습니다. Framework 예외 코드는 현재 스레드 로캘을 기반으로 리소스에서 오류 메시지를로드합니다. 일부 예외의 경우 Message 속성에 액세스 할 때 발생합니다.

이러한 예외가 발생하는 경우 스레드 로캘을 en-US로 간단히 전환하여 로그를 기록하여 메시지의 전체 영어 버전 메시지를 얻을 수 있습니다 (원래의 사용자 로캘을 미리 저장 한 후 바로 복원).

별도의 스레드에서이 작업을 수행하는 것이 더 좋습니다. 이렇게하면 부작용이 발생하지 않습니다. 예를 들면 다음과 같습니다.

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

ExceptionLogger 클래스는 다음과 같습니다.

class ExceptionLogger
{
  Exception _ex;

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

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

그러나 Joe 가이 회신의 이전 개정에 대한 주석에서 올바르게 지적한 것처럼 일부 메시지는 예외가 발생할 때 언어 자원에서 이미 (부분적으로)로드됩니다.

예를 들어 ArgumentNullException ( "foo") 예외가 발생할 때 생성 된 메시지의 '매개 변수가 널일 수 없음'부분에 적용됩니다. 이러한 경우 위의 코드를 사용하더라도 메시지가 여전히 부분적으로 현지화되어 나타납니다.

en-US 로켈이있는 스레드에서 UI가 아닌 모든 코드를 실행하는 등 실용적이 아닌 해킹을 사용하는 것 외에는 할 수있는 일이 많지 않습니다. .NET Framework 예외 코드에는 오류 메시지 로캘을 재정의하는 기능


10
예외가 발생했을 때가 아니라 Message 속성에 액세스 할 때 메시지 리소스가 검색되므로 FileNotFoundException에 대한 예제가 작동합니다. 그러나 이것은 모든 예외에 대해 사실이 아닙니다 (예 : 새로운 ArgumentNullException ( "paramName") 던지기
Joe

3
혼란 스러워요. 내가했다, 그래서 당신의 대답을 다음과 내가 프랑스어로 내 예외를 원하는 그것을 테스트 해봤 t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");하고 t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");... 결과 예외가 영어이고, 아직
VitalyB

7
@VitalyB 지역화 된 예외 텍스트는 .NET 프레임 워크 언어 팩의 일부입니다. 따라서 프랑스어 언어 팩이 설치되어 있지 않으면 번역 된 텍스트를 얻을 수 없습니다.
Daniel Rose

7
적어도 .NET 4.5에서는 모든 예외가 인스턴스화되어 Environment.GetResourceString("...")솔루션이 더 이상 작동하지 않습니다. 가장 좋은 것은 자신의 (영어) 메시지 텍스트로 사용자 정의 예외를 던지고 InnerException 속성을 사용하여 이전 예외를 유지하는 것입니다.
webber2k6

1
예외 유형 이름을 가져 오는 것이 편리 할 수 ​​있습니다.
기예르모 프란 디

67

unlocalize.com 에서 원래 예외 메시지를 검색 할 수 있습니다.


5
중국어 예외 메시지 검색을 시도했지만 항상 나에게 말했다 No records found.
Tyler Long

1
나쁜 선택. 예외를 Google 웹 로그 분석 (또는 다른 클라우드 서비스)에 보내면 동일한 예외에 대해 다른 언어 그룹의 예외 그룹이 적용됩니다. 그리고 실제 예외 (영어 100, 중국어 77, 한국어 80 등)를 반영하지 않기 때문에 각 예외 수를 기준으로 정렬 할 수 없습니다.
Artemious

현지화 된 예외 메시지를 Google에 간단히 덤프했을 때이 아름다운 웹 사이트를 여러 번 찾은 것을 기억합니다. 이제는 더 이상 사용할 수 없습니다.
마틴 브라운

40

논쟁의 여지가 있지만 문화를로 설정하는 대신로 설정할 en-US수 있습니다 Invariant. 에서 Invariant문화, 오류 메시지가 영어로되어 있습니다.

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

비 미국 영어권 지역에서는 편향적으로 보이지 않는 장점이 있습니다. (일명 동료의 비난을 피함)


1
ASP.NET 프로젝트에서이 줄을 어디에 써야합니까? 감사.
Jason Jason

2
Application_Start에서 맨 위에 제안하겠습니다. 전체 프로젝트가 영어로 실행됩니다. 원하는 오류 메시지에만 해당되는 경우 표지 기능을 만들어 각에서 호출 할 수 있습니다 catch.
MPelletier

5
그래도 표준 메시지 상자 버튼을 영어로 만들지 않습니까? 그것은 바람직한 행동이 아닙니다.
Nyerguds

12

다음은 코딩이 필요하지 않으며 너무 일찍로드 된 예외 텍스트 (예 : mscorlib의 텍스트)로 변경할 수없는 예외 텍스트에도 작동하는 솔루션입니다.

모든 경우에 항상 적용 가능한 것은 아니지만 (주 .exe 파일과 함께 .config 파일을 만들 수 있어야하기 때문에 설정에 따라 다릅니다) 그러나 그것은 저에게 효과적입니다. 따라서 예를 들어 다음과 같은 줄이 포함 된 app.configin dev (또는 a [myapp].exe.config또는 web.configproduction)를 만드십시오 .

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

이 작업은 프레임 워크 에서 프랑스어 (문화는 " " 로 설정 됨)의 프랑스어 (문화는 " " 로 설정 됨 )에서 존재하지 않는 (임의의) 임의의 (임의 mscorlib의) 리소스 및 리소스에 대한 어셈블리 바인딩을 리디렉션 하도록 지시합니다. 버전 999).System.Xmlfr

따라서 CLR이이 두 어셈블리 (mscorlib 및 System.xml)에 대한 프랑스어 리소스를 찾을 때는 찾지 못하고 정상적으로 영어로 대체됩니다. 상황과 테스트에 따라 이러한 리디렉션 (현지화 된 리소스가 포함 된 어셈블리)에 다른 어셈블리를 추가 할 수 있습니다.

물론 이것이 Microsoft에서 지원한다고 생각하지 않으므로 자신의 책임하에 사용하십시오. 문제를 발견 한 경우이 구성을 제거하고 관련이 없는지 확인할 수 있습니다.


1
테스트 실행기 도구에서 영어 출력이 필요할 때 작동합니다.
smg

이것을 시도했지만 그것은 효과가 없었습니다. .net에 다른 리소스 파일이 있습니까? 어디서 찾을 수 있습니까?
BluE

1
c : \ Windows \ Microsoft.NET \ Framework \ v4.0.30319를보십시오. 모든 언어에는 2 글자 폴더가 있습니다. 위의 답변에서 "fr"을 사용중인 실제 언어로 바꾸십시오. "no"노르웨이어, "da"덴마크어, "sv"스웨덴어 등
Wolf5

전체 목록을 만들려면 해당 폴더를 살펴보십시오. 약 120 개의 리소스 파일입니다. 각 구성을 구성에 추가하십시오. 더 이상 새 창 (OS의 일부)에서 .Net 언어 팩을 제거 할 수있는 방법이 없기 때문에 이것은 현재 Windows 10 이상에서 유일한 솔루션 인 것 같습니다. 이제 GAC에 배치되었으므로 해당 언어 폴더를 제거해도 작동하지 않는 것 같습니다.
Wolf5

10

Windows에는 사용하려는 UI 언어가 설치되어 있어야합니다. 번역 된 메시지가 무엇인지 마술처럼 알 수있는 방법은 없습니다.

pt-PT가 설치된 en-US Windows 7 Ultimate에서 다음 코드는 다음과 같습니다.

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;

pt-PT, en-US 및 en-US로 메시지를 생성합니다. 프랑스어 문화권 파일이 설치되어 있지 않기 때문에 기본적으로 Windows 기본 (설치?) 언어가 사용됩니다.


문제가 해결되었습니다. 내 상황에서 폴란드어 UI는 Vistalizator 프로그램을 사용하여 ~ 260MB의 MUI 언어 패키지를 설치했습니다.
Krzysztof Szynter

5

나는 이것이 오래된 주제라는 것을 알고 있지만 내 솔루션은 웹 검색에서 우연히 발견되는 사람과 관련이 있다고 생각합니다.

예외 로거에서 ex.GetType.ToString을 기록하면 예외 클래스의 이름이 저장됩니다. 클래스의 이름은 언어와 독립적이어야하고 따라서 항상 영어로 표시 될 것으로 기대합니다 (예 : "System.FileNotFoundException"). 현재로서는 외국어 시스템에 액세스 할 수는 없습니다. 생각.

오류 메시지 텍스트를 정말로 원한다면 가능한 모든 예외 클래스 이름과 해당 메시지의 사전을 원하는 언어로 만들 수 있지만 영어의 경우 클래스 이름이 완벽하다고 생각합니다.


5
작동하지 않습니다. 에 InvalidOperationException의해 던져졌다 System.Xml.XmlWellFormedWriter. 메시지를 읽지 않고 발생한 특정 오류를 추측하십시오. 천 가지가 될 수 있습니다.
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;

해결 방법이 없습니다.

Tks :)


당신은 잊었다;
KansaiRobot

4

Thread.CurrentThread.CurrentUICulture예외를 지역화하는 데 설정 이 사용됩니다. 두 종류의 예외가 필요한 경우 (하나는 사용자를 위해, 하나는 사용자를 위해) 다음 함수를 사용하여 예외 메시지를 번역 할 수 있습니다. .NET-Library 리소스에서 리소스 키를 가져온 다음 번역 된 값을 반환하기 위해 원본 텍스트를 검색합니다. 그러나 아직 좋은 해결책을 찾지 못한 한 가지 약점이 있습니다. 리소스에 {0}이 (가) 포함 된 메시지를 찾을 수 없습니다. 누구든지 좋은 해결책이 있다면 감사 할 것입니다.

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

예외에 형식이 지정된 매개 변수가 포함되어 있으면 작동하지 않습니다.
Nick Berardi

그러나 내가 말했듯이 "하지만 한 가지 약점은 아직 좋은 해결책을 찾지 못했습니다. 리소스에 {0}을 (를) 포함하는 메시지를 찾을 수 없습니다. 좋은 해결책을 가진 사람이 있으면 감사하겠습니다."
Vortex852456

3

.NET 프레임 워크는 두 부분으로 구성됩니다.

  1. .NET 프레임 워크 자체
  2. .NET 프레임 워크 언어 팩

모든 텍스트 (예 : 예외 메시지, MessageBox의 단추 레이블 등)는 .NET 프레임 워크 자체에서 영어로되어 있습니다. 언어 팩에는 현지화 된 텍스트가 있습니다.

정확한 상황에 따라 해결책은 언어 팩을 제거하는 것입니다 (즉, 클라이언트에게 그렇게하도록 지시). 이 경우 예외 텍스트는 영어입니다. 그러나 다른 모든 프레임 워크 제공 텍스트도 영어입니다 (예 : MessageBox의 단추 레이블, ApplicationCommands의 키보드 단축키).


감사!! 제거 대화 상자가 로컬 언어가 아닌 제거 팩의 언어로되어 있다는 것이 아이러니합니다. 참고 : 언어 팩은 몇 개월마다 다시 표시되는 것 같습니다. 나는 이유를 해결하지 못했지만 업데이트 / 업그레이드를 추측하고 있습니다.
Choco Smith

@ChocoSmith Windows Update를 통해 .NET Framework를 업데이트 할 때마다 언어 팩이 다시 설치됩니다.
다니엘 로즈

5
고객에게 자신의 언어에 맞는 언어 팩을 제거하도록 요청하는 것은 실행 가능한 해결책이 아닙니다.
Nyerguds

2

나는 이러한 접근법 중 하나를 상상할 것이다.

  1. 예외는 사용자 만 읽을 수 있습니다. 즉, 클라이언트 기능이 아니므로 터키어 모드에서 실행할 때 변경되지 않는 고정 배선 된 현지화되지 않은 문자열을 사용할 수 있습니다.

  2. 0x00000001영어 테이블에서 쉽게 찾을 수 있도록 각 오류에 오류 코드를 포함 하십시오.


9
.net 프레임 워크의 내부 구성 요소에 의해 예외가 발생하면 도움이되지 않습니다 . 이 모든 문제 자신이 던지는 예외 에는 적용되지 않습니다 . 분명히 어떤 메시지 프로그래머이 선택하는가에 포함 할 .
Nyerguds

1

Undercover1989 답변을 기반으로하지만 매개 변수 및 메시지가 인수 예외와 같은 여러 리소스 문자열로 구성된시기를 고려합니다.

public static string TranslateExceptionMessage(Exception exception, CultureInfo targetCulture)
{
    Assembly a = exception.GetType().Assembly;
    ResourceManager rm = new ResourceManager(a.GetName().Name, a);
    ResourceSet rsOriginal = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true);
    ResourceSet rsTranslated = rm.GetResourceSet(targetCulture, true, true);

    var result = exception.Message;

    foreach (DictionaryEntry item in rsOriginal)
    {
        if (!(item.Value is string message))
            continue;

        string translated = rsTranslated.GetString(item.Key.ToString(), false);

        if (!message.Contains("{"))
        {
            result = result.Replace(message, translated);
        }
        else
        {
            var pattern = $"{Regex.Escape(message)}";
            pattern = Regex.Replace(pattern, @"\\{([0-9]+)\}", "(?<group$1>.*)");

            var regex = new Regex(pattern);

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

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

    return result;
}

1

나는 같은 상황을 겪었고 여기와 다른 곳에서 찾은 모든 대답은 도움이되지 않거나 만족스럽지 못했습니다.

Thread.CurrentUICulture그물 예외의 언어를 변경하지만,하지의 경우와 Win32Exception윈도우 UI 자체의 언어로 윈도우 리소스를 사용한다. 따라서 Win32Exception영어 FormatMessage()Win32Exception을 얻는 방법에 설명 된대로 사용하지 않아도 독일어 대신 영어로 메시지를 인쇄 하지 못했습니다
.

따라서 다른 언어에 대한 대부분의 기존 예외 메시지를 외부 파일에 저장하는 자체 솔루션을 만들었습니다. 원하는 언어로 매우 정확한 메시지를받지는 못하지만 해당 언어로 된 메시지는 현재받는 것보다 훨씬 많습니다 (이해할 수없는 언어로 된 메시지).

이 클래스의 정적 함수는 다른 언어를 사용하는 Windows 설치에서 실행될 수 있습니다 CreateMessages(). 문화권 별 텍스트를 작성
SaveMessagesToXML()하면 언어가 작성되거나로드 될 때마다 많은 XML 파일에이를 저장하고
LoadMessagesFromXML()언어 별 메시지가있는 모든 XML 파일을로드합니다.

다른 언어로 다른 Windows 설치에서 XML 파일을 작성할 때 필요한 모든 언어가 곧 제공 될 것입니다.
여러 MUI 언어 팩이 설치된 경우 1 Windows에서 다른 언어의 텍스트를 만들 수는 있지만 아직 테스트하지는 않았습니다.

VS2008로 테스트되었으며 즉시 사용할 수 있습니다. 의견이나 제안을 환영합니다!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    GetExceptionMessages(dictExceptionMessage);
    GetExceptionMessagesWin32(dictExceptionMessage);

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

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

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

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

    return listoExceptionType;
  }

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

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

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

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

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

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

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

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

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

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

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

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

internal class Program
{
  public static void Main()
  {
    CException.CreateMessages(null);
    CException.SaveMessagesToXML(@"d:\temp\", "emsg");
    CException.LoadMessagesFromXML(@"d:\temp\", "emsg");
  }
}

1
Thread.CurrentUICulture 또한 그 끔찍한 옵션 만드는 UI의 언어를 변경합니다. 전형적인 예는 메시지 상자의 예 / 아니오 / 확인 / 취소 버튼입니다.
Nyerguds

0

영어로 된 예외 메시지

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

그런 다음 현지화 폴더로 이동하여 projectName.xml에 배치하고 추가하십시오.

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

-1

오류 메시지 대신 호출 스택을 기록해야합니다 (IIRC, 간단한 예외. ToString ()이 대신해야합니다). 여기에서 예외가 발생한 위치를 정확하게 판별하고 일반적으로 예외를 추론 할 수 있습니다.


3
우리는 메시지와 스택 추적을 기록하고 있습니다. 그러나 메시지가 분명하면 훨씬 쉽습니다.
Carra

-1

확장 방법을 사용하여 catch 블록에서 예외 메시지를 재정의합니다. Check thrown message는 코드에서 비롯되거나 아래에 언급되지 않은 것입니다.

    public static string GetEnglishMessageAndStackTrace(this Exception ex)
    {
        CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture;
        try
        {

            dynamic exceptionInstanceLocal = System.Activator.CreateInstance(ex.GetType());
            string str;
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

            if (ex.Message == exceptionInstanceLocal.Message)
            {
                dynamic exceptionInstanceENG = System.Activator.CreateInstance(ex.GetType());

                str = exceptionInstanceENG.ToString() + ex.StackTrace;

            }
            else
            {
                str = ex.ToString();
            }
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return str;

        }
        catch (Exception)
        {
            Thread.CurrentThread.CurrentUICulture = currentCulture;

            return ex.ToString();
        }

1
마찬가지로 내가 전에 말했듯이 ... InvalidOperationException. 메시지 자체없이 그것이 무엇을 의미하는지 알아내는 것이 즐겁습니다. 새로운 인스턴스에는 마법이 없습니다.
Nyerguds

-1

로깅을 위해 특정 응용 프로그램은 영어 예외 메시지를 가져와야합니다 (일반 클라이언트의 UICulture에 표시하는 것 외에도).

이를 위해 다음 코드

  1. 현재 UICulture를 변경합니다
  2. "GetType ()"& "Activator.CreateInstance (t)"를 사용하여 throw 된 Exception 객체를 다시 만듭니다.
  3. 새 UICuture에 새 예외 개체의 메시지를 표시합니다.
  4. 마지막으로 현재 UICulture를 이전 UICulture로 다시 변경합니다.

        try
        {
            int[] a = { 3, 6 };
            Console.WriteLine(a[3]); //Throws index out of bounds exception
    
            System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
            throw new System.IO.IOException();
    
        }
        catch (Exception ex)
        {
    
            Console.WriteLine(ex.Message);
            Type t = ex.GetType();
    
            CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
    
            object o = Activator.CreateInstance(t);
    
            System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
    
    
            Console.WriteLine(((Exception)o).Message.ToString());
            Console.ReadLine();
    
         }

1
이것은 새로운 객체의 예외 메시지가 발생 된 예외와 동일하다는 것을 보장하지는 않습니다. 완전히 다를 수 있으며 일반적으로 완전히 다릅니다. 그렇기 때문에 예외 메시지가 필요합니다.
Artemious September
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.