diff --git a/csharp/Platform.Exceptions.Tests/InternationalizationTests.cs b/csharp/Platform.Exceptions.Tests/InternationalizationTests.cs new file mode 100644 index 0000000..bba09f8 --- /dev/null +++ b/csharp/Platform.Exceptions.Tests/InternationalizationTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Globalization; +using System.Threading; +using Xunit; + +namespace Platform.Exceptions.Tests +{ + /// + /// Tests for internationalization functionality. + /// Тесты для функциональности интернационализации. + /// + public class InternationalizationTests + { + /// + /// Tests that exception messages are localized based on the current culture. + /// Проверяет, что сообщения исключений локализованы в соответствии с текущей культурой. + /// + [Fact] + public void TestArgumentNullExceptionLocalization() + { + // Test English (default) + Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; + var englishException = Assert.Throws(() => + Ensure.Always.ArgumentNotNull(null, "testArg")); + Assert.Contains("Argument testArg is null", englishException.Message); + + // Test Russian + Thread.CurrentThread.CurrentUICulture = new CultureInfo("ru-RU"); + var russianException = Assert.Throws(() => + Ensure.Always.ArgumentNotNull(null, "testArg")); + Assert.Contains("Аргумент testArg равен null", russianException.Message); + } + + /// + /// Tests that argument criteria exception messages are localized. + /// Проверяет, что сообщения исключений критериев аргументов локализованы. + /// + [Fact] + public void TestArgumentCriteriaExceptionLocalization() + { + // Test English (default) + Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; + var englishException = Assert.Throws(() => + Ensure.Always.ArgumentMeetsCriteria("test", x => x.Length > 10, "shortArg")); + Assert.Contains("Argument shortArg does not meet the criteria", englishException.Message); + + // Test Russian + Thread.CurrentThread.CurrentUICulture = new CultureInfo("ru-RU"); + var russianException = Assert.Throws(() => + Ensure.Always.ArgumentMeetsCriteria("test", x => x.Length > 10, "shortArg")); + Assert.Contains("Аргумент shortArg не соответствует критерию", russianException.Message); + } + + /// + /// Tests that exception formatting strings are localized. + /// Проверяет, что строки форматирования исключений локализованы. + /// + [Fact] + public void TestExceptionFormattingLocalization() + { + // Test English (default) + Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; + var innerEx = new InvalidOperationException("Inner"); + var outerEx = new Exception("Outer", innerEx); + var englishFormatted = outerEx.ToStringWithAllInnerExceptions(); + Assert.Contains("Inner exception:", englishFormatted); + + // Test Russian + Thread.CurrentThread.CurrentUICulture = new CultureInfo("ru-RU"); + var russianFormatted = outerEx.ToStringWithAllInnerExceptions(); + Assert.Contains("Внутреннее исключение:", russianFormatted); + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Exceptions/EnsureExtensions.cs b/csharp/Platform.Exceptions/EnsureExtensions.cs index 83501a6..b5403cf 100644 --- a/csharp/Platform.Exceptions/EnsureExtensions.cs +++ b/csharp/Platform.Exceptions/EnsureExtensions.cs @@ -43,7 +43,7 @@ public static void ArgumentNotNull(this EnsureAlwaysExtensionRoot roo /// The argument.Аргумент. /// The argument's name.Имя аргумента. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ArgumentNotNull(this EnsureAlwaysExtensionRoot root, TArgument argument, string argumentName) where TArgument : class => ArgumentNotNull(root, argument, argumentName, $"Argument {argumentName} is null."); + public static void ArgumentNotNull(this EnsureAlwaysExtensionRoot root, TArgument argument, string argumentName) where TArgument : class => ArgumentNotNull(root, argument, argumentName, string.Format(Resources.ArgumentIsNull, argumentName)); /// /// Ensures that argument is not null. This check is performed regardless of the build configuration. @@ -84,7 +84,7 @@ public static void ArgumentMeetsCriteria(this EnsureAlwaysExtensionRo /// A predicate that determines whether the argument meets a criterion.Предикат определяющий, соответствует ли аргумент критерию. /// The argument's name.Имя аргумента. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ArgumentMeetsCriteria(this EnsureAlwaysExtensionRoot root, TArgument argument, Predicate predicate, string argumentName) => ArgumentMeetsCriteria(root, argument, predicate, argumentName, $"Argument {argumentName} does not meet the criteria."); + public static void ArgumentMeetsCriteria(this EnsureAlwaysExtensionRoot root, TArgument argument, Predicate predicate, string argumentName) => ArgumentMeetsCriteria(root, argument, predicate, argumentName, string.Format(Resources.ArgumentDoesNotMeetCriteria, argumentName)); /// /// Ensures that the argument meets the criteria. This check is performed regardless of the build configuration. diff --git a/csharp/Platform.Exceptions/ExceptionExtensions.cs b/csharp/Platform.Exceptions/ExceptionExtensions.cs index 0694252..a8d1044 100644 --- a/csharp/Platform.Exceptions/ExceptionExtensions.cs +++ b/csharp/Platform.Exceptions/ExceptionExtensions.cs @@ -19,7 +19,7 @@ public static class ExceptionExtensions /// Represents a string returned from in the event of an unsuccessful attempt to format an exception. This field is a constant. /// Представляет строку выдаваемую из в случае неудачной попытки форматирования исключения. Это поле является константой. /// - public static readonly string ExceptionStringBuildingFailed = "Unable to format exception."; + public static readonly string ExceptionStringBuildingFailed = Resources.UnableToFormatException; /// /// Ignores the exception, notifying the class about it. @@ -57,7 +57,7 @@ private static void BuildExceptionString(this StringBuilder sb, Exception except if (exception.InnerException != null) { sb.Indent(level); - sb.AppendLine("Inner exception: "); + sb.AppendLine(Resources.InnerException); sb.BuildExceptionString(exception.InnerException, level + 1); } sb.Indent(level); diff --git a/csharp/Platform.Exceptions/Platform.Exceptions.csproj b/csharp/Platform.Exceptions/Platform.Exceptions.csproj index fde4379..2c3b4b7 100644 --- a/csharp/Platform.Exceptions/Platform.Exceptions.csproj +++ b/csharp/Platform.Exceptions/Platform.Exceptions.csproj @@ -4,7 +4,7 @@ LinksPlatform's Platform.Exceptions Class Library Konstantin Diachenko Platform.Exceptions - 0.5.0 + 0.6.0 Konstantin Diachenko net8 Platform.Exceptions @@ -23,7 +23,7 @@ true snupkg latest - Update target framework from net7 to net8. + Added internationalization support for exception messages. Supports English and Russian languages. enable @@ -35,6 +35,22 @@ + + + ResXFileCodeGenerator + Resources.Designer.cs + + + Resources.resx + + + + + True + True + Resources.resx + + diff --git a/csharp/Platform.Exceptions/Resources.Designer.cs b/csharp/Platform.Exceptions/Resources.Designer.cs new file mode 100644 index 0000000..999aad0 --- /dev/null +++ b/csharp/Platform.Exceptions/Resources.Designer.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Globalization; +using System.Resources; +using System.Runtime.CompilerServices; + +namespace Platform.Exceptions +{ + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Platform.Exceptions.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Argument {0} does not meet the criteria.. + /// + internal static string ArgumentDoesNotMeetCriteria + { + get + { + return ResourceManager.GetString("ArgumentDoesNotMeetCriteria", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument {0} is null.. + /// + internal static string ArgumentIsNull + { + get + { + return ResourceManager.GetString("ArgumentIsNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inner exception: . + /// + internal static string InnerException + { + get + { + return ResourceManager.GetString("InnerException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to format exception.. + /// + internal static string UnableToFormatException + { + get + { + return ResourceManager.GetString("UnableToFormatException", resourceCulture); + } + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Exceptions/Resources.resx b/csharp/Platform.Exceptions/Resources.resx new file mode 100644 index 0000000..4ef3730 --- /dev/null +++ b/csharp/Platform.Exceptions/Resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Argument {0} is null. + Message for ArgumentNullException when argument is null + + + Argument {0} does not meet the criteria. + Message for ArgumentException when argument doesn't meet criteria + + + Unable to format exception. + Message when exception formatting fails + + + Inner exception: + Label for inner exception in formatted exception strings + + \ No newline at end of file diff --git a/csharp/Platform.Exceptions/Resources.ru.resx b/csharp/Platform.Exceptions/Resources.ru.resx new file mode 100644 index 0000000..fc3b15b --- /dev/null +++ b/csharp/Platform.Exceptions/Resources.ru.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Аргумент {0} равен null. + Сообщение для ArgumentNullException когда аргумент равен null + + + Аргумент {0} не соответствует критерию. + Сообщение для ArgumentException когда аргумент не соответствует критерию + + + Невозможно отформатировать исключение. + Сообщение когда форматирование исключения не удалось + + + Внутреннее исключение: + Метка для внутреннего исключения в форматированных строках исключений + + \ No newline at end of file