diff --git a/src/components/AnalyticsModal.tsx b/src/components/AnalyticsModal.tsx index 7975de7..0865b9c 100644 --- a/src/components/AnalyticsModal.tsx +++ b/src/components/AnalyticsModal.tsx @@ -2,6 +2,7 @@ import { useEffect } from "react"; import { createPortal } from "react-dom"; +import { useTranslations } from "next-intl"; /** * Analytics metrics payload returned by the custom backend API @@ -24,20 +25,6 @@ interface AnalyticsModalProps { stats: AnalyticsData; } -/** - * Formats unix timestamps into relative time strings (e.g., "5s ago", "2m ago") - */ -function getTimeAgo(timestamp?: number): string { - if (!timestamp) return "just now"; - const seconds = Math.floor((Date.now() - timestamp * 1000) / 1000); - if (seconds < 10) return "just now"; - if (seconds < 60) return `${seconds}s ago`; - const minutes = Math.floor(seconds / 60); - if (minutes < 60) return `${minutes}m ago`; - const hours = Math.floor(minutes / 60); - return `${hours}h ago`; -} - /** * Terminal-style modal inspector for viewing live traffic and system health metric */ @@ -46,6 +33,22 @@ export default function AnalyticsModal({ onClose, stats, }: AnalyticsModalProps) { + const tAnalyticsModal = useTranslations("AnalyticsModal"); + + /** + * Formats unix timestamps into relative time strings based on locale + */ + const getTimeAgo = (timestamp?: number): string => { + if (!timestamp) return tAnalyticsModal("timeJustNow"); + const seconds = Math.floor((Date.now() - timestamp * 1000) / 1000); + if (seconds < 10) return tAnalyticsModal("timeJustNow"); + if (seconds < 60) return tAnalyticsModal("timeSecondsAgo", { seconds }); + const minutes = Math.floor(seconds / 60); + if (minutes < 60) return tAnalyticsModal("timeMinutesAgo", { minutes }); + const hours = Math.floor(minutes / 60); + return tAnalyticsModal("timeHoursAgo", { hours }); + }; + // Global hotkeys to dismiss the modal (ESC) useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -86,16 +89,16 @@ export default function AnalyticsModal({ @@ -126,10 +129,10 @@ export default function AnalyticsModal({
- STATUS: ONLINE + {tAnalyticsModal("statusOnline")} - LATENCY:{" "} + {tAnalyticsModal("latency")}:{" "} {stats.latencyMs ?? "<1"}ms @@ -141,7 +144,7 @@ export default function AnalyticsModal({
- views_today + {tAnalyticsModal("metricViewsToday")} #1
@@ -151,7 +154,7 @@ export default function AnalyticsModal({
- unique_visitors + {tAnalyticsModal("metricUniqueVisitors")} #2
@@ -163,7 +166,9 @@ export default function AnalyticsModal({ {/* Total Hits & Device Breakdown */}
- total_hits: + + {tAnalyticsModal("metricTotalHits")}: + {stats.totalViews} @@ -172,7 +177,9 @@ export default function AnalyticsModal({ {/* Device ratio progress bar */}
- device_ratio: + + {tAnalyticsModal("metricDeviceRatio")}: + 💻 {desktopCount} / 📱{" "} {mobileCount} @@ -196,9 +203,9 @@ export default function AnalyticsModal({ {/* GDPR & Activity Footer */}
- GDPR_ANONYMIZED: TRUE + {tAnalyticsModal("gdprAnonymized")} - LAST_PING:{" "} + {tAnalyticsModal("lastPing")}:{" "} {getTimeAgo(stats.lastPing)}
diff --git a/src/components/AnalyticsWidget.tsx b/src/components/AnalyticsWidget.tsx index 9a2726e..4237c8e 100644 --- a/src/components/AnalyticsWidget.tsx +++ b/src/components/AnalyticsWidget.tsx @@ -1,12 +1,15 @@ "use client"; import { useEffect, useState } from "react"; +import { useTranslations } from "next-intl"; import AnalyticsModal, { AnalyticsData } from "./AnalyticsModal"; /** * Footer badge widget that fetches live metrics and triggers the analytics modal */ export default function AnalyticsWidget() { + const tAnalyticsWidget = useTranslations("AnalyticsWidget"); + const [stats, setStats] = useState(null); const [isOpen, setIsOpen] = useState(false); const [mounted, setMounted] = useState(false); @@ -26,14 +29,14 @@ export default function AnalyticsWidget() { // Open modal and silently refresh stats without incrementing view count const handleOpenModal = () => { - fetchStats(false); // track=false when clicking badge + fetchStats(false); setIsOpen(true); }; // Hydrate client, fetch initial page metrics, and listen for custom Cmd+K palette events useEffect(() => { setMounted(true); - fetchStats(true); // Track initial page view + fetchStats(true); // Listen for custom trigger event fired from CommandPalette const handleCustomOpen = () => handleOpenModal(); @@ -50,7 +53,9 @@ export default function AnalyticsWidget() {
$ - loading_stats... + + {tAnalyticsWidget("loading")} +
); } @@ -61,7 +66,7 @@ export default function AnalyticsWidget() {