Pesan pengecualian dalam bahasa Inggris?


298

Kami mencatat setiap pengecualian yang terjadi di sistem kami dengan menulis Exception.Message ke file. Namun, mereka ditulis dalam budaya klien. Dan kesalahan Turki tidak berarti banyak bagi saya.

Jadi bagaimana kita bisa mencatat pesan kesalahan dalam bahasa Inggris tanpa mengubah budaya pengguna?


8
Mengapa Anda tidak dapat swith seperti ini: CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en"); // lempar Pengecualian baru di sini => Budaya dalam bahasa Inggris Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra

93
Saya tahu tidak ada pengembang, yang senang untuk pesan pengecualian non-Inggris: S ..
Zéiksz

3
@ Zéiksz Lihatlah melampaui negara-negara berbahasa Inggris dan Anda akan menemukan banyak di antaranya: D. Masalahnya bukan teks non-Inggris, masalah adalah bahasa yang tidak bisa Anda mengerti. Pesan dalam bahasa ibu Anda (dengan asumsi terjemahan yang tepat) baik-baik saja.
Alejandro

31
@Alejandro Harus menerjemahkan pesan pengecualian dari satu bahasa asli ke bahasa Inggris agar dapat google, itu adalah rasa sakit yang lebih besar di pantat. Menurut opini saya.
Antoine Meltzheim

18
Idiot di Microsoft mana yang memiliki ide untuk menerjemahkan pesan kesalahan yang hanya untuk pengembang. Bahkan istilah yang digunakan dalam bahasa pemrograman seperti kunci dalam kamus diterjemahkan. (Kunci tidak ditemukan dalam Kamus menjadi Sleutel di niet gevonden in de bibliotheek di Belanda). Saya tidak ingin mengubah bahasa OS untuk ini ...
Roel

Jawaban:


66

Masalah ini dapat diselesaikan sebagian. Kode pengecualian Kerangka memuat pesan kesalahan dari sumber dayanya, berdasarkan lokal utas saat ini. Dalam kasus beberapa pengecualian, ini terjadi pada saat properti Pesan diakses.

Untuk pengecualian tersebut, Anda dapat memperoleh versi bahasa Inggris AS lengkap dari pesan tersebut dengan secara singkat mengalihkan lokal utas ke en-AS saat masuk (menyimpan lokal pengguna asli sebelumnya dan mengembalikannya segera setelah itu).

Melakukan ini pada utas terpisah bahkan lebih baik: ini memastikan tidak akan ada efek samping. Sebagai contoh:

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

Di mana kelas ExceptionLogger terlihat seperti:

class ExceptionLogger
{
  Exception _ex;

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

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

Namun, seperti Joe ditunjukkan dengan benar dalam komentar tentang revisi sebelumnya atas balasan ini, beberapa pesan sudah (sebagian) dimuat dari sumber daya bahasa pada saat pengecualian dilemparkan.

Ini berlaku untuk bagian 'parameter tidak boleh nol' dari pesan yang dihasilkan ketika pengecualian ArgumentNullException ("foo") dilemparkan, misalnya. Dalam kasus tersebut, pesan akan tetap muncul (sebagian) terlokalisasi, bahkan ketika menggunakan kode di atas.

Selain dengan menggunakan peretasan yang tidak praktis, seperti menjalankan semua kode non-UI Anda pada utas dengan lokal en-AS untuk memulai, tampaknya tidak banyak yang dapat Anda lakukan tentang hal itu: kode pengecualian .NET Framework tidak memiliki fasilitas untuk mengganti lokal pesan kesalahan.


10
Contoh Anda berfungsi untuk FileNotFoundException, karena sumber daya pesan diambil saat properti Pesan diakses, bukan ketika pengecualian dilemparkan. Tetapi ini tidak benar untuk semua pengecualian (mis. Coba lempar ArgumentNullException baru ("paramName"))
Joe

3
Saya bingung. Saya sudah mencoba mengikuti jawaban Anda dan untuk mengujinya saya ingin pengecualian saya dalam bahasa Prancis, jadi saya lakukan t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");dan t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");belum, pengecualian yang dihasilkan adalah dalam bahasa Inggris ...
VitalyB

7
@VitalyB Teks pengecualian yang dilokalkan adalah bagian dari paket bahasa .NET framework. Jadi jika Anda tidak menginstal paket bahasa Prancis, Anda tidak akan mendapatkan teks yang diterjemahkan.
Daniel Rose

7
Setidaknya dengan .NET 4.5, semua pengecualian dipakai dengan Environment.GetResourceString("...")demikian solusi Anda tidak berfungsi lagi. Hal terbaik adalah melempar pengecualian khusus dengan teks pesan (bahasa Inggris) Anda sendiri dan menggunakan properti InnerException untuk mempertahankan yang lama.
webber2k6

