From 02a321dfc74add527201f6865d707f65c25dc98e Mon Sep 17 00:00:00 2001 From: tutkus Date: Sat, 30 Apr 2022 20:03:21 +0200 Subject: [PATCH] Added CultureInfo to StringFormatConverter --- .../Converters/StringFormatConverter.cs | 77 ++++++++-- .../Converters/Test_StringFormatConverter.cs | 132 +++++++++++++++--- 2 files changed, 181 insertions(+), 28 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI/Converters/StringFormatConverter.cs b/Microsoft.Toolkit.Uwp.UI/Converters/StringFormatConverter.cs index cb01f422c3f..53dfcf868f2 100644 --- a/Microsoft.Toolkit.Uwp.UI/Converters/StringFormatConverter.cs +++ b/Microsoft.Toolkit.Uwp.UI/Converters/StringFormatConverter.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Globalization; using Windows.UI.Xaml.Data; namespace Microsoft.Toolkit.Uwp.UI.Converters @@ -12,13 +13,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Converters /// public class StringFormatConverter : IValueConverter { + /// + /// Gets or sets the CultureInfo to make converter culture sensitive. The default value is + /// + public CultureInfo CultureInfo { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public StringFormatConverter() + { + CultureInfo = CultureInfo.CurrentCulture; + } + /// /// Return the formatted string version of the source object. /// /// Object to transform to string. /// The type of the target property, as a type reference /// An optional parameter to be used in the string.Format method. - /// The language of the conversion (not used). + /// The language of the conversion. If language is null or empty then will be used. /// Formatted string. public object Convert(object value, Type targetType, object parameter, string language) { @@ -27,20 +41,13 @@ public object Convert(object value, Type targetType, object parameter, string la return null; } - if (parameter == null) + string formatParameter = parameter as string; + if (formatParameter == null) { return value; } - try - { - return string.Format((string)parameter, value); - } - catch - { - } - - return value; + return FormatToString(value, formatParameter, GetCultureInfoOrDefault(language, () => GetDefaultCultureInfo())); } /// @@ -55,5 +62,53 @@ public object ConvertBack(object value, Type targetType, object parameter, strin { throw new NotImplementedException(); } + + private object FormatToString(object value, string parameter, CultureInfo cultureInfo) + { + try + { + return string.Format(cultureInfo, parameter, value); + } + catch + { + return value; + } + } + + private CultureInfo GetCultureInfoOrDefault(string language, Func getDefaultCultureInfo) + { + CultureInfo cultureInfo; + if (!TryGetCultureInfo(language, out cultureInfo)) + { + cultureInfo = getDefaultCultureInfo(); + } + + return cultureInfo; + } + + private bool TryGetCultureInfo(string language, out CultureInfo cultureInfo) + { + cultureInfo = null; + if (string.IsNullOrEmpty(language)) + { + return false; + } + + try + { + cultureInfo = CultureInfo.GetCultureInfo(language); + + return true; + } + catch + { + return false; + } + } + + private CultureInfo GetDefaultCultureInfo() + { + return CultureInfo ?? CultureInfo.InvariantCulture; + } } } \ No newline at end of file diff --git a/UnitTests/UnitTests.UWP/Converters/Test_StringFormatConverter.cs b/UnitTests/UnitTests.UWP/Converters/Test_StringFormatConverter.cs index 8bf74420b30..51d3ece8d80 100644 --- a/UnitTests/UnitTests.UWP/Converters/Test_StringFormatConverter.cs +++ b/UnitTests/UnitTests.UWP/Converters/Test_StringFormatConverter.cs @@ -5,59 +5,157 @@ using Microsoft.Toolkit.Uwp.UI.Converters; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Globalization; namespace UnitTests.Converters { [TestClass] public class Test_StringFormatConverter { - private static readonly object NullString = null; + private const string NullLanguage = null; + + private static readonly CultureInfo ConverterCultureInfo = new CultureInfo("pl-pl"); + private static readonly object NullString = null; private static readonly object NotEmptyString = "Hello, world"; private static readonly DateTime Date = DateTime.Now; + private static readonly decimal Amount = 333.4m; [TestCategory("Converters")] [TestMethod] - public void WhenValueIsNull_ThenReturnNull() + [DataRow(NullLanguage)] + [DataRow("en-us")] + public void WhenValueIsNull_ThenReturnNull(string language) { var converter = new StringFormatConverter(); - var result = converter.Convert(NullString, typeof(string), NullString, "en-us"); + var result = converter.Convert(NullString, typeof(string), NullString, language); Assert.IsNull(result); } [TestCategory("Converters")] [TestMethod] - public void WhenValueExistsAndParameterIsNull_ThenReturnValue() + [DataRow(NullLanguage)] + [DataRow("en-us")] + public void WhenValueExistsAndParameterIsNull_ThenReturnValue(string language) { var converter = new StringFormatConverter(); - var result = converter.Convert(NotEmptyString, typeof(string), NullString, "en-us"); + var result = converter.Convert(NotEmptyString, typeof(string), NullString, language); Assert.AreEqual(NotEmptyString, result); } [TestCategory("Converters")] [TestMethod] - public void WhenParameterIsTimeFormat_ThenReturnValueOfTimeFormat() + [DataRow(NullLanguage)] + [DataRow("en-us")] + public void WhenParameterIsInvalidFormat_ThenReturnValue(string language) { - var converter = new StringFormatConverter(); - var result = converter.Convert(Date, typeof(string), "{0:HH:mm}", "en-us"); - Assert.AreEqual(Date.ToString("HH:mm"), result); + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo + }; + var result = converter.Convert(Date, typeof(string), "{1:}", language); + Assert.AreEqual(Date, result); } [TestCategory("Converters")] [TestMethod] - public void WhenParameterIsInvalidFormat_ThenReturnValue() + [DataRow(NullLanguage)] + [DataRow("en-us")] + public void WhenParameterIsNotAString_ThenReturnValue(string language) { - var converter = new StringFormatConverter(); - var result = converter.Convert(Date, typeof(string), "{1:}", "en-us"); - Assert.AreEqual(Date, result); + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo + }; + var result = converter.Convert(NotEmptyString, typeof(string), 172, language); + Assert.AreEqual(NotEmptyString, result); + } + + [TestCategory("Converters")] + [TestMethod] + [DataRow("{0:ddd d MMM}", "ddd d MMM")] + [DataRow("{0:HH:mm}", "HH:mm")] + [DataRow("{0:hh:mm:ss tt}", "hh:mm:ss tt")] + public void WhenValueIsDateTimeAndLanguageIsUnknownAndCultureInfoIsNotSet_ThenReturnValueOfTimeInInvariantCultureFormat(string converterParameter, string expectedFormat) + { + var converter = new StringFormatConverter() + { + CultureInfo = null + }; + var result = converter.Convert(Date, typeof(string), converterParameter, NullLanguage); + Assert.AreEqual(Date.ToString(expectedFormat, CultureInfo.InvariantCulture), result); } [TestCategory("Converters")] [TestMethod] - public void WhenParameterIsNotAString_ThenReturnValue() + [DataRow("{0:ddd d MMM}", "ddd d MMM")] + [DataRow("{0:HH:mm}", "HH:mm")] + [DataRow("{0:hh:mm:ss tt}", "hh:mm:ss tt")] + public void WhenValueIsDateTimeAndLanguageIsUnknownAndCultureInfoIsSet_ThenReturnValueOfTimeInConverterCultureInfoFormat(string converterParameter, string expectedFormat) { - var converter = new StringFormatConverter(); - var result = converter.Convert(NotEmptyString, typeof(string), 172, "en-us"); - Assert.AreEqual(NotEmptyString, result); + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo + }; + var result = converter.Convert(Date, typeof(string), converterParameter, NullLanguage); + Assert.AreEqual(Date.ToString(expectedFormat, ConverterCultureInfo), result); + } + + [TestCategory("Converters")] + [TestMethod] + [DataRow("en-us", "{0:ddd d MMM}", "ddd d MMM")] + [DataRow("en-us", "{0:HH:mm}", "HH:mm")] + [DataRow("en-us", "{0:hh:mm:ss tt}", "hh:mm:ss tt")] + public void WhenValueIsDateTimeAndLanguageIsWellKnownAndCultureInfoIsSet_ThenReturnValueOfTimeInLanguageCultureFormat(string language, string converterParameter, string expectedFormat) + { + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo, + }; + var result = converter.Convert(Date, typeof(string), converterParameter, language); + Assert.AreEqual(Date.ToString(expectedFormat, CultureInfo.GetCultureInfo(language)), result); + } + + [TestCategory("Converters")] + [TestMethod] + [DataRow("{0:C2}", "C2")] + [DataRow("{0:E}", "E")] + public void WhenValueIsDecimalAndLanguageIsUnknownAndCultureInfoIsNotSet_ThenReturnValueOfDecimalInInvariantCultureFormat(string converterParameter, string expectedFormat) + { + var converter = new StringFormatConverter() + { + CultureInfo = null + }; + var result = converter.Convert(Amount, typeof(string), converterParameter, NullLanguage); + Assert.AreEqual(Amount.ToString(expectedFormat, CultureInfo.InvariantCulture), result); } + + [TestCategory("Converters")] + [TestMethod] + [DataRow("{0:C2}", "C2")] + [DataRow("{0:E}", "E")] + public void WhenValueIsDecimalAndLanguageIsUnknownAndCultureInfoIsSet_ThenReturnValueOfDecimalInConverterCultureInfoFormat(string converterParameter, string expectedFormat) + { + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo + }; + var result = converter.Convert(Amount, typeof(string), converterParameter, NullLanguage); + Assert.AreEqual(Amount.ToString(expectedFormat, ConverterCultureInfo), result); + } + + [TestCategory("Converters")] + [TestMethod] + [DataRow("en-us", "{0:C2}", "C2")] + [DataRow("en-us", "{0:E}", "E")] + [DataRow("fr-FR", "{0:E}", "E")] + public void WhenValueIsDecimalAndLanguageIsWellKnownAndCultureInfoIsSet_ThenReturnValueOfDecimalInLanguageCultureFormat(string language, string converterParameter, string expectedFormat) + { + var converter = new StringFormatConverter() + { + CultureInfo = ConverterCultureInfo, + }; + var result = converter.Convert(Amount, typeof(string), converterParameter, language); + Assert.AreEqual(Amount.ToString(expectedFormat, CultureInfo.GetCultureInfo(language)), result); + } } } \ No newline at end of file