chore: i18n time utils and use TFunction type (#6507) (#6539)

## Summary

Addresses two review comments from #6507:

- **`timeUtils.ts`** — route relative time strings (`just now`, `Xm
ago`, `Xh ago`, `Xd ago`) through i18n by accepting a `TFunction`
parameter and using new `time.relative.*` keys in `en-GB`
- **`ChatPanel.tsx`** — replace `ReturnType<typeof useTranslation>["t"]`
with `TFunction` from `i18next`

## Test plan
- [x] `task frontend:check` passes (695 tests)
This commit is contained in:
EthanHealy01
2026-06-05 09:45:27 +00:00
committed by GitHub
parent c93776e297
commit a61fe012d7
3 changed files with 16 additions and 7 deletions
@@ -8151,6 +8151,12 @@ label = "Select a TSA server"
[timestampPdf.steps]
settings = "Settings"
[time.relative]
daysAgo = "{{count}}d ago"
hoursAgo = "{{count}}h ago"
justNow = "just now"
minutesAgo = "{{count}}m ago"
[tool]
endpointUnavailable = "This tool is unavailable on your server."
endpointUnavailableClickable = "Not available in this mode. Click to sign in."
+7 -5
View File
@@ -1,10 +1,12 @@
export function formatRelativeTime(timestamp: number): string {
import { TFunction } from "i18next";
export function formatRelativeTime(timestamp: number, t: TFunction): string {
const diff = Date.now() - timestamp;
const mins = Math.floor(diff / 60_000);
if (mins < 1) return "just now";
if (mins < 60) return `${mins}m ago`;
if (mins < 1) return t("time.relative.justNow");
if (mins < 60) return t("time.relative.minutesAgo", { count: mins });
const hours = Math.floor(mins / 60);
if (hours < 24) return `${hours}h ago`;
if (hours < 24) return t("time.relative.hoursAgo", { count: hours });
const days = Math.floor(hours / 24);
return `${days}d ago`;
return t("time.relative.daysAgo", { count: days });
}
@@ -6,6 +6,7 @@ import {
type KeyboardEvent,
} from "react";
import { renderMarkdown } from "@app/components/viewer/nonpdf/MarkdownRenderer";
import { TFunction } from "i18next";
import { useTranslation } from "react-i18next";
import {
ActionIcon,
@@ -43,7 +44,7 @@ import { StirlingLogoAnimated } from "@app/components/agents/StirlingLogoAnimate
import { ChatQuickActions } from "@app/components/chat/ChatQuickActions";
import "@app/components/chat/ChatPanel.css";
type TranslateFn = ReturnType<typeof useTranslation>["t"];
type TranslateFn = TFunction;
/** Resolver mapping a tool endpoint path to its translated display name. */
type ToolNameResolver = (endpoint: string) => string | null;
@@ -207,7 +208,7 @@ function ChatMessageBubble({
<ContentCopyIcon sx={{ fontSize: 13 }} />
</button>
<span className="chat-message-timestamp">
{formatRelativeTime(timestamp)}
{formatRelativeTime(timestamp, t)}
</span>
</div>
);