web-dev-qa-db-ja.com

英語の例外メッセージ?

Exception.Messageをファイルに書き込むことにより、システムで発生した例外を記録しています。しかし、それらはクライアントの文化で書かれています。そして、トルコ語の間違いは私にとってあまり意味がありません。

それでは、ユーザーカルチャを変更せずに、どのようにエラーメッセージを英語で記録できますか?

280
Carra

この問題は部分的に回避できます。フレームワークの例外コードは、現在のスレッドロケールに基づいて、リソースからエラーメッセージを読み込みます。一部の例外の場合、これは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")例外がスローされたときに生成されるメッセージの「パラメーターをnullにすることはできません」部分に適用されます。これらの場合、上記のコードを使用しても、メッセージは(部分的に)ローカライズされたままになります。

最初にen-USロケールでスレッドですべての非UIコードを実行するなど、非実用的なハッキングを使用する以外に、それに対してできることはあまりないようです。NETFramework例外コードにはエラーメッセージのロケールを上書きする機能。

63
mdb

nlocalize.com で元の例外メッセージを検索できます

65
user461128

議論の余地があるかもしれませんが、カルチャをen-USに設定する代わりに、Invariantに設定できます。 Invariantカルチャでは、エラーメッセージは英語です。

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

特に非アメリカ英語圏のロケールでは、偏見がないという利点があります。 (別名、同僚からのスナイド発言を避ける)

39
MPelletier

これは、コーディングを必要とせず、コードで変更することができないほど早く読み込まれた例外のテキスト(たとえば、mscorlibのテキスト)でも機能するソリューションです。

すべての場合に常に適用できるとは限りません(メインの.exeファイルとは別に.configファイルを作成できるようにする必要があるため、セットアップに依存します)が、それは私にとってはうまくいきます。したがって、たとえば、次の行を含むapp.configをdevで作成します(または実動では[myapp].exe.configまたはweb.configを作成します。

<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"に設定されている)で、バージョンが1〜999の場合、frのリソースとSystem.Xmlのリソースのアセンブリバインディングをリダイレクトするようフレームワークに指示します。 ...存在しないアセンブリ(任意のバージョン999)。

そのため、CLRがこれら2つのアセンブリ(mscorlibとSystem.xml)のフランス語リソースを検索するとき、それらは見つからず、英語に適切にフォールバックします。コンテキストとテストに応じて、これらのリダイレクト(ローカライズされたリソースを含むアセンブリ)に他のアセンブリを追加することもできます。

もちろん、これはマイクロソフトによってサポートされているとは思わないので、自己責任で使用してください。問題を検出した場合は、この構成を削除して、関係がないことを確認するだけです。

10
Simon Mourier

Windowsには、使用するUI言語がインストールされている必要があります。それはそうではなく、翻訳されたメッセージが何であるかを魔法のように知る方法はありません。

En-US Windows 7 Ultimateで、pt-PTがインストールされている場合、次のコード:

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のデフォルト(インストール済み?)言語がデフォルトになります。

10
danobrega

私はこれが古いトピックであることを知っていますが、私の解決策はウェブ検索でそれを偶然見つけた人に非常に関連があると思います:

例外ロガーでは、ex.GetType.ToStringをログに記録できます。これにより、例外クラスの名前が保存されます。クラスの名前は言語から独立している必要があるため、常に英語で表されるはずです(たとえば、「System.FileNotFoundException」)。ただし、現時点では、外国語システムにアクセスして、アイデア。

エラーメッセージテキストも本当に必要な場合は、可能なすべての例外クラス名とその同等のメッセージのディクショナリを任意の言語で作成できますが、英語の場合、クラス名は完全に適切だと思います。

4
Barbarian
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 :)

3
Fabio Mastelari

Thread.CurrentThread.CurrentUICultureの設定は、例外のローカライズに使用されます。 2種類の例外(ユーザー用とユーザー用)が必要な場合は、次の関数を使用して例外メッセージを翻訳できます。元のテキストを.NET-Librariesリソースで検索してリソースキーを取得し、翻訳された値を返します。しかし、まだ良い解決策を見つけられなかった弱点が1つあります。リソースに{0}を含むメッセージは見つかりません。誰かが良い解決策を持っているなら、私は感謝するでしょう。

public static string TranslateExceptionMessage(Exception E, CultureInfo targetCulture)
{
    try
    {
        Assembly a = E.GetType().Assembly;
        ResourceManager rm = new ResourceManager(a.GetName().Name, a);
        ResourceSet rsOriginal = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true);
        ResourceSet rsTranslated = rm.GetResourceSet(targetCulture, true, true);
        foreach (DictionaryEntry item in rsOriginal)
            if (item.Value.ToString() == E.Message.ToString())
                return rsTranslated.GetString(item.Key.ToString(), false); // success

    }
    catch { }
    return E.Message; // failed (error or cause it's not intelligent enough to locale '{0}'-patterns
}
3
Undercover1989

.NETフレームワークには2つの部分があります。

  1. .NETフレームワーク自体
  2. .NET Framework言語パック

すべてのテキスト(例外メッセージ、MessageBoxのボタンラベルなど)は、.NETフレームワーク自体では英語です。言語パックにはローカライズされたテキストが含まれています。

正確な状況に応じて、解決策は言語パックをアンインストールすることです(つまり、クライアントにアンインストールするように指示します)。その場合、例外テキストは英語になります。ただし、フレームワークが提供する他のすべてのテキストも英語であることに注意してください(例:MessageBoxのボタンラベル、ApplicationCommandsのキーボードショートカット)。

3
Daniel Rose

これらのアプローチの1つを想像します。

1)例外はユーザーによってのみ読み取られます。つまり、クライアント機能ではないため、トルコ語モードで実行しても変わらない、固定化された非ローカライズ文字列を使用できます。

2)エラーコードを含めますエラーごとに0X00000001を追加すると、英語の表で簡単に調べることができます。

2
morechilli

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
jan

私は同じ状況にあり、ここや他の場所で見つけたすべての答えは役に立たなかったか、満足していませんでした:
英語の例外言語を強制
C#-アプリケーションが別の言語である場合に英語で例外メッセージを取得しますか?
デバッグ中にVisual Studio例外メッセージ言語を英語に変更する方法
例外メッセージの翻訳の処理方法
ローカライズされた.NET例外メッセージを完全に回避する方法

Thread.CurrentUICultureは.net例外の言語を変更しますが、Windows UI自体の言語でWindowsリソースを使用するWin32Exceptionは変更しません。だから、FormatMessage()を使用しても、Win32Exceptionのメッセージをドイツ語ではなく英語で印刷することはできませんでした。
英語で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
Tobias Knauss