1
Refleksi untuk mendapatkan nama jenis pengecualian bisa menjadi berguna.
Guillermo Prandi

67

Anda dapat mencari pesan pengecualian asli di unlocalize.com


5
Mencoba mencari beberapa pesan pengecualian Cina, selalu memberi tahu saya No records found.
Tyler Long

1
Pilihan yang buruk. Ketika saya mengirim pengecualian saya ke Google Analytics (atau layanan cloud lainnya), saya akan memiliki grup pengecualian yang berbeda untuk pengecualian yang sama, tetapi bahasa yang berbeda. Dan saya tidak akan dapat mengurutkan berdasarkan hitungan setiap pengecualian, karena tidak mencerminkan hitungan sebenarnya (100 dalam bahasa Inggris, 77 dalam bahasa Cina, 80 dalam bahasa Korea ... dll)
Artemious

Saya ingat untuk menemukan situs web yang indah ini berkali-kali ketika saya hanya membuang pesan pengecualian lokal ke Google, sekarang tidak lagi tersedia.
Martin Braun

40

Poin yang kontroversial mungkin, tetapi alih-alih mengatur budaya en-US, Anda dapat mengaturnya Invariant. Dalam Invariantbudaya, pesan kesalahan dalam bahasa Inggris.

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

Ini memiliki keuntungan karena tidak terlihat bias, terutama untuk lokal berbahasa Inggris non-Amerika. (alias menghindari komentar sinis dari rekan kerja)


1
Di mana kita harus menulis baris-baris ini dalam proyek ASP.NET kita? Terima kasih.
jason

2
Saya akan menyarankan di bagian atas, di Application_Start. Itu akan membuat seluruh proyek berjalan dalam bahasa Inggris. Jika hanya untuk pesan kesalahan yang Anda inginkan, Anda dapat membuat fungsi sampul dan memanggilnya masing-masing catch.
MPelletier

5
Bukankah ini juga akan membuat tombol kotak pesan standar dalam bahasa Inggris? Itu mungkin bukan perilaku yang diinginkan.
Nyerguds

12

Berikut adalah solusi yang tidak memerlukan pengkodean apa pun dan berfungsi bahkan untuk teks-teks pengecualian yang dimuat terlalu dini untuk dapat diubah oleh kode (misalnya, yang ada di mscorlib).

Ini mungkin tidak selalu berlaku dalam setiap kasus (itu tergantung pada pengaturan Anda karena Anda harus dapat membuat file .config selain file .exe utama) tetapi itu berfungsi untuk saya. Jadi, buat saja app.configdi dev, (atau a [myapp].exe.configatau web.configdi produksi) yang berisi baris-baris berikut misalnya:

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

Apa yang dilakukan adalah memberi tahu kerangka kerja untuk mengarahkan ikatan rakitan untuk mscorlibsumber daya dan System.Xmlsumber daya, untuk versi antara 1 dan 999, dalam bahasa Prancis (budaya diatur ke " fr") ke rakitan yang ... tidak ada (sewenang-wenang versi 999).

Jadi ketika CLR akan mencari sumber daya Perancis untuk dua majelis ini (mscorlib dan System.xml), itu tidak akan menemukan mereka dan mundur ke bahasa Inggris dengan anggun. Bergantung pada konteks dan pengujian Anda, Anda mungkin ingin menambahkan majelis lain ke arahan ulang ini (majelis yang berisi sumber daya lokal).

Tentu saja saya tidak berpikir ini didukung oleh Microsoft, jadi gunakan dengan risiko Anda sendiri. Nah, jika Anda mendeteksi masalah, Anda bisa menghapus konfigurasi ini dan periksa apakah itu tidak terkait.


1
Bekerja ketika membutuhkan keluaran bahasa Inggris dari alat test-runner.
smg

Sudah mencoba ini, tetapi tidak berhasil untuk saya. Apakah ada file sumber daya lain di .net? Di mana saya dapat menemukannya?
BluE

1
Lihat di c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Setiap bahasa memiliki folder 2 huruf di sana. Ingatlah untuk mengganti "fr" dalam jawaban di atas dengan bahasa aktual yang sedang digunakan. "tidak" untuk norwegian, "da" untuk Denmark, "sv" untuk swedia dll
Wolf5

Untuk membuat daftar LENGKAP, lihat di folder itu. Sekitar 120 file sumber daya. Tambahkan masing-masing ke dalam konfigurasi. Ini tampaknya menjadi satu-satunya solusi untuk Windows 10 dan yang lebih baru untuk saat ini, karena tidak ada lagi cara untuk menghapus paket bahasa .Net di windows yang lebih baru (bagian dari OS). Bahkan ditempatkan di GAC sekarang, jadi menghapus folder bahasa itu sepertinya tidak berfungsi.
Wolf5

10

