From 38b13a0cf1db2f5920461fefa92e75d8b651ebae Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Sun, 9 Nov 2025 09:17:59 +0000 Subject: [PATCH 1/6] fix: fix the missing i18n key --- web/public/locales/en/common.json | 3 ++- web/src/views/recording/RecordingView.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/web/public/locales/en/common.json b/web/public/locales/en/common.json index 87f32a251..e0d57cbbf 100644 --- a/web/public/locales/en/common.json +++ b/web/public/locales/en/common.json @@ -144,7 +144,8 @@ "unselect": "Unselect", "export": "Export", "deleteNow": "Delete Now", - "next": "Next" + "next": "Next", + "continue": "Continue" }, "menu": { "system": "System", diff --git a/web/src/views/recording/RecordingView.tsx b/web/src/views/recording/RecordingView.tsx index a934e1cb9..5b4d5328c 100644 --- a/web/src/views/recording/RecordingView.tsx +++ b/web/src/views/recording/RecordingView.tsx @@ -649,7 +649,7 @@ export function RecordingView({ value="detail" aria-label="Detail Stream" > -
Detail
+
{t("detail.label")}
) : ( From 6214d5232af650872417d2e4aa97170cd2b532cc Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Sun, 9 Nov 2025 09:19:18 +0000 Subject: [PATCH 2/6] fix: fix trackedObject i18n keys count variable --- web/src/components/timeline/DetailStream.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx index 8e80506bd..6127ab832 100644 --- a/web/src/components/timeline/DetailStream.tsx +++ b/web/src/components/timeline/DetailStream.tsx @@ -349,7 +349,7 @@ function ReviewGroup({ ? fetchedEvents.length : (review.data.objects ?? []).length; - return `${objectCount} ${t("detail.trackedObject", { count: objectCount })}`; + return `${t("detail.trackedObject", { count: objectCount })}`; }, [review, t, fetchedEvents]); const reviewDuration = useMemo( From 1c108bd9101e71c6a3924edcde0d8655165f1041 Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Sun, 9 Nov 2025 09:19:51 +0000 Subject: [PATCH 3/6] fix: fix some pages audio label missing i18n --- .../components/filter/ReviewFilterGroup.tsx | 23 ++++++++++++++- web/src/components/input/InputWithTags.tsx | 29 +++++++++++++++++-- web/src/components/timeline/DetailStream.tsx | 25 ++++++++++++++-- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index d6df53987..76274ec3f 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -454,6 +454,24 @@ export function GeneralFilterContent({ onClose, }: GeneralFilterContentProps) { const { t } = useTranslation(["components/filter", "views/events"]); + const { data: config } = useSWR("config", { + revalidateOnFocus: false, + }); + const allAudioListenLabels = useMemo(() => { + if (!config) { + return []; + } + + const labels = new Set(); + Object.values(config.cameras).forEach((camera) => { + if (camera?.audio?.enabled) { + camera.audio.listen.forEach((label) => { + labels.add(label); + }); + } + }); + return [...labels].sort(); + }, [config]); return ( <>
@@ -504,7 +522,10 @@ export function GeneralFilterContent({ {allLabels.map((item) => ( { if (isChecked) { diff --git a/web/src/components/input/InputWithTags.tsx b/web/src/components/input/InputWithTags.tsx index 199209c7c..d1bd4da40 100755 --- a/web/src/components/input/InputWithTags.tsx +++ b/web/src/components/input/InputWithTags.tsx @@ -81,6 +81,22 @@ export default function InputWithTags({ revalidateOnFocus: false, }); + const allAudioListenLabels = useMemo(() => { + if (!config) { + return []; + } + + const labels = new Set(); + Object.values(config.cameras).forEach((camera) => { + if (camera?.audio?.enabled) { + camera.audio.listen.forEach((label) => { + labels.add(label); + }); + } + }); + return [...labels].sort(); + }, [config]); + const [inputValue, setInputValue] = useState(search || ""); const [currentFilterType, setCurrentFilterType] = useState( null, @@ -421,7 +437,11 @@ export default function InputWithTags({ ? t("button.yes", { ns: "common" }) : t("button.no", { ns: "common" }); } else if (filterType === "labels") { - return getTranslatedLabel(String(filterValues)); + const value = String(filterValues); + return getTranslatedLabel( + value, + allAudioListenLabels.includes(value) ? "audio" : "object", + ); } else if (filterType === "search_type") { return t("filter.searchType." + String(filterValues)); } else { @@ -828,7 +848,12 @@ export default function InputWithTags({ > {t("filter.label." + filterType)}:{" "} {filterType === "labels" ? ( - getTranslatedLabel(value) + getTranslatedLabel( + value, + allAudioListenLabels.includes(value) + ? "audio" + : "object", + ) ) : filterType === "cameras" ? ( ) : filterType === "zones" ? ( diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx index 6127ab832..20bac9116 100644 --- a/web/src/components/timeline/DetailStream.tsx +++ b/web/src/components/timeline/DetailStream.tsx @@ -478,7 +478,7 @@ function ReviewGroup({
{getIconForLabel(audioLabel, "size-3 text-white")}
- {getTranslatedLabel(audioLabel)} + {getTranslatedLabel(audioLabel, "audio")}
))} @@ -513,7 +513,28 @@ function EventList({ const isSelected = selectedObjectIds.includes(event.id); - const label = event.sub_label || getTranslatedLabel(event.label); + const allAudioListenLabels = useMemo(() => { + if (!config) { + return []; + } + + const labels = new Set(); + Object.values(config.cameras).forEach((camera) => { + if (camera?.audio?.enabled) { + camera.audio.listen.forEach((label) => { + labels.add(label); + }); + } + }); + return [...labels].sort(); + }, [config]); + + const label = + event.sub_label || + getTranslatedLabel( + event.label, + allAudioListenLabels.includes(event.label) ? "audio" : "object", + ); const handleObjectSelect = (event: Event | undefined) => { if (event) { From bae32f8e40bbbd2667fd5f6947adcf82d4d195d4 Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Sun, 9 Nov 2025 09:24:48 +0000 Subject: [PATCH 4/6] fix: add 6214d52 missing variable --- web/public/locales/en/views/events.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/public/locales/en/views/events.json b/web/public/locales/en/views/events.json index 6e242c1e3..d3cf78658 100644 --- a/web/public/locales/en/views/events.json +++ b/web/public/locales/en/views/events.json @@ -24,8 +24,8 @@ "label": "Detail", "noDataFound": "No detail data to review", "aria": "Toggle detail view", - "trackedObject_one": "object", - "trackedObject_other": "objects", + "trackedObject_one": "{{count}} object", + "trackedObject_other": "{{count}} objects", "noObjectDetailData": "No object detail data available.", "settings": "Detail View Settings", "alwaysExpandActive": { From 96ed740a1299773f28053a122afad2dfde86d6a8 Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Mon, 10 Nov 2025 15:04:43 +0000 Subject: [PATCH 5/6] fix: add more missing i18n --- web/public/locales/en/common.json | 5 ++- web/public/locales/en/views/explore.json | 2 +- web/src/components/input/InputWithTags.tsx | 39 ++++++++++++------- .../overlay/detail/SearchDetailDialog.tsx | 6 ++- web/src/components/timeline/DetailStream.tsx | 22 +---------- web/src/utils/dateUtil.ts | 6 +-- 6 files changed, 39 insertions(+), 41 deletions(-) diff --git a/web/public/locales/en/common.json b/web/public/locales/en/common.json index e0d57cbbf..daf8c9897 100644 --- a/web/public/locales/en/common.json +++ b/web/public/locales/en/common.json @@ -72,7 +72,10 @@ "formattedTimestampFilename": { "12hour": "MM-dd-yy-h-mm-ss-a", "24hour": "MM-dd-yy-HH-mm-ss" - } + }, + "inProgress": "In progress", + "invalidStartTime": "Invalid start time", + "invalidEndTime": "Invalid end time" }, "unit": { "speed": { diff --git a/web/public/locales/en/views/explore.json b/web/public/locales/en/views/explore.json index afc81eaa6..3d6985cfc 100644 --- a/web/public/locales/en/views/explore.json +++ b/web/public/locales/en/views/explore.json @@ -35,7 +35,7 @@ "snapshot": "snapshot", "thumbnail": "thumbnail", "video": "video", - "object_lifecycle": "object lifecycle" + "tracking_details": "tracking details" }, "trackingDetails": { "title": "Tracking Details", diff --git a/web/src/components/input/InputWithTags.tsx b/web/src/components/input/InputWithTags.tsx index d1bd4da40..58098743b 100755 --- a/web/src/components/input/InputWithTags.tsx +++ b/web/src/components/input/InputWithTags.tsx @@ -81,9 +81,9 @@ export default function InputWithTags({ revalidateOnFocus: false, }); - const allAudioListenLabels = useMemo(() => { + const allAudioListenLabels = useMemo>(() => { if (!config) { - return []; + return new Set(); } const labels = new Set(); @@ -94,9 +94,30 @@ export default function InputWithTags({ }); } }); - return [...labels].sort(); + return labels; }, [config]); + const translatedAudioLabelMap = useMemo>(() => { + const map = new Map(); + if (!config) return map; + + allAudioListenLabels.forEach((label) => { + // getTranslatedLabel likely depends on i18n internally; including `lang` + // in deps ensures this map is rebuilt when language changes + map.set(label, getTranslatedLabel(label, "audio")); + }); + return map; + }, [allAudioListenLabels, config]); + + function resolveLabel(value: string) { + const mapped = translatedAudioLabelMap.get(value); + if (mapped) return mapped; + return getTranslatedLabel( + value, + allAudioListenLabels.has(value) ? "audio" : "object", + ); + } + const [inputValue, setInputValue] = useState(search || ""); const [currentFilterType, setCurrentFilterType] = useState( null, @@ -438,10 +459,7 @@ export default function InputWithTags({ : t("button.no", { ns: "common" }); } else if (filterType === "labels") { const value = String(filterValues); - return getTranslatedLabel( - value, - allAudioListenLabels.includes(value) ? "audio" : "object", - ); + return resolveLabel(value); } else if (filterType === "search_type") { return t("filter.searchType." + String(filterValues)); } else { @@ -848,12 +866,7 @@ export default function InputWithTags({ > {t("filter.label." + filterType)}:{" "} {filterType === "labels" ? ( - getTranslatedLabel( - value, - allAudioListenLabels.includes(value) - ? "audio" - : "object", - ) + resolveLabel(value) ) : filterType === "cameras" ? ( ) : filterType === "zones" ? ( diff --git a/web/src/components/overlay/detail/SearchDetailDialog.tsx b/web/src/components/overlay/detail/SearchDetailDialog.tsx index 7ff49d4d5..ae60ed1c6 100644 --- a/web/src/components/overlay/detail/SearchDetailDialog.tsx +++ b/web/src/components/overlay/detail/SearchDetailDialog.tsx @@ -1155,7 +1155,7 @@ function ObjectDetailsTab({
{getIconForLabel(search.label, "size-4 text-primary")} - {getTranslatedLabel(search.label)} + {getTranslatedLabel(search.label, search.data.type)} {search.sub_label && ` (${search.sub_label})`} {isAdmin && search.end_time && ( @@ -1394,7 +1394,9 @@ function ObjectDetailsTab({ {state == "submitted" && (
- {t("explore.plus.review.state.submitted")} + {t("explore.plus.review.state.submitted", { + ns: "components/dialog", + })}
)}
diff --git a/web/src/components/timeline/DetailStream.tsx b/web/src/components/timeline/DetailStream.tsx index 20bac9116..d133aa05a 100644 --- a/web/src/components/timeline/DetailStream.tsx +++ b/web/src/components/timeline/DetailStream.tsx @@ -513,28 +513,8 @@ function EventList({ const isSelected = selectedObjectIds.includes(event.id); - const allAudioListenLabels = useMemo(() => { - if (!config) { - return []; - } - - const labels = new Set(); - Object.values(config.cameras).forEach((camera) => { - if (camera?.audio?.enabled) { - camera.audio.listen.forEach((label) => { - labels.add(label); - }); - } - }); - return [...labels].sort(); - }, [config]); - const label = - event.sub_label || - getTranslatedLabel( - event.label, - allAudioListenLabels.includes(event.label) ? "audio" : "object", - ); + event.sub_label || getTranslatedLabel(event.label, event.data.type); const handleObjectSelect = (event: Event | undefined) => { if (event) { diff --git a/web/src/utils/dateUtil.ts b/web/src/utils/dateUtil.ts index 4427b59ac..db6e0b1cb 100644 --- a/web/src/utils/dateUtil.ts +++ b/web/src/utils/dateUtil.ts @@ -244,12 +244,12 @@ export const getDurationFromTimestamps = ( abbreviated: boolean = false, ): string => { if (isNaN(start_time)) { - return "Invalid start time"; + return i18n.t("time.invalidStartTime", { ns: "common" }); } - let duration = "In Progress"; + let duration = i18n.t("time.inProgress", { ns: "common" }); if (end_time !== null) { if (isNaN(end_time)) { - return "Invalid end time"; + return i18n.t("time.invalidEndTime", { ns: "common" }); } const start = fromUnixTime(start_time); const end = fromUnixTime(end_time); From 42c18044dee3f6f03089d0048331945f5e20e74c Mon Sep 17 00:00:00 2001 From: ZhaiSoul <842607283@qq.com> Date: Mon, 10 Nov 2025 15:08:27 +0000 Subject: [PATCH 6/6] fix: add menu missing key --- web/public/locales/en/common.json | 1 + 1 file changed, 1 insertion(+) diff --git a/web/public/locales/en/common.json b/web/public/locales/en/common.json index daf8c9897..aa841c30b 100644 --- a/web/public/locales/en/common.json +++ b/web/public/locales/en/common.json @@ -241,6 +241,7 @@ "export": "Export", "uiPlayground": "UI Playground", "faceLibrary": "Face Library", + "classification": "Classification", "user": { "title": "User", "account": "Account",