Повідомлення про виключення англійською мовою?


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. Проблема - це не англійський текст, проблема - це мова, яку ви не можете зрозуміти. Повідомлення рідною мовою (якщо припустити належний переклад) ідеально чудові.
Алехандро

31
@Alejandro Перевести повідомлення про виняток з однієї рідної мови на англійську, щоб перейти в Google, це ще більший біль у дупі. імхо.
Антуан Мельцгейм

18
Який ідіот в Microsoft мав ідею перекладати повідомлення про помилки, які призначені лише розробникам. Навіть терміни, які використовуються в мові програмування, як ключ у словнику, перекладаються. (Ключ не знайдений у словнику стає Sleutel in niet gevonden in de bibliotheek голландською мовою). Я не хочу змінювати мову ОС для цього ...
Roel

Відповіді:


66

Це питання можна частково вирішити. Код виключення Framework завантажує повідомлення про помилки зі своїх ресурсів на основі поточного локального потоку. У випадку деяких винятків це відбувається в момент доступу до властивості повідомлення.

За винятками, ви можете отримати повну англійську версію повідомлення в США, коротко переключивши локальний ланцюжок потоку на 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
  }
}

Однак, як правильно вказує Джо в коментарі до попередньої редакції цієї відповіді, деякі повідомлення вже (частково) завантажуються з мовних ресурсів під час скидання винятку.

Це стосується частини параметра "не може бути нульовим" повідомлення, що генерується, наприклад, якщо викинуто виняток ArgumentNullException ("foo"). У цих випадках повідомлення все ще буде (частково) локалізовано навіть при використанні вищевказаного коду.

Окрім використання непрактичних хак, таких як запуск усього коду, що не належить до UI, на потоці з локальною мовою en-US, для цього, здається, не так вже й багато: для цього виключення .NET Framework код не має засоби для переопределення локального повідомлення про помилку.


10
Ваш приклад працює для 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 Framework. Тож якщо у вас не встановлений пакет французької мови, ви не отримаєте перекладених текстів.
Даніель Роуз

7
Принаймні, з .NET 4.5 всі винятки створюються миттєво, Environment.GetResourceString("...")тому ваше рішення більше не працює. Найкраще - кинути спеціальний виняток із власним (англійською) текстом повідомлення та використовувати властивість InnerException, щоб зберегти старий.
webber2k6

1
Відображення для отримання назв типів виключень може стати в нагоді.
Гільєрмо Пранді

67

Ви можете шукати оригінальне повідомлення про виключення на сайті unlocalize.com


5
Я завжди намагався шукати деякі повідомлення про виключення в Китаї No records found.
Тайлер Лонг

1
Поганий вибір. Коли я надсилаю свої винятки до Google Analytics (або іншої хмарної служби), у мене будуть різні групи винятків для одного винятку, але на різних мовах. І я не зможу сортувати за підрахунками кожного винятку, оскільки це не відображає реального підрахунку (100 англійською, 77 китайською, 80 корейською ... тощо)
Artemious

Я пам'ятаю, що часто знаходив цей прекрасний веб-сайт, коли я просто перекидав локалізовані повідомлення про виключення в Google, тепер це більше не доступно.
Мартін Браун

40

Можливо, спірне питання, але замість того, щоб встановити культуру en-US, ви можете встановити її Invariant. У Invariantкультурі повідомлення про помилки є англійською мовою.

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

Він має перевагу в тому, що він не виглядає упередженим, особливо це стосується неамериканських англомовних мов. (він також уникає зауважень колег)


1
Де ми повинні написати ці рядки в нашому проекті ASP.NET? Дякую.
Jason

2
Я збираюся запропонувати вгорі, в Application_Start. Це змусить весь проект працювати англійською мовою. Якщо вам потрібні лише повідомлення про помилки, ви можете зробити функцію обкладинки і викликати її в кожному catch.
MPelletier

5
Невже це також не робить стандартні кнопки вікна повідомлень англійською мовою? Це може бути не бажана поведінка.
Nyerguds

12

Ось рішення, яке не вимагає кодування і працює навіть для текстів винятків, які завантажуються занадто рано, щоб ми могли змінити код (наприклад, ті, що в mscorlib).