Windows perlu menginstal bahasa UI yang ingin Anda gunakan. Jika tidak, ia tidak memiliki cara ajaib untuk mengetahui apa pesan yang diterjemahkan.

Di Windows 7 ultimate en-US, dengan pt-PT diinstal, kode berikut:

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;

Menghasilkan pesan di pt-PT, en-US dan en-US. Karena tidak ada file kultur Prancis yang diinstal, default ke bahasa windows default (diinstal?).


Itu memecahkan masalah. UI Polandia dalam situasi saya, menginstal paket bahasa MUI ~ 260MB, menggunakan program Vistalizator.
Krzysztof Szynter

5

Saya tahu ini adalah topik lama, tetapi saya pikir solusi saya mungkin cukup relevan bagi siapa saja yang tersandung di dalamnya dalam pencarian web:

Dalam pengecualian logger Anda bisa mencatat ex.GetType.ToString, yang akan menyimpan nama kelas pengecualian. Saya berharap bahwa nama kelas harus independen dari bahasa dan karena itu akan selalu diwakili dalam bahasa Inggris (misalnya "System.FileNotFoundException"), meskipun saat ini saya tidak memiliki akses ke sistem bahasa asing untuk menguji ide.

Jika Anda benar-benar menginginkan teks pesan kesalahan juga, Anda dapat membuat kamus dari semua kemungkinan nama kelas pengecualian dan pesan ekuivalennya dalam bahasa apa pun yang Anda inginkan, tetapi untuk bahasa Inggris saya rasa nama kelasnya cukup memadai.


5
Tidak bekerja Saya mendapat InvalidOperationException, dilemparkan oleh System.Xml.XmlWellFormedWriter. Anda mencoba menebak kesalahan spesifik apa yang terjadi tanpa membaca pesan. Bisa jadi seribu hal berbeda.
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;

Tanpa WORKAROUNDS.

Tks :)


Anda lupa;
KansaiRobot

4

Pengaturan Thread.CurrentThread.CurrentUICultureakan digunakan untuk melokalkan pengecualian. Jika Anda memerlukan dua jenis pengecualian (satu untuk pengguna, satu untuk Anda), Anda dapat menggunakan fungsi berikut untuk menerjemahkan pesan pengecualian. Sedang mencari di sumber daya .NET-Libraries untuk teks asli untuk mendapatkan kunci-sumber daya dan kemudian mengembalikan nilai yang diterjemahkan. Tapi ada satu kelemahan saya belum menemukan solusi yang baik: Pesan, yang mengandung {0} dalam sumber daya tidak akan ditemukan. Jika ada yang punya solusi yang baik saya akan berterima kasih.

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

Itu tidak akan berfungsi jika pengecualian berisi parameter yang diformat.
Nick Berardi

Yap, seperti yang saya katakan: "Tapi ada satu kelemahan saya belum menemukan solusi yang baik: Pesan, yang mengandung {0} dalam sumber daya tidak akan ditemukan. Jika ada yang punya solusi yang baik saya akan berterima kasih."
Vortex852456

3

Kerangka NET. Ada dua bagian:

  1. Framework .NET itu sendiri
  2. Paket bahasa .NET frameworks

Semua teks (mis. Pesan pengecualian, label tombol pada MessageBox, dll.) Dalam bahasa Inggris di .NET framework itu sendiri. Paket bahasa memiliki teks-teks yang dilokalkan.

Bergantung pada situasi Anda yang sebenarnya, solusinya adalah menghapus instalasi paket bahasa (mis. Beritahu klien untuk melakukannya). Dalam hal itu, teks pengecualian akan dalam bahasa Inggris. Namun perlu dicatat, bahwa semua teks yang disediakan kerangka kerja lainnya juga akan berbahasa Inggris (mis. Label tombol pada MessageBox, pintasan keyboard untuk ApplicationCommands).


Terima kasih!! Saya merasa ironis bahwa dialog uninstall adalah dalam bahasa paket uninstall dan bukan bahasa lokal. Catatan: Paket bahasa tampaknya kembali setiap beberapa bulan. saya belum mengetahui alasannya tetapi saya menduga pembaruan / peningkatan
Choco Smith

@ChocoSmith Dengan setiap pembaruan .NET Framework melalui Pembaruan Windows, paket bahasa diinstal lagi.
Daniel Rose

5
Meminta pelanggan untuk menghapus paket bahasa untuk bahasa mereka sendiri bukanlah solusi yang layak.
Nyerguds

2

Saya akan membayangkan salah satu dari pendekatan ini:

  1. Pengecualian hanya pernah dibaca oleh Anda, yaitu mereka bukan fitur klien, sehingga Anda dapat menggunakan string non-lokal bawaan yang tidak akan berubah ketika Anda menjalankan dalam mode Turki.

  2. Sertakan kode kesalahan misalnya 0x00000001dengan setiap kesalahan sehingga Anda dapat dengan mudah mencarinya di tabel bahasa Inggris.


