mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
fix(localization): 修复紧凑数字格式化器处理未知选项的行为
- 修改 CompactNumberLocalizationFormatter 中 TryApplyOption 方法的返回逻辑 - 当键名未知时现在返回 true 而不是 false,允许忽略未知选项 - 更新 NumericDisplayFormatter 使用 ResolveRule 方法来确定格式化规则 - 添加对不同数值显示风格的支持和验证 - 在集成测试中添加未知选项的测试用例以验证正确行为 - 改进 NumericSuffixFormatRule 的文档注释以更清楚地描述功能
This commit is contained in:
parent
5996ecf5f3
commit
fca3808657
@ -52,6 +52,7 @@ public class LocalizationIntegrationTests
|
|||||||
"status.health": "Health: {current}/{max}",
|
"status.health": "Health: {current}/{max}",
|
||||||
"status.gold": "Gold: {gold:compact}",
|
"status.gold": "Gold: {gold:compact}",
|
||||||
"status.damage": "Damage: {damage:compact:maxDecimals=2}",
|
"status.damage": "Damage: {damage:compact:maxDecimals=2}",
|
||||||
|
"status.unknownCompact": "Gold: {gold:compact:maxDecimalss=2}",
|
||||||
"status.invalidCompact": "Gold: {gold:compact:maxDecimals=abc}"
|
"status.invalidCompact": "Gold: {gold:compact:maxDecimals=abc}"
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
@ -63,6 +64,7 @@ public class LocalizationIntegrationTests
|
|||||||
"status.health": "生命值: {current}/{max}",
|
"status.health": "生命值: {current}/{max}",
|
||||||
"status.gold": "金币: {gold:compact}",
|
"status.gold": "金币: {gold:compact}",
|
||||||
"status.damage": "伤害: {damage:compact:maxDecimals=2}",
|
"status.damage": "伤害: {damage:compact:maxDecimals=2}",
|
||||||
|
"status.unknownCompact": "金币: {gold:compact:maxDecimalss=2}",
|
||||||
"status.invalidCompact": "金币: {gold:compact:maxDecimals=abc}"
|
"status.invalidCompact": "金币: {gold:compact:maxDecimals=abc}"
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
@ -134,6 +136,16 @@ public class LocalizationIntegrationTests
|
|||||||
Assert.That(damage, Is.EqualTo("Damage: 1.23K"));
|
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]
|
[Test]
|
||||||
public void GetString_WithInvalidCompactFormatterArgs_ShouldFallbackToDefaultFormatting()
|
public void GetString_WithInvalidCompactFormatterArgs_ShouldFallbackToDefaultFormatting()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -146,7 +146,7 @@ public sealed class CompactNumberLocalizationFormatter : ILocalizationFormatter
|
|||||||
/// <param name="minDecimalPlaces">最小小数位数的引用参数</param>
|
/// <param name="minDecimalPlaces">最小小数位数的引用参数</param>
|
||||||
/// <param name="trimTrailingZeros">是否去除尾随零的引用参数</param>
|
/// <param name="trimTrailingZeros">是否去除尾随零的引用参数</param>
|
||||||
/// <param name="useGroupingBelowThreshold">是否在阈值以下使用分组的引用参数</param>
|
/// <param name="useGroupingBelowThreshold">是否在阈值以下使用分组的引用参数</param>
|
||||||
/// <returns>如果键名有效且值成功解析则返回true;如果键名无效或值解析失败则返回false</returns>
|
/// <returns>如果值成功解析或键名未知则返回true;如果键名已知但值解析失败则返回false</returns>
|
||||||
private static bool TryApplyOption(
|
private static bool TryApplyOption(
|
||||||
string key,
|
string key,
|
||||||
string value,
|
string value,
|
||||||
@ -161,7 +161,7 @@ public sealed class CompactNumberLocalizationFormatter : ILocalizationFormatter
|
|||||||
"minDecimals" => int.TryParse(value, out minDecimalPlaces),
|
"minDecimals" => int.TryParse(value, out minDecimalPlaces),
|
||||||
"trimZeros" => bool.TryParse(value, out trimTrailingZeros),
|
"trimZeros" => bool.TryParse(value, out trimTrailingZeros),
|
||||||
"grouping" => bool.TryParse(value, out useGroupingBelowThreshold),
|
"grouping" => bool.TryParse(value, out useGroupingBelowThreshold),
|
||||||
_ => false
|
_ => true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ public sealed class NumericDisplayFormatter : INumericDisplayFormatter
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resolvedOptions = NormalizeOptions(options);
|
var resolvedOptions = NormalizeOptions(options);
|
||||||
var rule = resolvedOptions.Rule ?? _defaultRule;
|
var rule = ResolveRule(resolvedOptions);
|
||||||
|
|
||||||
if (rule.TryFormat(value, resolvedOptions, out var result))
|
if (rule.TryFormat(value, resolvedOptions, out var result))
|
||||||
{
|
{
|
||||||
@ -113,6 +113,22 @@ public sealed class NumericDisplayFormatter : INumericDisplayFormatter
|
|||||||
return resolved;
|
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)
|
private static string FormatFallback(object value, IFormatProvider? provider)
|
||||||
{
|
{
|
||||||
return value switch
|
return value switch
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认国际缩写规则。
|
/// 默认国际缩写规则,使用标准的K、M、B、T后缀表示千、百万、十亿、万亿。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static NumericSuffixFormatRule InternationalCompact { get; } = new(
|
public static NumericSuffixFormatRule InternationalCompact { get; } = new(
|
||||||
"compact",
|
"compact",
|
||||||
@ -44,10 +44,19 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule
|
|||||||
new NumericSuffixThreshold(1_000_000_000_000m, "T")
|
new NumericSuffixThreshold(1_000_000_000_000m, "T")
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
|
/// 获取此格式化规则的名称。
|
||||||
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <summary>
|
||||||
|
/// 尝试将指定的数值按照当前规则进行格式化。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">数值的类型</typeparam>
|
||||||
|
/// <param name="value">要格式化的数值</param>
|
||||||
|
/// <param name="options">格式化选项,包含小数位数、舍入模式等设置</param>
|
||||||
|
/// <param name="result">格式化后的字符串结果</param>
|
||||||
|
/// <returns>如果格式化成功则返回true;如果输入无效或格式化失败则返回false</returns>
|
||||||
public bool TryFormat<T>(T value, NumericFormatOptions options, out string result)
|
public bool TryFormat<T>(T value, NumericFormatOptions options, out string result)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(options);
|
ArgumentNullException.ThrowIfNull(options);
|
||||||
@ -164,15 +173,13 @@ public sealed class NumericSuffixFormatRule : INumericFormatRule
|
|||||||
}
|
}
|
||||||
catch (OverflowException)
|
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TryFormatDouble(doubleValue, options, out result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user