Це може бути не завжди застосовано у кожному випадку (це залежить від вашої установки, оскільки вам потрібно мати змогу створити .config файл, крім основного .exe-файлу), але це працює для мене. Отже, просто створіть програму app.configinv, (або a [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ресурсів і System.Xmlресурсів, для версій між 1 та 999 французькою мовою (культура встановлена ​​на " fr") на збірку, яка ... не існує (довільна версія 999).

Отже, коли CLR буде шукати французькі ресурси для цих двох збірок (mscorlib та System.xml), він не знайде їх і виграшно вийде на англійську. Залежно від вашого контексту та тестувань, ви можете додати до цих перенаправлень інші збірки (збірки, що містять локалізовані ресурси).

Звичайно, я не думаю, що це підтримує Microsoft, тому використовуйте на свій страх і ризик. Ну, якщо ви виявите проблему, ви можете просто видалити цю конфігурацію і перевірити, що вона не пов'язана.


1
Працює, коли потрібен вихід з англійської мови з інструментів для тестування.
smg

Спробував це, але мені це не вийшло. Чи є інші файли ресурсів у .net? Де їх можна знайти?
BluE

1
Подивіться в c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. У кожній мові є папка з двома літерами. Не забудьте замінити "fr" у відповіді вище на фактичну мову, якою ви користуєтесь. "ні" для норвезької, "da" для датської, "sv" для шведської тощо
Wolf5

Щоб створити ПОВНИЙ список, погляньте в цю папку. Це близько 120 файлів ресурсів. Додайте кожен з них у конфігурацію. Це здається єдиним рішенням для Windows 10 та новіших на сьогоднішній день, оскільки вже немає можливості видалити мовні пакети .Net у новіших вікнах (його частина ОС). Її навіть розміщують у GAC зараз, тому видалення цих мовних папок, здається, не працює.
Вовк5

10

У Windows має бути встановлена ​​мова інтерфейсу, яку ви хочете використовувати. Це не так, він не має можливості магічно пізнати, що таке перекладене повідомлення.

У програмі 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 (за замовчуванням?).


Ось і вирішена проблема. Польський інтерфейс у моїй ситуації встановив мовні пакети MUI ~ 260 Мб за допомогою програми Vistalizator.
Кшиштоф Шінтер

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-Бібліотеки вихідний текст, щоб отримати ключ-ресурс, а потім повернути переведене значення. Але є одна слабкість, для якої я ще не знайшов хорошого рішення: Повідомлення, що містять {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)
}

Це не працює, якщо виняток містить форматований параметр.
Нік Берарді

Так, як я вже говорив: "Але є одна слабкість, яку я ще не знайшов."
Vortex852456

3

Рамка .NET складається з двох частин:

  1. Сама структура .NET
  2. Мовні пакети .NET Framework

Усі тексти (наприклад, повідомлення про винятки, мітки кнопок на MessageBox тощо) є англійською мовою в самому рамках .NET. Мовні пакети мають локалізовані тексти.

Залежно від вашої конкретної ситуації, рішенням буде видалити мовні пакети (тобто сказати клієнту зробити це). У такому випадку тексти виключень будуть англійською мовою. Однак зауважте, що весь текст, що надається рамками, також буде англійською мовою (наприклад, мітки кнопок на MessageBox, комбінації клавіш для ApplicationCommands).


Дякую!! Я вважаю іронічним те, що діалог для видалення є мовою пакета для видалення, а не локальною мовою. Побічна примітка: Мовляв, мовні пакети повертаються кожні кілька місяців. я не працював чому, але я здогадуюсь оновлення / оновлення
Choco Smith

@ChocoSmith З кожним оновленням .NET Framework через оновлення Windows мовний пакет знову встановлюється.
Даніель Роуз

5
Попросити клієнтів видалити мовні пакети для їх власної мови не є прийнятним рішенням.
Nyerguds

2

Я б уявив один із таких підходів:

  1. Винятки ви читаєте лише коли-небудь, тобто вони не є функцією клієнта, тому ви можете використовувати жорсткі провідні не локалізовані рядки, які не змінюватимуться під час запуску в турецькому режимі.

  2. Додайте код помилки, наприклад, 0x00000001з кожною помилкою, щоб ви могли легко її переглянути в англійській таблиці.


9
Це не дуже допоможе, якщо вони є винятками, викинутими внутрішніми компонентами .net Framework . Вся ця проблема не стосується винятків, які ви кидаєте на себе; очевидно, програміст вибирає, яке повідомлення включити до них .
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Змінює мову винятків .net, але це не для Win32Exception, яка використовує ресурси Windows , на мові самого інтерфейсу Windows. Тож мені ніколи не вдалося надрукувати повідомлення Win32Exceptionанглійською мовою замість німецької, навіть не використовуючи, FormatMessage()як описано в розділі
Як отримати Win32Exception англійською мовою?

Тому я створив власне рішення, яке зберігає більшість існуючих повідомлень про виключення для різних мов у зовнішніх файлах. Ви не отримаєте дуже точне повідомлення бажаною мовою, але ви отримаєте повідомлення на тій мові, що набагато більше, ніж ви отримуєте в даний час (це повідомлення мовою, яку ви, ймовірно, не розумієте).

Статичні функції цього класу можна виконувати в установках Windows з різними мовами: CreateMessages()створює тексти, що стосуються культури,
SaveMessagesToXML()зберігає їх у стільки файлів XML, скільки мов створено або завантажено
LoadMessagesFromXML()завантажує всі файли XML з повідомленнями, що стосуються мови.

Створюючи XML-файли на різних установках Windows з різними мовами, незабаром з’являться всі потрібні вам мови.
Можливо, ви можете створити тексти для різних мов на 1 Windows, коли у вас встановлено кілька мовних пакетів MUI, але я ще цього не перевіряв.

Випробуваний на 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 Також змінює мову інтерфейсу, що робить його жахливий варіант. Класичний приклад - кнопки Так / Ні / ОК / Скасувати в полі повідомлень.
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
Ми реєструємо повідомлення та стек-трек. Але набагато простіше, якщо повідомлення зрозуміло.
Карра

-1

Перевизначення повідомлення про виключення в блоці вилову за допомогою методу розширення, Перевірте викинуте повідомлення з коду чи не, як зазначено нижче.

    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)"
  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
це не гарантує, що повідомлення про виключення нового об’єкта є таким, як і викинуте виняток. Це може бути зовсім інше, і зазвичай воно зовсім інше. Ось чому нам потрібне повідомлення про виключення.
Артемічний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.