Tin nhắn ngoại lệ bằng tiếng Anh?


298

Chúng tôi đang ghi lại bất kỳ trường hợp ngoại lệ nào xảy ra trong hệ thống của chúng tôi bằng cách viết Exception.Message vào một tệp. Tuy nhiên, chúng được viết trong văn hóa của khách hàng. Và lỗi tiếng Thổ Nhĩ Kỳ không có ý nghĩa nhiều với tôi.

Vậy làm thế nào chúng ta có thể đăng nhập bất kỳ thông báo lỗi bằng tiếng Anh mà không thay đổi văn hóa người dùng?


8
Tại sao bạn không thể swith như thế này: CultureInfo oldCARM = Thread.CảnThread.CiverseCARM; Thread.CienThread.CiverseCARM = CultureInfo.CreateSpecificCARM ("en"); // ném ngoại lệ mới vào đây => Văn hóa bằng tiếng Anh Thread.CảnThread.CiverseCARM = oldCARM;
CheGueVerra

93
Tôi biết không có nhà phát triển, điều đó rất vui cho các tin nhắn ngoại lệ không phải tiếng Anh: S ..
Zéiksz

3
@ Zéiksz Nhìn xa hơn các quốc gia nói tiếng Anh và bạn sẽ tìm thấy nhiều người trong số họ: D. Vấn đề không phải là văn bản không phải tiếng Anh, vấn đề là ngôn ngữ mà bạn không thể hiểu. Tin nhắn bằng ngôn ngữ mẹ đẻ của bạn (giả sử dịch đúng) là hoàn toàn tốt.
Alejandro

31
@Alejandro Phải dịch một tin nhắn ngoại lệ từ một ngôn ngữ bản địa sang tiếng Anh để google, đó là một nỗi đau thậm chí còn lớn hơn ở mông. imho.
Antoine Meltzheim 18/1/17

18
Kẻ ngốc nào ở Microsoft đã có ý tưởng dịch các thông báo lỗi chỉ dành cho nhà phát triển. Ngay cả các thuật ngữ được sử dụng trong ngôn ngữ lập trình như khóa trong từ điển cũng được dịch. (Không tìm thấy khóa trong Từ điển trở thành Sleutel trong niet gevonden in de bibliotheek ở Hà Lan). Tôi không muốn thay đổi ngôn ngữ hệ điều hành cho việc này ...
Roel

Câu trả lời:


66

Vấn đề này có thể được làm việc một phần xung quanh. Mã ngoại lệ khung tải các thông báo lỗi từ tài nguyên của nó, dựa trên ngôn ngữ luồng hiện tại. Trong trường hợp có một số ngoại lệ, điều này xảy ra tại thời điểm thuộc tính Message được truy cập.

Đối với những trường hợp ngoại lệ đó, bạn có thể nhận được phiên bản tiếng Anh đầy đủ của tin nhắn bằng cách chuyển nhanh ngôn ngữ luồng sang en-US trong khi ghi nhật ký (lưu địa điểm người dùng ban đầu trước đó và khôi phục ngay sau đó).

Làm điều này trên một luồng riêng biệt thậm chí còn tốt hơn: điều này đảm bảo sẽ không có bất kỳ tác dụng phụ nào. Ví dụ:

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

Trường hợp lớp ExceptionLogger trông giống như:

