diff --git a/GFramework.Core.Tests/Localization/LocalizationIntegrationTests.cs b/GFramework.Core.Tests/Localization/LocalizationIntegrationTests.cs index 5086867..e37c1be 100644 --- a/GFramework.Core.Tests/Localization/LocalizationIntegrationTests.cs +++ b/GFramework.Core.Tests/Localization/LocalizationIntegrationTests.cs @@ -52,6 +52,7 @@ public class LocalizationIntegrationTests "status.health": "Health: {current}/{max}", "status.gold": "Gold: {gold:compact}", "status.damage": "Damage: {damage:compact:maxDecimals=2}", + "status.unknownCompact": "Gold: {gold:compact:maxDecimalss=2}", "status.invalidCompact": "Gold: {gold:compact:maxDecimals=abc}" } """); @@ -63,6 +64,7 @@ public class LocalizationIntegrationTests "status.health": "生命值: {current}/{max}", "status.gold": "金币: {gold:compact}", "status.damage": "伤害: {damage:compact:maxDecimals=2}", + "status.unknownCompact": "金币: {gold:compact:maxDecimalss=2}", "status.invalidCompact": "金币: {gold:compact:maxDecimals=abc}" } """); @@ -134,6 +136,16 @@ public class LocalizationIntegrationTests Assert.That(damage, Is.EqualTo("Damage: 1.23K")); } + [Test] + public void GetString_WithUnknownCompactFormatterArgs_ShouldIgnoreUnknownOptions() + { + var gold = _manager!.GetString("common", "status.unknownCompact") + .WithVariable("gold", 1_250) + .Format(); + + Assert.That(gold, Is.EqualTo("Gold: 1.3K")); + } + [Test] public void GetString_WithInvalidCompactFormatterArgs_ShouldFallbackToDefaultFormatting() { diff --git a/GFramework.Core/Localization/Formatters/CompactNumberLocalizationFormatter.cs b/GFramework.Core/Localization/Formatters/CompactNumberLocalizationFormatter.cs index 7630842..b37d892 100644 --- a/GFramework.Core/Localization/Formatters/CompactNumberLocalizationFormatter.cs +++ b/GFramework.Core/Localization/Formatters/CompactNumberLocalizationFormatter.cs @@ -146,7 +146,7 @@ public sealed class CompactNumberLocalizationFormatter : ILocalizationFormatter /// 最小小数位数的引用参数 /// 是否去除尾随零的引用参数 /// 是否在阈值以下使用分组的引用参数 - /// 如果键名有效且值成功解析则返回true;如果键名无效或值解析失败则返回false + /// 如果值成功解析或键名未知则返回true;如果键名已知但值解析失败则返回false private static bool TryApplyOption( string key, string value, @@ -161,7 +161,7 @@ public sealed class CompactNumberLocalizationFormatter : ILocalizationFormatter "minDecimals" => int.TryParse(value, out minDecimalPlaces), "trimZeros" => bool.TryParse(value, out trimTrailingZeros), "grouping" => bool.TryParse(value, out useGroupingBelowThreshold), - _ => false + _ => true }; } } \ No newline at end of file diff --git a/GFramework.Core/Utility/Numeric/NumericDisplayFormatter.cs b/GFramework.Core/Utility/Numeric/NumericDisplayFormatter.cs index e9afc87..372d30b 100644 --- a/GFramework.Core/Utility/Numeric/NumericDisplayFormatter.cs +++ b/GFramework.Core/Utility/Numeric/NumericDisplayFormatter.cs @@ -37,7 +37,7 @@ public sealed class NumericDisplayFormatter : INumericDisplayFormatter } var resolvedOptions = NormalizeOptions(options); - var rule = resolvedOptions.Rule ?? _defaultRule; + var rule = ResolveRule(resolvedOptions); if (rule.TryFormat(value, resolvedOptions, out var result)) { @@ -113,6 +113,22 @@ public sealed class NumericDisplayFormatter : INumericDisplayFormatter return resolved; } + private INumericFormatRule ResolveRule(NumericFormatOptions options) + { + ArgumentNullException.ThrowIfNull(options); + + if (options.Rule is not null) + { + return options.Rule; + } + + return options.Style switch + { + NumericDisplayStyle.Compact => _defaultRule, + _ => throw new ArgumentOutOfRangeException(nameof(options), options.Style, "不支持的数值显示风格。") + }; + } + private static string FormatFallback(object value, IFormatProvider? provider) { return value switch diff --git a/GFramework.Core/Utility/Numeric/NumericSuffixFormatRule.cs b/GFramework.Core/Utility/Numeric/NumericSuffixFormatRule.cs index 3e1f706..60a90f3 100644 --- a/GFramework.Core/Utility/Numeric/NumericSuffixFormatRule.cs +++ b/GFramework.Core/Utility/Numeric/NumericSuffixFormatRule.cs @@ -33,7 +33,7 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule } /// - /// 默认国际缩写规则。 + /// 默认国际缩写规则,使用标准的K、M、B、T后缀表示千、百万、十亿、万亿。 /// public static NumericSuffixFormatRule InternationalCompact { get; } = new( "compact", @@ -44,10 +44,19 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule new NumericSuffixThreshold(1_000_000_000_000m, "T") ]); - /// + /// + /// 获取此格式化规则的名称。 + /// public string Name { get; } - /// + /// + /// 尝试将指定的数值按照当前规则进行格式化。 + /// + /// 数值的类型 + /// 要格式化的数值 + /// 格式化选项,包含小数位数、舍入模式等设置 + /// 格式化后的字符串结果 + /// 如果格式化成功则返回true;如果输入无效或格式化失败则返回false public bool TryFormat(T value, NumericFormatOptions options, out string result) { ArgumentNullException.ThrowIfNull(options); @@ -164,15 +173,13 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule } catch (OverflowException) { - try + var doubleValue = (double)value; + if (TryFormatSpecialFloatingPoint(doubleValue, options.FormatProvider, out result)) { - return TryFormatDouble((double)value, options, out result); - } - catch (OverflowException) - { - result = value.ToString(options.FormatProvider ?? CultureInfo.CurrentCulture); return true; } + + return TryFormatDouble(doubleValue, options, out result); } }