From f9b2db440542cf24d636f549478336c150ddbe05 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 22 Apr 2025 16:21:09 -0600 Subject: [PATCH] Implement smart capitalization based on locale (#17860) --- web/src/App.tsx | 10 +++++++++- web/src/components/card/ExportCard.tsx | 2 +- web/src/components/card/ReviewCard.tsx | 2 +- web/src/components/card/SearchThumbnail.tsx | 2 +- web/src/components/filter/CameraGroupSelector.tsx | 4 ++-- web/src/components/filter/CamerasFilterButton.tsx | 4 ++-- web/src/components/filter/FilterSwitch.tsx | 2 +- web/src/components/filter/LogSettingsButton.tsx | 2 +- web/src/components/filter/ReviewFilterGroup.tsx | 2 +- web/src/components/filter/SearchFilterGroup.tsx | 4 ++-- web/src/components/filter/ZoneMaskFilter.tsx | 4 ++-- web/src/components/graph/CombinedStorageGraph.tsx | 2 +- web/src/components/indicators/Chip.tsx | 2 +- web/src/components/input/InputWithTags.tsx | 4 ++-- web/src/components/menu/LiveContextMenu.tsx | 2 +- web/src/components/overlay/CameraInfoDialog.tsx | 2 +- web/src/components/overlay/ExportDialog.tsx | 2 +- web/src/components/overlay/FaceSelectionDialog.tsx | 4 ++-- web/src/components/overlay/MobileCameraDrawer.tsx | 4 ++-- .../overlay/MobileReviewSettingsDrawer.tsx | 2 +- .../components/overlay/MobileTimelineDrawer.tsx | 6 +++--- .../components/overlay/detail/ObjectLifecycle.tsx | 6 +++--- web/src/components/overlay/detail/ObjectPath.tsx | 2 +- .../overlay/detail/ObjectPathPlotter.tsx | 4 +++- .../overlay/detail/ReviewDetailDialog.tsx | 10 +++++----- .../overlay/detail/SearchDetailDialog.tsx | 6 +++--- web/src/components/player/LivePlayer.tsx | 2 +- .../components/player/PreviewThumbnailPlayer.tsx | 2 +- .../components/settings/CameraStreamingDialog.tsx | 2 +- web/src/components/settings/ZoneEditPane.tsx | 2 +- web/src/pages/Exports.tsx | 2 +- web/src/pages/FaceLibrary.tsx | 14 +++++++------- web/src/pages/Logs.tsx | 4 ++-- web/src/pages/Settings.tsx | 4 ++-- web/src/pages/System.tsx | 2 +- web/src/utils/i18n.ts | 2 +- web/src/views/explore/ExploreView.tsx | 4 ++-- web/src/views/search/SearchView.tsx | 2 +- web/src/views/settings/CameraSettingsView.tsx | 4 ++-- .../views/settings/NotificationsSettingsView.tsx | 2 +- web/src/views/settings/ObjectSettingsView.tsx | 4 ++-- web/src/views/system/CameraMetrics.tsx | 2 +- web/src/views/system/EnrichmentMetrics.tsx | 2 +- web/tailwind.config.cjs | 14 ++++++++++++++ 44 files changed, 95 insertions(+), 71 deletions(-) diff --git a/web/src/App.tsx b/web/src/App.tsx index a0062549f..83a3b0304 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -6,12 +6,13 @@ import Sidebar from "@/components/navigation/Sidebar"; import { isDesktop, isMobile } from "react-device-detect"; import Statusbar from "./components/Statusbar"; import Bottombar from "./components/navigation/Bottombar"; -import { Suspense, lazy } from "react"; +import React, { Suspense, lazy } from "react"; import { Redirect } from "./components/navigation/Redirect"; import { cn } from "./lib/utils"; import { isPWA } from "./utils/isPWA"; import ProtectedRoute from "@/components/auth/ProtectedRoute"; import { AuthProvider } from "@/context/auth-context"; +import { useTranslation } from "react-i18next"; const Live = lazy(() => import("@/pages/Live")); const Events = lazy(() => import("@/pages/Events")); @@ -26,6 +27,13 @@ const Logs = lazy(() => import("@/pages/Logs")); const AccessDenied = lazy(() => import("@/pages/AccessDenied")); function App() { + const { i18n } = useTranslation(); + + // Set the lang attribute on the html element when language changes + React.useEffect(() => { + document.documentElement.lang = i18n.language; + }, [i18n.language]); + return ( diff --git a/web/src/components/card/ExportCard.tsx b/web/src/components/card/ExportCard.tsx index fcd970904..9115e0509 100644 --- a/web/src/components/card/ExportCard.tsx +++ b/web/src/components/card/ExportCard.tsx @@ -222,7 +222,7 @@ export default function ExportCard({ )}
-
+
{exportedRecording.name.replaceAll("_", " ")}
diff --git a/web/src/components/card/ReviewCard.tsx b/web/src/components/card/ReviewCard.tsx index 291201369..09929cec5 100644 --- a/web/src/components/card/ReviewCard.tsx +++ b/web/src/components/card/ReviewCard.tsx @@ -175,7 +175,7 @@ export default function ReviewCard({
{formattedDate}
- + {[ ...new Set([ ...(event.data.objects || []), diff --git a/web/src/components/card/SearchThumbnail.tsx b/web/src/components/card/SearchThumbnail.tsx index 75bae5cef..a765a8073 100644 --- a/web/src/components/card/SearchThumbnail.tsx +++ b/web/src/components/card/SearchThumbnail.tsx @@ -146,7 +146,7 @@ export default function SearchThumbnail({ - + {[searchResult.sub_label ?? objectLabel] .filter( (item) => item !== undefined && !item.includes("-verified"), diff --git a/web/src/components/filter/CameraGroupSelector.tsx b/web/src/components/filter/CameraGroupSelector.tsx index ecb06a12b..6d9ea7856 100644 --- a/web/src/components/filter/CameraGroupSelector.tsx +++ b/web/src/components/filter/CameraGroupSelector.tsx @@ -196,7 +196,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) { - + {name} @@ -847,7 +847,7 @@ export function CameraGroupEdit({
-
+
{getLifecycleItemDescription(item)}
@@ -616,7 +616,7 @@ export default function ObjectLifecycle({ )}
setSelectedZone(zone)} > {zone.replaceAll("_", " ")} @@ -722,7 +722,7 @@ export default function ObjectLifecycle({ /> - + {getLifecycleItemDescription(item)} diff --git a/web/src/components/overlay/detail/ObjectPath.tsx b/web/src/components/overlay/detail/ObjectPath.tsx index f8ee02080..06a47d571 100644 --- a/web/src/components/overlay/detail/ObjectPath.tsx +++ b/web/src/components/overlay/detail/ObjectPath.tsx @@ -100,7 +100,7 @@ export function ObjectPath({ /> - + {pos.lifecycle_item ? getLifecycleItemDescription(pos.lifecycle_item) : "Tracked point"} diff --git a/web/src/components/overlay/detail/ObjectPathPlotter.tsx b/web/src/components/overlay/detail/ObjectPathPlotter.tsx index 40cf1728e..1fcf02d1d 100644 --- a/web/src/components/overlay/detail/ObjectPathPlotter.tsx +++ b/web/src/components/overlay/detail/ObjectPathPlotter.tsx @@ -223,7 +223,9 @@ export default function ObjectPathPlotter() { }} /> - {event.label} + + {event.label} + {formatUnixTimestampToDateTime(event.start_time, { timezone: config?.ui.timezone, })} diff --git a/web/src/components/overlay/detail/ReviewDetailDialog.tsx b/web/src/components/overlay/detail/ReviewDetailDialog.tsx index 23666acb4..c296866c4 100644 --- a/web/src/components/overlay/detail/ReviewDetailDialog.tsx +++ b/web/src/components/overlay/detail/ReviewDetailDialog.tsx @@ -233,7 +233,7 @@ export default function ReviewDetailDialog({
{t("details.camera")}
-
+
{review.camera.replaceAll("_", " ")}
@@ -249,12 +249,12 @@ export default function ReviewDetailDialog({
{t("details.objects")}
-
+
{events?.map((event) => { return (
{getIconForLabel( event.label, @@ -290,12 +290,12 @@ export default function ReviewDetailDialog({
{t("details.zones")}
-
+
{review.data.zones.map((zone) => { return (
{zone.replaceAll("_", " ")}
diff --git a/web/src/components/overlay/detail/SearchDetailDialog.tsx b/web/src/components/overlay/detail/SearchDetailDialog.tsx index 2938bf3a2..9b913ed53 100644 --- a/web/src/components/overlay/detail/SearchDetailDialog.tsx +++ b/web/src/components/overlay/detail/SearchDetailDialog.tsx @@ -231,7 +231,7 @@ export default function SearchDetailDialog({ {item == "object_lifecycle" && ( )} -
{t(`type.${item}`)}
+
{t(`type.${item}`)}
))} @@ -711,7 +711,7 @@ function ObjectDetailsTab({
{t("details.label")}
-
+
{getIconForLabel(search.label, "size-4 text-primary")} {t(search.label, { ns: "objects", @@ -831,7 +831,7 @@ function ObjectDetailsTab({ )}
{t("details.camera")}
-
+
{search.camera.replaceAll("_", " ")}
diff --git a/web/src/components/player/LivePlayer.tsx b/web/src/components/player/LivePlayer.tsx index 1989a55ab..3d8df2b34 100644 --- a/web/src/components/player/LivePlayer.tsx +++ b/web/src/components/player/LivePlayer.tsx @@ -361,7 +361,7 @@ export default function LivePlayer({
- + {[ ...new Set([ ...(objects || []).map(({ label, sub_label }) => diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index da7fac0e2..0e66b3c26 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -262,7 +262,7 @@ export default function PreviewThumbnailPlayer({
- + {[ ...new Set([ ...(review.data.objects || []), diff --git a/web/src/components/settings/CameraStreamingDialog.tsx b/web/src/components/settings/CameraStreamingDialog.tsx index b9bd8a4b6..0aae164e8 100644 --- a/web/src/components/settings/CameraStreamingDialog.tsx +++ b/web/src/components/settings/CameraStreamingDialog.tsx @@ -185,7 +185,7 @@ export function CameraStreamingDialog({ return ( - + {t("group.camera.setting.title", { cameraName: camera.replaceAll("_", " "), })} diff --git a/web/src/components/settings/ZoneEditPane.tsx b/web/src/components/settings/ZoneEditPane.tsx index c6eefaf6d..5e8681732 100644 --- a/web/src/components/settings/ZoneEditPane.tsx +++ b/web/src/components/settings/ZoneEditPane.tsx @@ -933,7 +933,7 @@ export function ZoneObjectSelector({ {allLabels.map((item) => (