class ExceptionLogger
{
  Exception _ex;

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

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

Tuy nhiên, như Joe chỉ ra một cách chính xác trong một nhận xét về sửa đổi trước đó của câu trả lời này, một số tin nhắn đã được tải (một phần) từ các tài nguyên ngôn ngữ tại thời điểm ngoại lệ được đưa ra.

Ví dụ, điều này áp dụng cho tham số 'không thể là null' của thông báo được tạo khi ném ngoại lệ ArgumentNullException ("foo"). Trong những trường hợp đó, thông báo vẫn sẽ xuất hiện (một phần) cục bộ, ngay cả khi sử dụng đoạn mã trên.

Khác với việc sử dụng các bản hack không thực tế, chẳng hạn như chạy tất cả mã không phải UI của bạn trên một luồng với ngôn ngữ en-US để bắt đầu, dường như bạn không thể làm gì nhiều về điều đó: mã ngoại lệ .NET Framework không có các cơ sở để ghi đè miền địa phương thông báo lỗi.


10
Ví dụ của bạn hoạt động cho FileNotFoundException, vì tài nguyên thông báo được truy xuất khi thuộc tính Message được truy cập, không phải khi ném ngoại lệ. Nhưng điều này không đúng với tất cả các trường hợp ngoại lệ (ví dụ: thử ném ArgumentNullException mới ("paramName"))
Joe

3
Tôi bị bối rối. Tôi đã thử làm theo câu trả lời của bạn và để kiểm tra nó Tôi muốn ngoại lệ của mình bằng tiếng Pháp, vì vậy tôi đã làm t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");ngoại lệ, kết quả là bằng tiếng Anh ...
VitalyB

7
@VitalyB Các văn bản ngoại lệ được bản địa hóa là một phần của gói ngôn ngữ .NET framework. Vì vậy, nếu bạn chưa cài đặt gói ngôn ngữ tiếng Pháp, bạn sẽ không nhận được các văn bản dịch.
Daniel Rose

7
Ít nhất với .NET 4.5, tất cả các ngoại lệ đều được khởi tạo Environment.GetResourceString("...")để giải pháp của bạn không hoạt động nữa. Điều tốt nhất là ném ngoại lệ tùy chỉnh với văn bản tin nhắn (tiếng Anh) của riêng bạn và sử dụng thuộc tính InnerException để giữ cái cũ.
webber2k6

1
Sự phản chiếu để có được các loại tên ngoại lệ có thể trở nên tiện dụng.
Guillermo Prandi

67

Bạn có thể tìm kiếm thông báo ngoại lệ gốc tại unlocalize.com


5
Đã thử tìm kiếm một số tin nhắn ngoại lệ của Trung Quốc, luôn luôn nói với tôi No records found.
Tyler Long

1
Lựa chọn tồi. Khi tôi gửi ngoại lệ của mình tới Google Analytics (hoặc dịch vụ đám mây khác), tôi sẽ có các nhóm ngoại lệ khác nhau cho cùng một ngoại lệ, nhưng các ngôn ngữ khác nhau. Và tôi sẽ không thể sắp xếp theo số lượng của từng ngoại lệ, vì nó không phản ánh số lượng thực (100 bằng tiếng Anh, 77 bằng tiếng Trung, 80 bằng tiếng Hàn ... vv)
Artemious

Tôi nhớ đã tìm thấy trang web tuyệt đẹp này nhiều lần khi tôi đơn giản chuyển các tin nhắn ngoại lệ được bản địa hóa vào Google, bây giờ nó không còn khả dụng nữa.
Martin Braun

40

Một điểm gây tranh cãi có lẽ, nhưng thay vì đặt văn hóa en-US, bạn có thể đặt nó thành Invariant. Trong Invariantvăn hóa, các thông báo lỗi bằng tiếng Anh.

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

Nó có lợi thế là không nhìn thiên vị, đặc biệt là đối với các địa phương nói tiếng Anh không phải là người Mỹ. (aka tránh nhận xét snide từ đồng nghiệp)


1
Chúng ta nên viết những dòng này trong dự án ASP.NET của chúng ta ở đâu? Cảm ơn.
jason

2
Tôi sẽ đề xuất ở trên cùng, trong Application_Start. Điều đó sẽ làm cho toàn bộ dự án chạy bằng tiếng Anh. Nếu nó chỉ dành cho các thông báo lỗi mà bạn muốn, bạn có thể tạo một hàm bìa và gọi nó trong mỗi thông báo catch.
MPelletier

5
Điều này cũng không làm cho các nút hộp thư tiêu chuẩn bằng tiếng Anh, mặc dù? Đó có thể không phải là hành vi mong muốn.
Nyerguds

12

Đây là giải pháp không yêu cầu bất kỳ mã hóa nào và hoạt động ngay cả đối với các văn bản ngoại lệ được tải quá sớm để chúng tôi có thể thay đổi bằng mã (ví dụ: các mã trong mscorlib).

Nó có thể không phải lúc nào cũng có thể áp dụng trong mọi trường hợp (tùy thuộc vào thiết lập của bạn vì bạn cần có thể tạo tệp .config sang một tệp .exe chính) nhưng điều đó hiệu quả với tôi. Vì vậy, chỉ cần tạo một app.configdev, (hoặc a [myapp].exe.confighoặc web.configtrong sản xuất) có chứa các dòng sau chẳng hạn:

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

Điều này làm là nói với khung để chuyển hướng các ràng buộc lắp ráp cho mscorlibtài nguyên và System.Xmltài nguyên của các phiên bản từ 1 đến 999, bằng tiếng Pháp (văn hóa được đặt thành "fr ") cho một hội đồng mà ... không tồn tại (tùy ý phiên bản 999).

Vì vậy, khi CLR sẽ tìm kiếm tài nguyên tiếng Pháp cho hai hội đồng này (mscorlib và System.xml), nó sẽ không tìm thấy chúng và chuyển sang tiếng Anh một cách duyên dáng. Tùy thuộc vào ngữ cảnh và các thử nghiệm của bạn, bạn có thể muốn thêm các cụm khác vào các chuyển hướng này (các cụm chứa các tài nguyên cục bộ).

Tất nhiên tôi không nghĩ rằng điều này được Microsoft hỗ trợ, vì vậy hãy tự chịu rủi ro khi sử dụng. Chà, trong trường hợp bạn phát hiện ra một vấn đề, bạn có thể xóa cấu hình này và kiểm tra xem nó không liên quan.


1
Hoạt động khi cần đầu ra tiếng Anh từ các công cụ chạy thử.
smg

Đã thử điều này, nhưng nó không làm việc cho tôi. Có các tệp tài nguyên khác trong .net không? Tôi có thể tìm thấy chúng ở đâu?
BluE

1
Xem trong c: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319. Mỗi ngôn ngữ có một thư mục 2 chữ cái đó. Hãy nhớ thay thế "fr" trong câu trả lời ở trên bằng ngôn ngữ thực tế đang được sử dụng. "không" đối với
tiếng Na Uy

Để tạo một danh sách ĐẦY ĐỦ, hãy xem trong thư mục đó. Nó có khoảng 120 tệp tài nguyên. Thêm từng người trong số họ vào cấu hình. Đây dường như là giải pháp duy nhất cho Windows 10 và mới hơn bây giờ, vì không có cách nào để gỡ cài đặt gói ngôn ngữ .Net trong các cửa sổ mới hơn nữa (một phần của HĐH). Bây giờ nó thậm chí còn được đặt trong GAC, vì vậy việc loại bỏ các thư mục ngôn ngữ đó dường như không hoạt động.
Wolf5

10

Windows cần phải có ngôn ngữ UI bạn muốn sử dụng được cài đặt. Nó không, nó không có cách nào kỳ diệu biết thông điệp được dịch là gì.

Trong một cửa sổ en-US 7 tuyệt đỉnh, với pt-PT được cài đặt, đoạn mã sau:

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;

Tạo tin nhắn trong pt-PT, en-US và en-US. Vì không có tệp văn hóa Pháp nào được cài đặt, nên nó mặc định là ngôn ngữ mặc định (đã cài đặt?) Của Windows.


Điều đó đã giải quyết vấn đề. UI Ba Lan trong tình huống của tôi, đã cài đặt các gói ngôn ngữ MUI ~ 260MB, sử dụng chương trình Vistalizator.
Krzysztof Szynter

5

Tôi biết đây là một chủ đề cũ, nhưng tôi nghĩ giải pháp của tôi có thể khá phù hợp với bất kỳ ai tình cờ tìm thấy nó trong một tìm kiếm trên web:

Trong trình ghi nhật ký ngoại lệ, bạn có thể đăng nhập ex.GetType.ToString, sẽ lưu tên của lớp ngoại lệ. Tôi hy vọng rằng tên của một lớp phải độc lập với ngôn ngữ và do đó sẽ luôn được trình bày bằng tiếng Anh (ví dụ: "System.FileNotFoundException"), mặc dù hiện tại tôi không có quyền truy cập vào hệ thống ngoại ngữ để kiểm tra ý tưởng.

Nếu bạn thực sự muốn văn bản thông báo lỗi, bạn có thể tạo một từ điển của tất cả các tên lớp ngoại lệ có thể và các tin nhắn tương đương của chúng bằng bất kỳ ngôn ngữ nào bạn thích, nhưng đối với tiếng Anh tôi nghĩ rằng tên lớp là hoàn toàn phù hợp.


5
Không hoạt động. Tôi có một InvalidOperationException, ném bởi System.Xml.XmlWellFormedWriter. Bạn thử đoán xem lỗi cụ thể đã xảy ra mà không đọc tin nhắn. Có thể là một ngàn điều khác nhau.
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;

Nếu không có CÔNG VIỆC.

Tks :)


