Skip to content

Commit 6933239

Browse files
AlexAlves87AlexAlves87claudeshanselmanCopilot
authored
fix: use invariant culture in numeric display formatting (#158)
* fix: use invariant culture in token and cost display formatting FormatLargeNumber and CostUsd were using the current thread culture, producing "2,5M" or "$0,25" on non-English locales instead of the expected "2.5M" / "$0.25". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: add regression for invariant culture numeric formatting Covers non-English culture formatting so token and cost display stays as 2.5M / .25 rather than locale-specific 2,5M / ,25. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: AlexAlves87 <alexalves87@github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Scott Hanselman <scott@hanselman.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bd0a7b0 commit 6933239

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

src/OpenClaw.Shared/Models.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Globalization;
2+
13
namespace OpenClaw.Shared;
24

35
public enum ConnectionStatus
@@ -295,7 +297,7 @@ public string DisplayText
295297
if (TotalTokens > 0)
296298
parts.Add($"Tokens: {ModelFormatting.FormatLargeNumber(TotalTokens)}");
297299
if (CostUsd > 0)
298-
parts.Add($"${CostUsd:F2}");
300+
parts.Add("$" + CostUsd.ToString("F2", CultureInfo.InvariantCulture));
299301
if (RequestCount > 0)
300302
parts.Add($"{RequestCount} requests");
301303
if (!string.IsNullOrEmpty(Model))
@@ -455,8 +457,8 @@ internal static class ModelFormatting
455457
/// </summary>
456458
internal static string FormatLargeNumber(long n)
457459
{
458-
if (n >= 1_000_000) return $"{n / 1_000_000.0:F1}M";
459-
if (n >= 1_000) return $"{n / 1_000.0:F1}K";
460+
if (n >= 1_000_000) return (n / 1_000_000.0).ToString("F1", CultureInfo.InvariantCulture) + "M";
461+
if (n >= 1_000) return (n / 1_000.0).ToString("F1", CultureInfo.InvariantCulture) + "K";
460462
return n.ToString();
461463
}
462464
}

tests/OpenClaw.Shared.Tests/ModelsTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using Xunit;
23
using OpenClaw.Shared;
34

@@ -541,6 +542,37 @@ public void DisplayText_CombinesAllFields_WhenAllPresent()
541542
Assert.Contains("25 requests", display);
542543
Assert.Contains("gpt-4", display);
543544
}
545+
546+
[Fact]
547+
public void DisplayText_UsesInvariantCulture_ForTokenAndCostFormatting()
548+
{
549+
var originalCulture = CultureInfo.CurrentCulture;
550+
var originalUiCulture = CultureInfo.CurrentUICulture;
551+
552+
try
553+
{
554+
CultureInfo.CurrentCulture = new CultureInfo("fr-FR");
555+
CultureInfo.CurrentUICulture = new CultureInfo("fr-FR");
556+
557+
var usage = new GatewayUsageInfo
558+
{
559+
TotalTokens = 2_500_000,
560+
CostUsd = 0.25
561+
};
562+
563+
var display = usage.DisplayText;
564+
565+
Assert.Contains("2.5M", display);
566+
Assert.Contains("$0.25", display);
567+
Assert.DoesNotContain("2,5M", display);
568+
Assert.DoesNotContain("$0,25", display);
569+
}
570+
finally
571+
{
572+
CultureInfo.CurrentCulture = originalCulture;
573+
CultureInfo.CurrentUICulture = originalUiCulture;
574+
}
575+
}
544576
}
545577

546578
public class GatewayNodeInfoTests

0 commit comments

Comments
 (0)