mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-06 05:27:44 +03:00
chore: fix some key not work
This commit is contained in:
parent
ef646203a7
commit
a8a4938c97
@ -38,6 +38,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"camera": {
|
||||
"enable": "Enable Camera",
|
||||
"disable": "Disable Camera"
|
||||
},
|
||||
"detect": {
|
||||
"enable": "Enable Detect",
|
||||
"disable": "Disable Detect"
|
||||
|
||||
@ -64,6 +64,7 @@
|
||||
"info": "信息"
|
||||
},
|
||||
"menu": {
|
||||
"system": "系统",
|
||||
"systemMetrics": "系统信息",
|
||||
"configuration": "配置",
|
||||
"systemLogs": "系统日志",
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"camera": {
|
||||
"enable": "开启摄像头",
|
||||
"disable": "关闭摄像头"
|
||||
},
|
||||
"detect": {
|
||||
"enable": "启用检测",
|
||||
"disable": "关闭检测"
|
||||
|
||||
@ -69,7 +69,7 @@ export default function CalendarFilterButton({
|
||||
updateSelectedDay(undefined);
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -76,7 +76,7 @@ import { Switch } from "../ui/switch";
|
||||
import { CameraStreamingDialog } from "../settings/CameraStreamingDialog";
|
||||
import { DialogTrigger } from "@radix-ui/react-dialog";
|
||||
import { useStreamingSettings } from "@/context/streaming-settings-provider";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type CameraGroupSelectorProps = {
|
||||
className?: string;
|
||||
@ -165,7 +165,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent className="" side="right">
|
||||
{t("menu.live.allCameras")}
|
||||
{t("menu.live.allCameras", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
@ -536,15 +536,19 @@ export function CameraGroupRow({
|
||||
<AlertDialogTitle>{t("group.delete.confirm")}</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogDescription>
|
||||
{t("group.delete.confirm.desc", { name: group[0] })}
|
||||
<Trans ns="components/camera" values={{ name: group[0] }}>
|
||||
group.delete.confirm.desc
|
||||
</Trans>
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={buttonVariants({ variant: "destructive" })}
|
||||
onClick={onDeleteGroup}
|
||||
>
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@ -562,13 +566,13 @@ export function CameraGroupRow({
|
||||
aria-label="Edit group"
|
||||
onClick={onEditGroup}
|
||||
>
|
||||
{t("button.edit")}
|
||||
{t("button.edit", { ns: "common" })}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
aria-label="Delete group"
|
||||
onClick={() => setDeleteDialogOpen(true)}
|
||||
>
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenuPortal>
|
||||
@ -585,7 +589,9 @@ export function CameraGroupRow({
|
||||
onClick={onEditGroup}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t("button.edit")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.edit", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
@ -596,7 +602,9 @@ export function CameraGroupRow({
|
||||
onClick={() => setDeleteDialogOpen(true)}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t("button.delete")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
@ -925,7 +933,7 @@ export function CameraGroupEdit({
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -937,10 +945,10 @@ export function CameraGroupEdit({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -42,7 +42,7 @@ export function CamerasFilterButton({
|
||||
}
|
||||
|
||||
if (!selectedCameras || selectedCameras.length == 0) {
|
||||
return t("menu.live.allCameras");
|
||||
return t("menu.live.allCameras", { ns: "common" });
|
||||
}
|
||||
|
||||
return `${selectedCameras.includes("birdseye") ? selectedCameras.length - 1 : selectedCameras.length} Camera${selectedCameras.length !== 1 ? "s" : ""}`;
|
||||
@ -236,7 +236,7 @@ export function CamerasFilterContent({
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Reset"
|
||||
@ -245,7 +245,7 @@ export function CamerasFilterContent({
|
||||
updateCameraFilter(undefined);
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -577,10 +577,10 @@ export function GeneralFilterContent({
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common" })}
|
||||
</Button>
|
||||
<Button aria-label="Reset" onClick={onReset}>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -391,7 +391,7 @@ export function GeneralFilterContent({
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Reset"
|
||||
@ -400,7 +400,7 @@ export function GeneralFilterContent({
|
||||
updateLabelFilter(undefined);
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
@ -567,7 +567,7 @@ export function SortTypeContent({
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Reset"
|
||||
@ -576,7 +576,7 @@ export function SortTypeContent({
|
||||
updateSortType(undefined);
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -101,10 +101,10 @@ export function GeneralFilterContent({
|
||||
>
|
||||
{t(
|
||||
"masksAndZones." +
|
||||
item.replace(/_([a-z])/g, (letter) =>
|
||||
letter.toUpperCase(),
|
||||
) +
|
||||
"s",
|
||||
item
|
||||
.replace(/_([a-z])/g, (letter) => letter.toUpperCase())
|
||||
.replace("_", "") +
|
||||
"s.label",
|
||||
{ ns: "views/settings" },
|
||||
)}
|
||||
</Label>
|
||||
|
||||
@ -80,7 +80,7 @@ export function SaveSearchDialog({
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button aria-label="Cancel" onClick={onClose}>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
@ -88,7 +88,7 @@ export function SaveSearchDialog({
|
||||
className="mb-2 md:mb-0"
|
||||
aria-label="Save this search"
|
||||
>
|
||||
{t("button.save")}
|
||||
{t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@ -187,7 +187,7 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
||||
>
|
||||
<a className="flex" href={logoutUrl}>
|
||||
<LuLogOut className="mr-2 size-4" />
|
||||
<span>Logout</span>
|
||||
<span>{t("menu.user.logout", { ns: "common" })}</span>
|
||||
</a>
|
||||
</MenuItem>
|
||||
</div>
|
||||
|
||||
@ -40,7 +40,7 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import useSWR from "swr";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type SearchResultActionsProps = {
|
||||
searchResult: SearchResult;
|
||||
@ -154,7 +154,7 @@ export default function SearchResultActions({
|
||||
onClick={() => setDeleteDialogOpen(true)}
|
||||
>
|
||||
<LuTrash2 className="mr-2 size-4" />
|
||||
<span>{t("button.delete")}</span>
|
||||
<span>{t("button.delete", { ns: "common" })}</span>
|
||||
</MenuItem>
|
||||
</>
|
||||
);
|
||||
@ -170,15 +170,17 @@ export default function SearchResultActions({
|
||||
<AlertDialogTitle>{t("dialog.confirmDelete")}</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogDescription>
|
||||
{t("dialog.confirmDelete.desc")}
|
||||
<Trans ns="views/explore">dialog.confirmDelete.desc</Trans>
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={buttonVariants({ variant: "destructive" })}
|
||||
onClick={handleDelete}
|
||||
>
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
|
||||
@ -61,7 +61,7 @@ export default function NavItem({
|
||||
<TooltipTrigger>{content}</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent side="right">
|
||||
<p>{t("{item.title}")}</p>
|
||||
<p>{t(item.title)}</p>
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
|
||||
@ -15,7 +15,7 @@ import { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { toast } from "sonner";
|
||||
import { Toaster } from "../ui/sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type CameraInfoDialogProps = {
|
||||
camera: CameraConfig;
|
||||
@ -80,7 +80,7 @@ export default function CameraInfoDialog({
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DialogDescription>
|
||||
{t("cameras.info.streamDataFromFFPROBE")}
|
||||
<Trans ns="views/system">cameras.info.streamDataFromFFPROBE</Trans>
|
||||
</DialogDescription>
|
||||
|
||||
<div className="mb-2 p-4">
|
||||
@ -184,7 +184,7 @@ export default function CameraInfoDialog({
|
||||
aria-label="Copy"
|
||||
onClick={() => onCopyFfprobe()}
|
||||
>
|
||||
{t("button.copy")}
|
||||
{t("button.copy", { ns: "common" })}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@ -211,7 +211,7 @@ export default function CreateUserDialog({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-sm font-medium">
|
||||
{t("role.title")}
|
||||
{t("role.title", { ns: "common" })}
|
||||
</FormLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
@ -229,7 +229,7 @@ export default function CreateUserDialog({
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Shield className="h-4 w-4 text-primary" />
|
||||
<span>{t("role.admin")}</span>
|
||||
<span>{t("role.admin", { ns: "common" })}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
@ -238,13 +238,13 @@ export default function CreateUserDialog({
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<User className="h-4 w-4 text-muted-foreground" />
|
||||
<span>{t("role.viewer")}</span>
|
||||
<span>{t("role.viewer", { ns: "common" })}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription className="text-xs text-muted-foreground">
|
||||
{t("role.desc")}
|
||||
{t("role.desc", { ns: "common" })}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -261,7 +261,7 @@ export default function CreateUserDialog({
|
||||
onClick={handleCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -273,10 +273,10 @@ export default function CreateUserDialog({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -48,7 +48,7 @@ export default function DeleteUserDialog({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
@ -56,7 +56,7 @@ export default function DeleteUserDialog({
|
||||
className="flex flex-1"
|
||||
onClick={onDelete}
|
||||
>
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -321,7 +321,7 @@ export function ExportContent({
|
||||
className={`cursor-pointer p-2 text-center ${isDesktop ? "" : "w-full"}`}
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</div>
|
||||
<Button
|
||||
className={isDesktop ? "" : "w-full"}
|
||||
|
||||
@ -247,7 +247,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@ -52,7 +52,7 @@ export default function RoleChangeDialog({
|
||||
|
||||
<div className="py-6">
|
||||
<div className="mb-4 text-sm text-muted-foreground">
|
||||
{t("users.dialog.changeRole.roleInfo")}
|
||||
<Trans ns="views/settings">users.dialog.changeRole.roleInfo</Trans>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
@ -90,7 +90,7 @@ export default function RoleChangeDialog({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -99,7 +99,7 @@ export default function RoleChangeDialog({
|
||||
onClick={() => onSave(selectedRole)}
|
||||
disabled={selectedRole === currentRole}
|
||||
>
|
||||
{t("button.save")}
|
||||
{t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -35,7 +35,7 @@ export default function SaveExportOverlay({
|
||||
onClick={onCancel}
|
||||
>
|
||||
<LuX />
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
|
||||
@ -205,7 +205,7 @@ export default function SetPasswordDialog({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -214,7 +214,7 @@ export default function SetPasswordDialog({
|
||||
onClick={handleSave}
|
||||
disabled={!password || password !== confirmPassword}
|
||||
>
|
||||
{t("button.save")}
|
||||
{t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -719,7 +719,7 @@ function ObjectDetailsTab({
|
||||
aria-label="Save"
|
||||
onClick={updateDescription}
|
||||
>
|
||||
{t("button.save")}
|
||||
{t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
)}
|
||||
<TextEntryDialog
|
||||
@ -834,7 +834,9 @@ export function ObjectSnapshotTab({
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>{t("button.download")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.download", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@ -84,7 +84,9 @@ export default function RestartDialog({
|
||||
<AlertDialogTitle>{t("restart.title")}</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleRestart}>
|
||||
{t("restart.button")}
|
||||
</AlertDialogAction>
|
||||
|
||||
@ -33,7 +33,7 @@ import {
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type SearchFilterDialogProps = {
|
||||
config?: FrigateConfig;
|
||||
@ -176,7 +176,7 @@ export default function SearchFilterDialog({
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
aria-label="Reset filters to default values"
|
||||
@ -196,7 +196,7 @@ export default function SearchFilterDialog({
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -691,14 +691,14 @@ export function SnapshotClipFilterContent({
|
||||
aria-label="Yes"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.yes")}
|
||||
{t("button.yes", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="no"
|
||||
aria-label="No"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.no")}
|
||||
{t("button.no", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
@ -732,7 +732,9 @@ export function SnapshotClipFilterContent({
|
||||
side="left"
|
||||
sideOffset={5}
|
||||
>
|
||||
{t("features.submittedToFrigatePlus.tips")}
|
||||
<Trans ns="components/filter">
|
||||
features.submittedToFrigatePlus.tips
|
||||
</Trans>
|
||||
</TooltipContent>
|
||||
)}
|
||||
</Tooltip>
|
||||
@ -767,14 +769,14 @@ export function SnapshotClipFilterContent({
|
||||
aria-label="Yes"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.yes")}
|
||||
{t("button.yes", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="no"
|
||||
aria-label="No"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.no")}
|
||||
{t("button.no", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
@ -822,14 +824,14 @@ export function SnapshotClipFilterContent({
|
||||
aria-label="Yes"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.yes")}
|
||||
{t("button.yes", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
value="no"
|
||||
aria-label="No"
|
||||
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
|
||||
>
|
||||
{t("button.no")}
|
||||
{t("button.no", { ns: "common" })}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
@ -91,10 +91,10 @@ export default function TextEntryDialog({
|
||||
/>
|
||||
<DialogFooter className="pt-4">
|
||||
<Button type="button" onClick={() => setOpen(false)}>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button variant="select" type="submit">
|
||||
{t("button.save")}
|
||||
{t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@ -31,7 +31,7 @@ import useSWR from "swr";
|
||||
import { LuCheck, LuExternalLink, LuInfo, LuX } from "react-icons/lu";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LiveStreamMetadata } from "@/types/live";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type CameraStreamingDialogProps = {
|
||||
camera: string;
|
||||
@ -173,7 +173,9 @@ export function CameraStreamingDialog({
|
||||
cameraName: camera.replaceAll("_", " "),
|
||||
})}
|
||||
</DialogTitle>
|
||||
<DialogDescription>{t("group.camera.setting.desc")}</DialogDescription>
|
||||
<DialogDescription>
|
||||
<Trans ns="components/camera">group.camera.setting.desc</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col space-y-8">
|
||||
{!isRestreamed && (
|
||||
@ -190,7 +192,9 @@ export function CameraStreamingDialog({
|
||||
<PopoverTrigger asChild>
|
||||
<div className="cursor-pointer p-0">
|
||||
<LuInfo className="size-4" />
|
||||
<span className="sr-only">{t("button.info")}</span>
|
||||
<span className="sr-only">
|
||||
{t("button.info", { ns: "common" })}
|
||||
</span>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 text-xs">
|
||||
@ -247,7 +251,9 @@ export function CameraStreamingDialog({
|
||||
<PopoverTrigger asChild>
|
||||
<div className="cursor-pointer p-0">
|
||||
<LuInfo className="size-4" />
|
||||
<span className="sr-only">{t("button.info")}</span>
|
||||
<span className="sr-only">
|
||||
{t("button.info", { ns: "common" })}
|
||||
</span>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 text-xs">
|
||||
@ -355,7 +361,7 @@ export function CameraStreamingDialog({
|
||||
aria-label="Cancel"
|
||||
onClick={handleCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -367,10 +373,10 @@ export function CameraStreamingDialog({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -22,7 +22,7 @@ import { Toaster } from "../ui/sonner";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LuExternalLink } from "react-icons/lu";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type MotionMaskEditPaneProps = {
|
||||
polygons?: Polygon[];
|
||||
@ -232,7 +232,9 @@ export default function MotionMaskEditPane({
|
||||
: t("masksAndZones.motionMasks.add")}
|
||||
</Heading>
|
||||
<div className="my-3 space-y-3 text-sm text-muted-foreground">
|
||||
<p>{t("masksAndZones.motionMasks.context")}</p>
|
||||
<p>
|
||||
<Trans ns="views/settings">masksAndZones.motionMasks.context</Trans>
|
||||
</p>
|
||||
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -324,7 +326,7 @@ export default function MotionMaskEditPane({
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -336,10 +338,10 @@ export default function MotionMaskEditPane({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -365,7 +365,7 @@ export default function ObjectMaskEditPane({
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -377,10 +377,10 @@ export default function ObjectMaskEditPane({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -319,7 +319,9 @@ export default function PolygonItem({
|
||||
}}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t("button.edit")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.edit", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
@ -332,7 +334,9 @@ export default function PolygonItem({
|
||||
onClick={() => handleCopyCoordinates(index)}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t("button.copyCoordinates")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.copyCoordinates", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
@ -346,7 +350,9 @@ export default function PolygonItem({
|
||||
onClick={() => !isLoading && setDeleteDialogOpen(true)}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t("button.delete")}</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -29,7 +29,7 @@ import { toast } from "sonner";
|
||||
import { flattenPoints, interpolatePoints } from "@/utils/canvasUtil";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { getAttributeLabels } from "@/utils/iconUtil";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type ZoneEditPaneProps = {
|
||||
polygons?: Polygon[];
|
||||
@ -558,7 +558,9 @@ export default function ZoneEditPane({
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
{t("masksAndZones.zones.inertia.desc")}
|
||||
<Trans ns="views/settings">
|
||||
masksAndZones.zones.inertia.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -579,7 +581,9 @@ export default function ZoneEditPane({
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
{t("masksAndZones.zones.loiteringTime.desc")}
|
||||
<Trans ns="views/settings">
|
||||
masksAndZones.zones.loiteringTime.desc
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -808,7 +812,7 @@ export default function ZoneEditPane({
|
||||
aria-label="Cancel"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -820,10 +824,10 @@ export default function ZoneEditPane({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -431,7 +431,7 @@ export function DateRangePicker({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("button.apply")}
|
||||
{t("button.apply", { ns: "common"})}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
@ -442,7 +442,7 @@ export function DateRangePicker({
|
||||
variant="ghost"
|
||||
aria-label="Reset"
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common"})}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -125,14 +125,16 @@ function Exports() {
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
|
||||
<AlertDialogCancel>
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<Button
|
||||
className="text-white"
|
||||
aria-label="Delete Export"
|
||||
variant="destructive"
|
||||
onClick={() => onHandleDelete()}
|
||||
>
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
|
||||
@ -96,7 +96,7 @@ export default function EventView({
|
||||
pullLatestData,
|
||||
updateFilter,
|
||||
}: EventViewProps) {
|
||||
const { t } = useTranslation(["views/event"]);
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
const contentRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
@ -472,7 +472,7 @@ function DetectionReview({
|
||||
setSelectedReviews,
|
||||
pullLatestData,
|
||||
}: DetectionReviewProps) {
|
||||
const { t } = useTranslation(["views/event"]);
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
|
||||
const reviewTimelineRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -870,7 +870,7 @@ function MotionReview({
|
||||
motionOnly = false,
|
||||
onOpenRecording,
|
||||
}: MotionReviewProps) {
|
||||
const { t } = useTranslation(["views/event"]);
|
||||
const { t } = useTranslation(["views/events"]);
|
||||
const segmentDuration = 30;
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
|
||||
@ -696,8 +696,8 @@ export default function DraggableGridLayout({
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{fullscreen
|
||||
? t("button.exitFullscreen")
|
||||
: t("button.fullscreen")}
|
||||
? t("button.exitFullscreen", { ns: "common" })
|
||||
: t("button.fullscreen", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</>
|
||||
|
||||
@ -436,7 +436,9 @@ export default function LiveCameraView({
|
||||
>
|
||||
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && (
|
||||
<div className="text-primary">{t("button.back")}</div>
|
||||
<div className="text-primary">
|
||||
{t("button.back", { ns: "common" })}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
@ -458,7 +460,9 @@ export default function LiveCameraView({
|
||||
>
|
||||
<LuHistory className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && (
|
||||
<div className="text-primary">{t("button.history")}</div>
|
||||
<div className="text-primary">
|
||||
{t("button.history", { ns: "common" })}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
@ -479,7 +483,7 @@ export default function LiveCameraView({
|
||||
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && (
|
||||
<div className="text-secondary-foreground">
|
||||
{t("button.back")}
|
||||
{t("button.back", { ns: "common" })}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
@ -491,7 +495,9 @@ export default function LiveCameraView({
|
||||
Icon={fullscreen ? FaCompress : FaExpand}
|
||||
isActive={fullscreen}
|
||||
title={
|
||||
fullscreen ? t("button.close") : t("button.fullscreen")
|
||||
fullscreen
|
||||
? t("button.close", { ns: "common" })
|
||||
: t("button.fullscreen", { ns: "common" })
|
||||
}
|
||||
onClick={toggleFullscreen}
|
||||
/>
|
||||
@ -502,7 +508,11 @@ export default function LiveCameraView({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={LuPictureInPicture}
|
||||
isActive={pip}
|
||||
title={pip ? t("button.close") : t("button.pictureInPicture")}
|
||||
title={
|
||||
pip
|
||||
? t("button.close", { ns: "common" })
|
||||
: t("button.pictureInPicture", { ns: "common" })
|
||||
}
|
||||
onClick={() => {
|
||||
if (!pip) {
|
||||
setPip(true);
|
||||
@ -1101,7 +1111,9 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={enabledState == "ON" ? LuPower : LuPowerOff}
|
||||
isActive={enabledState == "ON"}
|
||||
title={`${enabledState == "ON" ? "Disable" : "Enable"} Camera`}
|
||||
title={
|
||||
enabledState == "ON" ? t("camera.disable") : t("camera.enable")
|
||||
}
|
||||
onClick={() => sendEnabled(enabledState == "ON" ? "OFF" : "ON")}
|
||||
disabled={false}
|
||||
/>
|
||||
@ -1110,7 +1122,9 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
|
||||
isActive={detectState == "ON"}
|
||||
title={`${detectState == "ON" ? "Disable" : "Enable"} Detect`}
|
||||
title={
|
||||
detectState == "ON" ? t("detect.disable") : t("detect.enable")
|
||||
}
|
||||
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
|
||||
disabled={!cameraEnabled}
|
||||
/>
|
||||
@ -1119,7 +1133,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
|
||||
isActive={recordState == "ON"}
|
||||
title={`${recordState == "ON" ? "Disable" : "Enable"} Recording`}
|
||||
title={
|
||||
recordState == "ON"
|
||||
? t("recording.disable")
|
||||
: t("recording.enable")
|
||||
}
|
||||
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
|
||||
disabled={!cameraEnabled}
|
||||
/>
|
||||
@ -1128,7 +1146,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
|
||||
isActive={snapshotState == "ON"}
|
||||
title={`${snapshotState == "ON" ? "Disable" : "Enable"} Snapshots`}
|
||||
title={
|
||||
snapshotState == "ON"
|
||||
? t("snapshots.disable")
|
||||
: t("snapshots.enable")
|
||||
}
|
||||
onClick={() => sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")}
|
||||
disabled={!cameraEnabled}
|
||||
/>
|
||||
@ -1138,7 +1160,11 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={audioState == "ON" ? LuEar : LuEarOff}
|
||||
isActive={audioState == "ON"}
|
||||
title={`${audioState == "ON" ? "Disable" : "Enable"} Audio Detect`}
|
||||
title={
|
||||
audioState == "ON"
|
||||
? t("audioDetect.disable")
|
||||
: t("audioDetect.enable")
|
||||
}
|
||||
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
|
||||
disabled={!cameraEnabled}
|
||||
/>
|
||||
@ -1151,7 +1177,11 @@ function FrigateCameraFeatures({
|
||||
autotrackingState == "ON" ? TbViewfinder : TbViewfinderOff
|
||||
}
|
||||
isActive={autotrackingState == "ON"}
|
||||
title={`${autotrackingState == "ON" ? "Disable" : "Enable"} Autotracking`}
|
||||
title={
|
||||
autotrackingState == "ON"
|
||||
? t("autotracking.disable")
|
||||
: t("autotracking.enable")
|
||||
}
|
||||
onClick={() =>
|
||||
sendAutotracking(autotrackingState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
@ -1189,11 +1219,13 @@ function FrigateCameraFeatures({
|
||||
<div className="flex flex-col gap-5 p-4">
|
||||
{!isRestreamed && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label>{t("streaming", { ns: "components/dialog" })}</Label>
|
||||
<Label>
|
||||
{t("streaming.label", { ns: "components/dialog" })}
|
||||
</Label>
|
||||
<div className="flex flex-row items-center gap-1 text-sm text-muted-foreground">
|
||||
<LuX className="size-4 text-danger" />
|
||||
<div>
|
||||
{t("streaming.restreaming.disabled", {
|
||||
{t("streaming.restreaming.NotEnabled", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
</div>
|
||||
@ -1398,7 +1430,9 @@ function FrigateCameraFeatures({
|
||||
className="mx-0 cursor-pointer text-primary"
|
||||
htmlFor="showstats"
|
||||
>
|
||||
{t("streaming.showStats", { ns: "components/dialog" })}
|
||||
{t("streaming.showStats.label", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
</Label>
|
||||
<Switch
|
||||
className="ml-1"
|
||||
|
||||
@ -564,8 +564,8 @@ export default function LiveDashboardView({
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{fullscreen
|
||||
? t("button.exitFullscreen")
|
||||
: t("button.fullscreen")}
|
||||
? t("button.exitFullscreen", { ns: "common" })
|
||||
: t("button.fullscreen", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@ -401,7 +401,9 @@ export function RecordingView({
|
||||
>
|
||||
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && (
|
||||
<div className="text-primary">{t("button.back")}</div>
|
||||
<div className="text-primary">
|
||||
{t("button.back", { ns: "common" })}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@ -256,7 +256,9 @@ export default function AuthenticationView() {
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{t("role." + user.role || "viewer")}
|
||||
{t("role." + (user.role || "viewer"), {
|
||||
ns: "common",
|
||||
})}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
@ -280,7 +282,7 @@ export default function AuthenticationView() {
|
||||
>
|
||||
<LuUserCog className="size-3.5" />
|
||||
<span className="ml-1.5 hidden sm:inline-block">
|
||||
{t("role.title")}
|
||||
{t("role.title", { ns: "common" })}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
@ -326,7 +328,7 @@ export default function AuthenticationView() {
|
||||
>
|
||||
<HiTrash className="size-3.5" />
|
||||
<span className="ml-1.5 hidden sm:inline-block">
|
||||
{t("button.delete")}
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
|
||||
@ -27,11 +27,11 @@ import { LuExternalLink } from "react-icons/lu";
|
||||
import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
import { MdCircle } from "react-icons/md";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { Trans } from "react-i18next";
|
||||
import { t } from "i18next";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useAlertsState, useDetectionsState, useEnabledState } from "@/api/ws";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
type CameraSettingsViewProps = {
|
||||
selectedCamera: string;
|
||||
@ -47,7 +47,6 @@ export default function CameraSettingsView({
|
||||
selectedCamera,
|
||||
setUnsavedChanges,
|
||||
}: CameraSettingsViewProps) {
|
||||
const { t } = useTranslation(["views/settings"]);
|
||||
const { data: config, mutate: updateConfig } =
|
||||
useSWR<FrigateConfig>("config");
|
||||
|
||||
@ -82,7 +81,7 @@ export default function CameraSettingsView({
|
||||
.map((label) => t(label, { ns: "objects" }))
|
||||
.join(", ")
|
||||
: "";
|
||||
}, [cameraConfig, t]);
|
||||
}, [cameraConfig]);
|
||||
|
||||
const detectionsLabels = useMemo(() => {
|
||||
return cameraConfig?.review.detections.labels
|
||||
@ -90,7 +89,7 @@ export default function CameraSettingsView({
|
||||
.map((label) => t(label, { ns: "objects" }))
|
||||
.join(", ")
|
||||
: "";
|
||||
}, [cameraConfig, t]);
|
||||
}, [cameraConfig]);
|
||||
|
||||
// form
|
||||
|
||||
@ -191,7 +190,7 @@ export default function CameraSettingsView({
|
||||
setIsLoading(false);
|
||||
});
|
||||
},
|
||||
[updateConfig, setIsLoading, selectedCamera, cameraConfig, t],
|
||||
[updateConfig, setIsLoading, selectedCamera, cameraConfig],
|
||||
);
|
||||
|
||||
const onCancel = useCallback(() => {
|
||||
@ -260,13 +259,13 @@ export default function CameraSettingsView({
|
||||
<Toaster position="top-center" closeButton={true} />
|
||||
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0">
|
||||
<Heading as="h3" className="my-2">
|
||||
{t("camera.title")}
|
||||
<Trans ns="views/settings">camera.title</Trans>
|
||||
</Heading>
|
||||
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
|
||||
<Heading as="h4" className="my-2">
|
||||
{t("camera.streams.title")}
|
||||
<Trans ns="views/settings">camera.streams.title</Trans>
|
||||
</Heading>
|
||||
|
||||
<div className="flex flex-row items-center">
|
||||
@ -279,16 +278,18 @@ export default function CameraSettingsView({
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="camera-enabled">{t("button.enabled")}</Label>
|
||||
<Label htmlFor="camera-enabled">
|
||||
<Trans>button.enabled</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-sm text-muted-foreground">
|
||||
{t("camera.streams.desc")}
|
||||
<Trans ns="views/settings">camera.streams.desc</Trans>
|
||||
</div>
|
||||
<Separator className="mb-2 mt-4 flex bg-secondary" />
|
||||
|
||||
<Heading as="h4" className="my-2">
|
||||
{t("camera.review.title")}
|
||||
<Trans ns="views/settings">camera.review.title</Trans>
|
||||
</Heading>
|
||||
|
||||
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 space-y-3 text-sm text-primary-variant">
|
||||
@ -303,7 +304,7 @@ export default function CameraSettingsView({
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="alerts-enabled">
|
||||
{t("camera.review.alerts")}
|
||||
<Trans ns="views/settings">camera.review.alerts</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
@ -319,12 +320,12 @@ export default function CameraSettingsView({
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="detections-enabled">
|
||||
{t("camera.review.detections")}
|
||||
<Trans ns="views/settings">camera.review.detections</Trans>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-sm text-muted-foreground">
|
||||
{t("camera.review.desc")}
|
||||
<Trans ns="views/settings">camera.review.desc</Trans>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -332,12 +333,16 @@ export default function CameraSettingsView({
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
|
||||
<Heading as="h4" className="my-2">
|
||||
{t("camera.reviewClassification.title")}
|
||||
<Trans ns="views/settings">camera.reviewClassification.title</Trans>
|
||||
</Heading>
|
||||
|
||||
<div className="max-w-6xl">
|
||||
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>{t("camera.reviewClassification.desc")}</p>
|
||||
<p>
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/review"
|
||||
@ -345,7 +350,9 @@ export default function CameraSettingsView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
{t("camera.reviewClassification.readTheDocumentation")}{" "}
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.readTheDocumentation
|
||||
</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -374,13 +381,15 @@ export default function CameraSettingsView({
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<FormLabel className="flex flex-row items-center text-base">
|
||||
{t("camera.review.alerts")}
|
||||
<Trans ns="views/settings">
|
||||
camera.review.alerts
|
||||
</Trans>
|
||||
<MdCircle className="ml-3 size-2 text-severity_alert" />
|
||||
</FormLabel>
|
||||
<FormDescription>
|
||||
{t(
|
||||
"camera.reviewClassification.selectAlertsZones",
|
||||
)}
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.selectAlertsZones
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</div>
|
||||
<div className="max-w-md rounded-lg bg-secondary p-4 md:max-w-full">
|
||||
@ -429,7 +438,9 @@ export default function CameraSettingsView({
|
||||
</>
|
||||
) : (
|
||||
<div className="font-normal text-destructive">
|
||||
{t("camera.reviewClassification.noDefinedZones")}
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.noDefinedZones
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
<FormMessage />
|
||||
@ -450,6 +461,7 @@ export default function CameraSettingsView({
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
ns: "views/settings",
|
||||
},
|
||||
)
|
||||
: t("camera.reviewClassification.objectAlertsTips", {
|
||||
@ -457,6 +469,7 @@ export default function CameraSettingsView({
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
ns: "views/settings",
|
||||
})}
|
||||
</div>
|
||||
</FormItem>
|
||||
@ -472,14 +485,16 @@ export default function CameraSettingsView({
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<FormLabel className="flex flex-row items-center text-base">
|
||||
{t("camera.review.detections")}
|
||||
<Trans ns="views/settings">
|
||||
camera.review.detections
|
||||
</Trans>
|
||||
<MdCircle className="ml-3 size-2 text-severity_detection" />
|
||||
</FormLabel>
|
||||
{selectDetections && (
|
||||
<FormDescription>
|
||||
{t(
|
||||
"camera.reviewClassification.selectDetectionsZones",
|
||||
)}
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.selectDetectionsZones
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
)}
|
||||
</div>
|
||||
@ -542,9 +557,9 @@ export default function CameraSettingsView({
|
||||
htmlFor="select-detections"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
{t(
|
||||
"camera.reviewClassification.limitDetections",
|
||||
)}
|
||||
<Trans ns="views/settings">
|
||||
camera.reviewClassification.limitDetections
|
||||
</Trans>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -553,51 +568,58 @@ export default function CameraSettingsView({
|
||||
|
||||
<div className="text-sm">
|
||||
{watchedDetectionsZones &&
|
||||
watchedDetectionsZones.length > 0
|
||||
? !selectDetections
|
||||
? t(
|
||||
"camera.reviewClassification.zoneObjectDetectionsTips",
|
||||
{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"camera.reviewClassification.zoneObjectDetectionsTips.notSelectDetections",
|
||||
{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
},
|
||||
)
|
||||
: t(
|
||||
"camera.reviewClassification.objectDetectionsTips",
|
||||
{
|
||||
watchedDetectionsZones.length > 0 ? (
|
||||
!selectDetections ? (
|
||||
<Trans
|
||||
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips"
|
||||
values={{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
},
|
||||
)}
|
||||
}}
|
||||
ns="views/settings"
|
||||
></Trans>
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips.notSelectDetections"
|
||||
values={{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones
|
||||
.map((zone) =>
|
||||
capitalizeFirstLetter(zone).replaceAll(
|
||||
"_",
|
||||
" ",
|
||||
),
|
||||
)
|
||||
.join(", "),
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
}}
|
||||
ns="views/settings"
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey="camera.reviewClassification.objectDetectionsTips"
|
||||
values={{
|
||||
detectionsLabels,
|
||||
cameraName: capitalizeFirstLetter(
|
||||
cameraConfig?.name ?? "",
|
||||
).replaceAll("_", " "),
|
||||
}}
|
||||
ns="views/settings"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
@ -612,7 +634,7 @@ export default function CameraSettingsView({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
<Trans>button.cancel</Trans>
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -624,10 +646,12 @@ export default function CameraSettingsView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>
|
||||
<Trans>button.saving</Trans>
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
<Trans>button.save</Trans>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -21,7 +21,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LuExternalLink } from "react-icons/lu";
|
||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type MotionTunerViewProps = {
|
||||
selectedCamera: string;
|
||||
@ -236,7 +236,11 @@ export default function MotionTunerView({
|
||||
{t("motionDetectionTuner.contourArea")}
|
||||
</Label>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>{t("motionDetectionTuner.contourArea.desc")}</p>
|
||||
<p>
|
||||
<Trans ns="views/settings">
|
||||
motionDetectionTuner.contourArea.desc
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between">
|
||||
@ -264,7 +268,9 @@ export default function MotionTunerView({
|
||||
{t("motionDetectionTuner.improveContrast")}
|
||||
</Label>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t("motionDetectionTuner.improveContrast.desc")}
|
||||
<Trans ns="views/settings">
|
||||
motionDetectionTuner.improveContrast.desc
|
||||
</Trans>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
@ -285,7 +291,7 @@ export default function MotionTunerView({
|
||||
aria-label="Reset"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -297,10 +303,10 @@ export default function MotionTunerView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -478,7 +478,7 @@ export default function NotificationView({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
{t("button.cancel")}
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -490,10 +490,10 @@ export default function NotificationView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -250,7 +250,7 @@ export default function ObjectSettingsView({
|
||||
<div className="cursor-pointer p-0">
|
||||
<LuInfo className="size-4" />
|
||||
<span className="sr-only">
|
||||
{t("button.info")}
|
||||
{t("button.info", { ns: "common" })}
|
||||
</span>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
} from "@/components/ui/select";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type ExploreSettingsViewProps = {
|
||||
setUnsavedChanges: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
@ -172,7 +172,9 @@ export default function ExploreSettingsView({
|
||||
</Heading>
|
||||
<div className="max-w-6xl">
|
||||
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>{t("explore.semanticSearch.desc")}</p>
|
||||
<p>
|
||||
<Trans ns="views/settings">explore.semanticSearch.desc</Trans>
|
||||
</p>
|
||||
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -200,7 +202,9 @@ export default function ExploreSettingsView({
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="enabled">{t("button.enabled")}</Label>
|
||||
<Label htmlFor="enabled">
|
||||
{t("button.enabled", { ns: "common" })}
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
@ -221,7 +225,9 @@ export default function ExploreSettingsView({
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 text-sm text-muted-foreground">
|
||||
{t("explore.semanticSearch.reindexOnStartup.desc")}
|
||||
<Trans ns="views/settings">
|
||||
explore.semanticSearch.reindexOnStartup.desc
|
||||
</Trans>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col space-y-6">
|
||||
@ -230,10 +236,22 @@ export default function ExploreSettingsView({
|
||||
{t("explore.semanticSearch.modelSize.label")}
|
||||
</div>
|
||||
<div className="space-y-1 text-sm text-muted-foreground">
|
||||
<p>{t("explore.semanticSearch.modelSize.desc")}</p>
|
||||
<p>
|
||||
<Trans ns="views/settings">
|
||||
explore.semanticSearch.modelSize.desc
|
||||
</Trans>
|
||||
</p>
|
||||
<ul className="list-disc pl-5 text-sm">
|
||||
<li>{t("explore.semanticSearch.modelSize.small.desc")}</li>
|
||||
<li>{t("explore.semanticSearch.modelSize.large.desc")}</li>
|
||||
<li>
|
||||
<Trans ns="views/settings">
|
||||
explore.semanticSearch.modelSize.small.desc
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans ns="views/settings">
|
||||
explore.semanticSearch.modelSize.large.desc
|
||||
</Trans>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -271,7 +289,7 @@ export default function ExploreSettingsView({
|
||||
|
||||
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
|
||||
<Button className="flex flex-1" aria-label="Reset" onClick={onCancel}>
|
||||
{t("button.reset")}
|
||||
{t("button.reset", { ns: "common" })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -283,10 +301,10 @@ export default function ExploreSettingsView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>{t("button.saving")}</span>
|
||||
<span>{t("button.saving", { ns: "common" })}</span>
|
||||
</div>
|
||||
) : (
|
||||
t("button.save")
|
||||
t("button.save", { ns: "common" })
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user