bạn đã quên mất;
KansaiRobot

4

Cài đặt Thread.CurrentThread.CurrentUICulturesẽ được sử dụng để bản địa hóa các ngoại lệ. Nếu bạn cần hai loại ngoại lệ (một cho người dùng, một cho bạn), bạn có thể sử dụng chức năng sau để dịch thông báo ngoại lệ. Đó là tìm kiếm trong tài nguyên Thư viện .NET cho văn bản gốc để lấy khóa tài nguyên và sau đó trả về giá trị đã dịch. Nhưng có một điểm yếu tôi chưa tìm thấy giải pháp tốt: Tin nhắn, chứa {0} trong tài nguyên sẽ không được tìm thấy. Nếu ai có giải pháp tốt tôi sẽ rất biết ơn.

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

Điều đó sẽ không hoạt động nếu ngoại lệ chứa tham số được định dạng.
Nick Berardi

Đúng, như tôi đã nói: "Nhưng có một điểm yếu tôi chưa tìm được giải pháp tốt: Tin nhắn, có chứa {0} trong tài nguyên sẽ không được tìm thấy. Nếu có ai có giải pháp tốt tôi sẽ rất biết ơn."
Vortex852456

3

.NET framework có hai phần:

  1. Bản thân .NET framework
  2. Gói ngôn ngữ .NET framework

