mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-07-30 13:48:07 +02:00
Fixes (#18877)
* Object labels with spaces should use correct i18n keys * Add Hungarian * Ensure onvif move request has a valid speed before removing When autotracking zooming is set to `disabled` (or is left out of the config), move_request["Speed"] may not exist, depending on the camera * Add another frame cache debug log
This commit is contained in:
parent
623bc72633
commit
f97629433d
@ -445,7 +445,7 @@ class CameraState:
|
||||
obj.thumbnail_data["frame_time"] if obj.thumbnail_data else None
|
||||
)
|
||||
logger.debug(
|
||||
f"{self.name}: Tracked object {obj_id} thumbnail frame_time: {thumb_time}"
|
||||
f"{self.name}: Tracked object {obj_id} thumbnail frame_time: {thumb_time}, false positive: {obj.false_positive}"
|
||||
)
|
||||
for t in thumb_frames_to_delete:
|
||||
object_id = self.frame_cache[t].get("object_id", "unknown")
|
||||
|
@ -265,9 +265,15 @@ class OnvifController:
|
||||
"RelativeZoomTranslationSpace"
|
||||
][zoom_space_id]["URI"]
|
||||
else:
|
||||
if "Zoom" in move_request["Translation"]:
|
||||
if (
|
||||
move_request["Translation"] is not None
|
||||
and "Zoom" in move_request["Translation"]
|
||||
):
|
||||
del move_request["Translation"]["Zoom"]
|
||||
if "Zoom" in move_request["Speed"]:
|
||||
if (
|
||||
move_request["Speed"] is not None
|
||||
and "Zoom" in move_request["Speed"]
|
||||
):
|
||||
del move_request["Speed"]["Zoom"]
|
||||
logger.debug(
|
||||
f"{camera_name}: Relative move request after deleting zoom: {move_request}"
|
||||
|
@ -12,7 +12,7 @@ import { SearchResult } from "@/types/search";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import useContextMenu from "@/hooks/use-contextmenu";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type SearchThumbnailProps = {
|
||||
searchResult: SearchResult;
|
||||
@ -23,7 +23,6 @@ export default function SearchThumbnail({
|
||||
searchResult,
|
||||
onClick,
|
||||
}: SearchThumbnailProps) {
|
||||
const { t } = useTranslation(["views/search"]);
|
||||
const apiHost = useApiHost();
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
|
||||
@ -151,7 +150,7 @@ export default function SearchThumbnail({
|
||||
.filter(
|
||||
(item) => item !== undefined && !item.includes("-verified"),
|
||||
)
|
||||
.map((text) => t(text, { ns: "objects" }))
|
||||
.map((text) => getTranslatedLabel(text))
|
||||
.sort()
|
||||
.join(", ")
|
||||
.replaceAll("-verified", "")}
|
||||
|
@ -24,6 +24,7 @@ import CalendarFilterButton from "./CalendarFilterButton";
|
||||
import { CamerasFilterButton } from "./CamerasFilterButton";
|
||||
import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
const REVIEW_FILTERS = [
|
||||
"cameras",
|
||||
@ -498,7 +499,7 @@ export function GeneralFilterContent({
|
||||
{allLabels.map((item) => (
|
||||
<FilterSwitch
|
||||
key={item}
|
||||
label={t(item, { ns: "objects" })}
|
||||
label={getTranslatedLabel(item)}
|
||||
isChecked={filter.labels?.includes(item) ?? false}
|
||||
onCheckedChange={(isChecked) => {
|
||||
if (isChecked) {
|
||||
|
@ -26,6 +26,7 @@ import { CalendarRangeFilterButton } from "./CalendarFilterButton";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type SearchFilterGroupProps = {
|
||||
className: string;
|
||||
@ -372,7 +373,7 @@ export function GeneralFilterContent({
|
||||
{allLabels.map((item) => (
|
||||
<FilterSwitch
|
||||
key={item}
|
||||
label={t(item, { ns: "objects" })}
|
||||
label={getTranslatedLabel(item)}
|
||||
isChecked={currentLabels?.includes(item) ?? false}
|
||||
onCheckedChange={(isChecked) => {
|
||||
if (isChecked) {
|
||||
|
@ -38,6 +38,7 @@ import { toast } from "sonner";
|
||||
import { Toaster } from "../ui/sonner";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type ObjectMaskEditPaneProps = {
|
||||
polygons?: Polygon[];
|
||||
@ -101,7 +102,7 @@ export default function ObjectMaskEditPane({
|
||||
|
||||
return t("masksAndZones.objectMaskLabel", {
|
||||
number: count + 1,
|
||||
label: t(objectType, { ns: "objects" }),
|
||||
label: getTranslatedLabel(objectType),
|
||||
});
|
||||
}, [polygons, polygon, t]);
|
||||
|
||||
@ -438,7 +439,7 @@ export function ZoneObjectSelector({ camera }: ZoneObjectSelectorProps) {
|
||||
<SelectSeparator className="bg-secondary" />
|
||||
{allLabels.map((item) => (
|
||||
<SelectItem key={item} value={item}>
|
||||
{t(item, { ns: "objects" })}
|
||||
{getTranslatedLabel(item)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
|
@ -33,6 +33,7 @@ import { Trans, useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LuExternalLink } from "react-icons/lu";
|
||||
import { useDocDomain } from "@/hooks/use-doc-domain";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type ZoneEditPaneProps = {
|
||||
polygons?: Polygon[];
|
||||
@ -969,7 +970,7 @@ export function ZoneObjectSelector({
|
||||
className="w-full cursor-pointer text-primary smart-capitalize"
|
||||
htmlFor={item}
|
||||
>
|
||||
{t(item, { ns: "objects" })}
|
||||
{getTranslatedLabel(item)}
|
||||
</Label>
|
||||
<Switch
|
||||
key={item}
|
||||
|
@ -19,4 +19,5 @@ export const supportedLanguageKeys = [
|
||||
"pl",
|
||||
"uk",
|
||||
"cs",
|
||||
"hu",
|
||||
];
|
||||
|
@ -1,7 +1,13 @@
|
||||
import i18n from "i18next";
|
||||
import i18n, { t } from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import HttpBackend from "i18next-http-backend";
|
||||
|
||||
export const getTranslatedLabel = (label: string) => {
|
||||
if (!label) return "";
|
||||
|
||||
return t(`${label.replace(/\s+/g, "_").toLowerCase()}`, { ns: "objects" });
|
||||
};
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(HttpBackend)
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { ObjectLifecycleSequence } from "@/types/timeline";
|
||||
import { t } from "i18next";
|
||||
import { getTranslatedLabel } from "./i18n";
|
||||
|
||||
export function getLifecycleItemDescription(
|
||||
lifecycleItem: ObjectLifecycleSequence,
|
||||
) {
|
||||
// can't use useTranslation here
|
||||
const label = t(
|
||||
(
|
||||
(Array.isArray(lifecycleItem.data.sub_label)
|
||||
? lifecycleItem.data.sub_label[0]
|
||||
: lifecycleItem.data.sub_label) || lifecycleItem.data.label
|
||||
)
|
||||
.replace(" ", "_")
|
||||
.toLowerCase(),
|
||||
{ ns: "objects" },
|
||||
);
|
||||
const rawLabel = Array.isArray(lifecycleItem.data.sub_label)
|
||||
? lifecycleItem.data.sub_label[0]
|
||||
: lifecycleItem.data.sub_label || lifecycleItem.data.label;
|
||||
|
||||
const label = getTranslatedLabel(rawLabel);
|
||||
|
||||
switch (lifecycleItem.class_type) {
|
||||
case "visible":
|
||||
|
@ -22,6 +22,7 @@ import SearchResultActions from "@/components/menu/SearchResultActions";
|
||||
import { SearchTab } from "@/components/overlay/detail/SearchDetailDialog";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type ExploreViewProps = {
|
||||
searchDetail: SearchResult | undefined;
|
||||
@ -152,7 +153,7 @@ function ThumbnailRow({
|
||||
return (
|
||||
<div className="rounded-lg bg-background_alt p-2 md:px-4">
|
||||
<div className="flex flex-row items-center text-lg smart-capitalize">
|
||||
{t(objectType, { ns: "objects" })}
|
||||
{getTranslatedLabel(objectType)}
|
||||
{searchResults && (
|
||||
<span className="ml-3 text-sm text-secondary-foreground">
|
||||
{t("trackedObjectsCount", {
|
||||
|
@ -32,6 +32,7 @@ import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useAlertsState, useDetectionsState, useEnabledState } from "@/api/ws";
|
||||
import { useDocDomain } from "@/hooks/use-doc-domain";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type CameraSettingsViewProps = {
|
||||
selectedCamera: string;
|
||||
@ -81,18 +82,18 @@ export default function CameraSettingsView({
|
||||
const alertsLabels = useMemo(() => {
|
||||
return cameraConfig?.review.alerts.labels
|
||||
? cameraConfig.review.alerts.labels
|
||||
.map((label) => t(label, { ns: "objects" }))
|
||||
.map((label) => getTranslatedLabel(label))
|
||||
.join(", ")
|
||||
: "";
|
||||
}, [cameraConfig, t]);
|
||||
}, [cameraConfig]);
|
||||
|
||||
const detectionsLabels = useMemo(() => {
|
||||
return cameraConfig?.review.detections.labels
|
||||
? cameraConfig.review.detections.labels
|
||||
.map((label) => t(label, { ns: "objects" }))
|
||||
.map((label) => getTranslatedLabel(label))
|
||||
.join(", ")
|
||||
: "";
|
||||
}, [cameraConfig, t]);
|
||||
}, [cameraConfig]);
|
||||
|
||||
// form
|
||||
|
||||
|
@ -42,6 +42,7 @@ import { useSearchEffect } from "@/hooks/use-overlay-state";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useDocDomain } from "@/hooks/use-doc-domain";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type MasksAndZoneViewProps = {
|
||||
selectedCamera: string;
|
||||
@ -332,7 +333,7 @@ export default function MasksAndZonesView({
|
||||
camera: cameraConfig.name,
|
||||
name: t("masksAndZones.objectMaskLabel", {
|
||||
number: globalObjectMasksCount + index + 1,
|
||||
label: t(objectName, { ns: "objects" }),
|
||||
label: getTranslatedLabel(objectName),
|
||||
}),
|
||||
objects: [objectName],
|
||||
points: interpolatePoints(
|
||||
|
@ -29,6 +29,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { useDocDomain } from "@/hooks/use-doc-domain";
|
||||
import { getTranslatedLabel } from "@/utils/i18n";
|
||||
|
||||
type ObjectSettingsViewProps = {
|
||||
selectedCamera?: string;
|
||||
@ -371,7 +372,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
{getIconForLabel(obj.label, "size-5 text-white")}
|
||||
</div>
|
||||
<div className="ml-3 text-lg">
|
||||
{t(obj.label, { ns: "objects" })}
|
||||
{getTranslatedLabel(obj.label)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-8/12 flex-row items-center justify-end">
|
||||
|
Loading…
Reference in New Issue
Block a user