9
Itu tidak akan banyak membantu ketika mereka merupakan pengecualian yang dilemparkan oleh komponen internal kerangka .net . Seluruh masalah ini tidak berlaku untuk pengecualian yang Anda lemparkan sendiri; jelas programmer memilih pesan apa yang akan dimasukkan dengan mereka .
Nyerguds

1

Berdasarkan jawaban Undercover1989, tetapi memperhitungkan parameter akun dan ketika pesan terdiri dari beberapa rangkaian sumber daya (seperti pengecualian argumen).

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

Saya memiliki situasi yang sama, dan semua jawaban yang saya temukan di sini dan di tempat lain tidak membantu atau tidak memuaskan:

The Thread.CurrentUICulturemengubah bahasa pengecualian Net, tetapi tidak untuk Win32Exception, yang menggunakan sumber daya Windows dalam bahasa Windows UI itu sendiri. Jadi saya tidak pernah berhasil mencetak pesan Win32Exceptiondalam bahasa Inggris, bukan bahasa Jerman, bahkan dengan menggunakan FormatMessage()seperti yang dijelaskan dalam
Cara mendapatkan Win32Exception dalam Bahasa Inggris?

Karena itu saya membuat solusi saya sendiri, yang menyimpan sebagian besar pesan pengecualian yang ada untuk berbagai bahasa dalam file eksternal. Anda tidak akan mendapatkan pesan yang sangat tepat dalam bahasa yang Anda inginkan, tetapi Anda akan mendapatkan pesan dalam bahasa itu, yang jauh lebih banyak daripada yang Anda dapatkan saat ini (yang merupakan pesan dalam bahasa yang Anda mungkin tidak mengerti).

Fungsi statis dari kelas ini dapat dijalankan pada instalasi Windows dengan bahasa yang berbeda: CreateMessages()membuat teks khusus budaya
SaveMessagesToXML()menyimpannya sebagai file XML sebanyak bahasa dibuat atau dimuat
LoadMessagesFromXML() memuat semua file XML dengan pesan khusus bahasa

Saat membuat file XML pada instalasi Windows yang berbeda dengan bahasa yang berbeda, Anda akan segera memiliki semua bahasa yang Anda butuhkan.
Mungkin Anda dapat membuat teks untuk berbagai bahasa pada 1 Windows ketika Anda memiliki beberapa paket bahasa MUI yang diinstal, tetapi saya belum mengujinya.

Diuji dengan VS2008, siap digunakan. Komentar dan saran dipersilahkan!

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
Itu Thread.CurrentUICulture juga mengubah bahasa UI, menjadikannya pilihan yang mengerikan. Contoh klasik adalah tombol Ya / Tidak / OK / Batalkan pada kotak pesan.
Nyerguds

0

Pesan pengecualian dalam bahasa Inggris

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

lalu buka folder Pelokalan dan letakkan di projectName.xml dan tambahkan

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

-1

Anda harus mencatat tumpukan panggilan alih-alih hanya pesan kesalahan (IIRC, pengecualian sederhana.ToString () harus melakukan itu untuk Anda). Dari sana, Anda dapat menentukan dengan tepat dari mana pengecualian itu berasal, dan biasanya menyimpulkan dari mana pengecualian itu.


3
Kami sedang mencatat pesan dan stacktrace. Tapi itu jauh lebih mudah jika pesannya jelas.
Carra

-1

Mengganti pesan pengecualian di blok tangkap menggunakan metode ekstensi, Periksa pesan yang dilemparkan adalah dari kode atau tidak seperti yang disebutkan di bawah ini.

    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
Seperti yang saya katakan sebelumnya ... InvalidOperationException. Bersenang-senang mencari tahu apa artinya tanpa pesan itu sendiri. Sebuah instance baru tidak akan secara ajaib memilikinya.
Nyerguds

-1

Untuk tujuan Pencatatan, aplikasi tertentu mungkin perlu mengambil pesan pengecualian Bahasa Inggris (selain menampilkannya dalam UICulture klien biasa).

Untuk itu, kode berikut

  1. mengubah UICulture saat ini
  2. membuat ulang objek Pengecualian yang dilemparkan menggunakan "GetType ()" & "Activator.CreateInstance (t)"
  3. menampilkan Pesan objek Pengecualian baru di UICuture baru
  4. dan akhirnya mengubah UICulture saat ini kembali ke UICulture sebelumnya.

        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
ini tidak menjamin bahwa pesan pengecualian objek baru adalah sama dengan pengecualian yang dilemparkan. Mungkin sangat berbeda, dan biasanya sama sekali berbeda. Itu sebabnya kami membutuhkan pesan pengecualian.
Artemious
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.