Tất cả các văn bản (ví dụ: tin nhắn ngoại lệ, nhãn nút trên MessageBox, v.v.) đều bằng tiếng Anh trong chính khung .NET. Các gói ngôn ngữ có các văn bản địa phương.

Tùy thuộc vào tình huống chính xác của bạn, một giải pháp sẽ là gỡ cài đặt các gói ngôn ngữ (nghĩa là bảo khách hàng làm như vậy). Trong trường hợp đó, các văn bản ngoại lệ sẽ bằng tiếng Anh. Tuy nhiên, xin lưu ý rằng tất cả các văn bản được cung cấp khung khác cũng sẽ bằng tiếng Anh (ví dụ: nhãn nút trên MessageBox, các phím tắt cho ApplicationCommands).


Cảm ơn!! Tôi thấy thật trớ trêu khi hộp thoại gỡ cài đặt bằng ngôn ngữ của gói gỡ cài đặt chứ không phải ngôn ngữ địa phương. Lưu ý bên lề: Các gói ngôn ngữ dường như trở lại sau mỗi vài tháng. Tôi đã không tìm ra lý do tại sao nhưng tôi đoán một bản cập nhật / nâng cấp
Choco Smith

@ChocoSmith Với mỗi bản cập nhật .NET Framework qua Windows Update, gói ngôn ngữ được cài đặt lại.
Daniel Rose

5
Yêu cầu khách hàng gỡ cài đặt gói ngôn ngữ cho ngôn ngữ của họ không phải là giải pháp khả thi.
Nyerguds

2

Tôi sẽ tưởng tượng một trong những cách tiếp cận sau:

  1. Các trường hợp ngoại lệ chỉ được bạn đọc, tức là chúng không phải là một tính năng máy khách, vì vậy bạn có thể sử dụng các chuỗi không được bản địa hóa cứng sẽ không thay đổi khi bạn chạy ở chế độ Thổ Nhĩ Kỳ.

  2. Bao gồm một mã lỗi, ví dụ 0x00000001với mỗi lỗi để bạn có thể dễ dàng tìm kiếm nó trong một bảng tiếng Anh.


9
Điều đó sẽ không giúp ích nhiều khi chúng là ngoại lệ được ném bởi các thành phần bên trong của khung .net . Toàn bộ vấn đề này không áp dụng cho các trường hợp ngoại lệ bạn tự ném; rõ ràng là lập trình viên chọn thông điệp gì để bao gồm với những người đó .
Nyerguds

1

Dựa trên câu trả lời Undercover1989, nhưng sẽ đưa vào các tham số tài khoản và khi các thông báo được tạo thành từ một số chuỗi tài nguyên (như ngoại lệ đối số).

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

Tôi đã có tình huống tương tự, và tất cả các câu trả lời mà tôi tìm thấy ở đây và những nơi khác không giúp ích hoặc không thỏa mãn:

Các Thread.CurrentUICulturethay đổi ngôn ngữ của các ngoại lệ .net, nhưng nó không cho Win32Exception, trong đó sử dụng tài nguyên Windows bằng ngôn ngữ của Windows UI riêng của mình. Vì vậy, tôi không bao giờ quản lý để in các tin nhắn Win32Exceptionbằng tiếng Anh thay vì tiếng Đức, thậm chí không bằng cách sử dụng FormatMessage()như được mô tả trong
Làm thế nào để có được Win32Exception bằng tiếng Anh?

Do đó, tôi đã tạo ra giải pháp của riêng mình, nơi lưu trữ phần lớn các thông báo ngoại lệ hiện có cho các ngôn ngữ khác nhau trong các tệp bên ngoài. Bạn sẽ không nhận được thông điệp chính xác bằng ngôn ngữ bạn muốn, nhưng bạn sẽ nhận được một tin nhắn bằng ngôn ngữ đó, nhiều hơn so với hiện tại bạn nhận được (đó là một tin nhắn bằng ngôn ngữ mà bạn có thể không hiểu).

Các hàm tĩnh của lớp này có thể được thực thi trên các bản cài đặt Windows với các ngôn ngữ khác nhau: CreateMessages()tạo các văn bản dành riêng cho văn hóa
SaveMessagesToXML()lưu chúng vào nhiều tệp XML khi ngôn ngữ được tạo hoặc tải
LoadMessagesFromXML()tải tất cả các tệp XML bằng các thông điệp ngôn ngữ cụ thể

Khi tạo các tệp XML trên các bản cài đặt Windows khác nhau bằng các ngôn ngữ khác nhau, bạn sẽ sớm có tất cả các ngôn ngữ bạn cần.
Có thể bạn có thể tạo văn bản cho các ngôn ngữ khác nhau trên 1 Windows khi bạn cài đặt nhiều gói ngôn ngữ MUI, nhưng tôi chưa thử nghiệm điều đó.

Đã thử nghiệm với VS2008, sẵn sàng để sử dụng. Nhận xét và đề nghị được chào đón!

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
Việc này Thread.CurrentUICulture cũng thay đổi ngôn ngữ của UI, khiến nó trở thành một lựa chọn tồi tệ. Một ví dụ kinh điển là các nút Có / Không / OK / Hủy trên hộp thông báo.
Nyerguds

0

Tin nhắn ngoại lệ bằng tiếng Anh

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

sau đó vào thư mục Bản địa hóa và đặt nó trong projectName.xml và thêm

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

-1

Bạn nên ghi lại ngăn xếp cuộc gọi thay vì chỉ thông báo lỗi (IIRC, ngoại lệ đơn giản.ToString () sẽ làm điều đó cho bạn). Từ đó, bạn có thể xác định chính xác ngoại lệ bắt nguồn từ đâu và thường suy ra đó là ngoại lệ nào.


3
Chúng tôi đang đăng nhập tin nhắn và stacktrace. Nhưng nó dễ dàng hơn nhiều nếu thông điệp rõ ràng.
Carra

-1

Ghi đè thông báo ngoại lệ trong khối bắt bằng phương pháp tiện ích mở rộng, Kiểm tra thư bị ném có phải từ mã hay không như được đề cập dưới đây.

    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
Như tôi đã nói trước ... InvalidOperationException. Hãy vui vẻ tìm hiểu điều đó có nghĩa là gì mà không có tin nhắn. Một trường hợp mới sẽ không có điều kỳ diệu có nó.
Nyerguds

-1

Đối với mục đích Ghi nhật ký, một số ứng dụng có thể cần tìm nạp thông báo ngoại lệ bằng tiếng Anh (bên cạnh việc hiển thị nó trong UICARM của khách hàng thông thường).

Với mục đích đó, đoạn mã sau

  1. thay đổi UICARM hiện tại
  2. tạo lại đối tượng Exception đã ném bằng cách sử dụng "GetType ()" & "Activator.CreateInstance (t)"
  3. hiển thị Thông báo của đối tượng Ngoại lệ mới trong UICuture mới
  4. và cuối cùng thay đổi UICARM hiện tại trở lại UICARM trước đó.

        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
điều này không đảm bảo rằng thông báo ngoại lệ của đối tượng mới giống với thông báo ngoại lệ bị ném. Nó có thể hoàn toàn khác nhau, và thường thì nó hoàn toàn khác nhau. Đó là lý do tại sao chúng ta cần thông điệp ngoại lệ.
Khủng khiếp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.