mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-05 13:07:44 +03:00
feat: add more document title i18n keys
This commit is contained in:
parent
18ff446465
commit
29087cfcbc
@ -123,6 +123,8 @@
|
||||
"live": "Live",
|
||||
"live.allCameras": "All Cameras",
|
||||
"live.cameras": "Cameras",
|
||||
"live.cameras.count_one": "{{count}} Camera",
|
||||
"live.cameras.count_other": "{{count}} Cameras",
|
||||
"review": "Review",
|
||||
"explore": "Explore",
|
||||
"export": "Export",
|
||||
@ -156,5 +158,16 @@
|
||||
"next": "Next",
|
||||
"next.label": "Go to next page",
|
||||
"more": "More pages"
|
||||
}
|
||||
},
|
||||
"accessDefined": {
|
||||
"documentTitle": "Access Defined - Frigate",
|
||||
"title": "Access Defined",
|
||||
"desc": "You don't have permission to view this page."
|
||||
},
|
||||
"notFound": {
|
||||
"documentTitle": "Not Found - Frigate",
|
||||
"title": "404",
|
||||
"desc": "Page not found"
|
||||
},
|
||||
"selectItem": "Select {{item}}"
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "Config Editor - Frigate",
|
||||
"configEditor": "Config Editor",
|
||||
"copyConfig": "Copy Config",
|
||||
"saveAndRestart": "Save & Restart",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "Explore - Frigate",
|
||||
"generativeAI": "Generative AI",
|
||||
"exploreIsUnavailable": {
|
||||
"title": "Explore is Unavailable",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "Face Library - Frigate",
|
||||
"uploadFaceImage": {
|
||||
"title": "Upload Face Image",
|
||||
"desc": "Upload an image to scan for faces and include for {{pageToggle}}"
|
||||
|
||||
@ -1,7 +1,17 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"default": "Settings - Frigate",
|
||||
"authentication": "Authentication Settings - Frigate",
|
||||
"camera": "Camera Settings - Frigate",
|
||||
"classification": "Classification Settings - Frigate",
|
||||
"masksAndZones": "Mask and Zone Editor - Frigate",
|
||||
"motionTuner": "Motion Tuner - Frigate",
|
||||
"object": "Object Settings - Frigate",
|
||||
"general": "General Settings - Frigate"
|
||||
},
|
||||
"menu": {
|
||||
"uiSettings": "UI Settings",
|
||||
"exploreSettings": "Explore Settings",
|
||||
"classificationSettings": "Classification Settings",
|
||||
"cameraSettings": "Camera Settings",
|
||||
"masksAndZones": "Masks / Zones",
|
||||
"motionTuner": "Motion Tuner",
|
||||
@ -9,6 +19,16 @@
|
||||
"users": "Users",
|
||||
"notifications": "Notifications"
|
||||
},
|
||||
"dialog": {
|
||||
"unsavedChanges": {
|
||||
"title": "You have unsaved changes.",
|
||||
"desc": "Do you want to save your changes before continuing?"
|
||||
}
|
||||
},
|
||||
"cameraSetting": {
|
||||
"camera": "Camera",
|
||||
"noCamera": "No Camera"
|
||||
},
|
||||
"general": {
|
||||
"title": "General Settings",
|
||||
"liveDashboard": {
|
||||
@ -376,7 +396,10 @@
|
||||
"desc": "Web push notifications require a secure context (<code>https://...</code>). This is a browser limitation. Access Frigate securely to use notifications.",
|
||||
"documentation": "Read the Documentation"
|
||||
},
|
||||
|
||||
"globalSettings": {
|
||||
"title": "Global Settings",
|
||||
"desc": "Temporarily suspend notifications for specific cameras on all registered devices."
|
||||
},
|
||||
"email": "Email",
|
||||
"email.placeholder": "e.g. example@email.com",
|
||||
"email.desc": "A valid email is required and will be used to notify you if there are any issues with the push service.",
|
||||
@ -386,6 +409,19 @@
|
||||
"deviceSpecific": "Device Specific Settings",
|
||||
"registerDevice": "Register This Device",
|
||||
"unregisterDevice": "Unregister This Device",
|
||||
"sendTestNotification": "Send a test notification",
|
||||
"active": "Notifications Active",
|
||||
"suspended": "Notifications suspended {{time}}",
|
||||
"suspendTime": {
|
||||
"5minutes": "Suspend for 5 minutes",
|
||||
"10minutes": "Suspend for 10 minutes",
|
||||
"30minutes": "Suspend for 30 minutes",
|
||||
"1hour": "Suspend for 1 hour",
|
||||
"12hours": "Suspend for 12 hours",
|
||||
"24hours": "Suspend for 24 hours",
|
||||
"untilRestart": "Suspend until restart"
|
||||
},
|
||||
"cancelSuspension": "Cancel Suspension",
|
||||
"toast": {
|
||||
"success": {
|
||||
"registered": "Successfully registered for notifications. Restarting Frigate is required before any notifications (including a test notification) can be sent.",
|
||||
|
||||
@ -1,4 +1,15 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"cameras": "Cameras Stats - Frigate",
|
||||
"storage": "Storage Stats - Frigate",
|
||||
"general": "General Stats - Frigate",
|
||||
"features": "Features Stats- Frigate",
|
||||
"logs": {
|
||||
"frigate": "Frigate Logs - Frigate",
|
||||
"go2rtc": "Go2RTC Logs - Frigate",
|
||||
"nginx": "Nginx Logs - Frigate"
|
||||
}
|
||||
},
|
||||
"title": "System",
|
||||
"metrics": "System metrics",
|
||||
"logs": {
|
||||
|
||||
@ -130,6 +130,8 @@
|
||||
"live": "实时监控",
|
||||
"live.allCameras": "所有摄像头",
|
||||
"live.cameras": "摄像头",
|
||||
"live.cameras.count_one": "{{count}} 个摄像头",
|
||||
"live.cameras.count_other": "{{count}} 个摄像头",
|
||||
"review": "回放",
|
||||
"explore": "探测",
|
||||
"export": "导出",
|
||||
@ -156,5 +158,16 @@
|
||||
"admin": "管理员",
|
||||
"viewer": "查看者",
|
||||
"desc": "管理员可以完全访问 Frigate UI 的所有功能。查看者则仅限于在 UI 中查看摄像头、审核项和历史录像。"
|
||||
}
|
||||
},
|
||||
"accessDefined": {
|
||||
"documentTitle": "没有权限 - Frigate",
|
||||
"title": "没有权限",
|
||||
"desc": "您没有权限查看此页面。"
|
||||
},
|
||||
"notFound": {
|
||||
"documentTitle": "没有找到页面 - Frigate",
|
||||
"title": "404",
|
||||
"desc": "页面未找到"
|
||||
},
|
||||
"selectItem": "选择 {{item}}"
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "配置编辑器 - Frigate",
|
||||
"configEditor": "配置编辑器",
|
||||
"copyConfig": "复制配置",
|
||||
"saveAndRestart": "保存并重启",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "探索 - Frigate",
|
||||
"generativeAI": "生成式 AI",
|
||||
"exploreIsUnavailable": {
|
||||
"title": "探索功能不可用",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"documentTitle": "人脸库 - Frigate",
|
||||
"uploadFaceImage": {
|
||||
"title": "上传人脸图片",
|
||||
"desc": "上传图片以扫描人脸并包含在{{pageToggle}}中"
|
||||
|
||||
@ -1,7 +1,23 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"default": "设置 - Frigate",
|
||||
"authentication": "身份验证设置 - Frigate",
|
||||
"camera": "摄像头设置 - Frigate",
|
||||
"classification": "分类设置 - Frigate",
|
||||
"masksAndZones": "遮罩和区域编辑器 - Frigate",
|
||||
"motionTuner": "运动调整器 - Frigate",
|
||||
"object": "对象设置 - Frigate",
|
||||
"general": "常规设置 - Frigate"
|
||||
},
|
||||
"dialog": {
|
||||
"unsavedChanges": {
|
||||
"title": "你有未保存的更改。",
|
||||
"desc": "是否要在继续之前保存更改?"
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"uiSettings": "界面设置",
|
||||
"exploreSettings": "搜索设置",
|
||||
"classificationSettings": "分类设置",
|
||||
"cameraSettings": "摄像头设置",
|
||||
"masksAndZones": "遮罩/ 区域",
|
||||
"motionTuner": "运动调整器",
|
||||
@ -373,6 +389,10 @@
|
||||
"desc": "Frigate 在浏览器中运行或作为 PWA 安装时,可以原生向您的设备发送推送通知。",
|
||||
"documentation": "阅读文档(英文)"
|
||||
},
|
||||
"globalSettings": {
|
||||
"title": "全局设置",
|
||||
"desc": "临时暂停所有已注册设备上特定摄像头的通知。"
|
||||
},
|
||||
"notificationUnavailable": {
|
||||
"title": "通知功能不可用",
|
||||
"desc": "网页推送通知需要安全连接(<code>https://...</code>)。这是浏览器的限制。请通过安全方式访问 Frigate 以使用通知功能。",
|
||||
@ -387,6 +407,19 @@
|
||||
"deviceSpecific": "设备专用设置",
|
||||
"registerDevice": "注册该设备",
|
||||
"unregisterDevice": "取消注册该设备",
|
||||
"sendTestNotification": "发送测试通知",
|
||||
"active": "通知已启用",
|
||||
"suspended": "通知已暂停 {{time}}",
|
||||
"suspendTime": {
|
||||
"5minutes": "暂停 5 分钟",
|
||||
"10minutes": "暂停 10 分钟",
|
||||
"30minutes": "暂停 30 分钟",
|
||||
"1hour": "暂停 1 小时",
|
||||
"12hours": "暂停 12 小时",
|
||||
"24hours": "暂停 24 小时",
|
||||
"untilRestart": "暂停直到重启"
|
||||
},
|
||||
"cancelSuspension": "取消暂停",
|
||||
"toast": {
|
||||
"success": {
|
||||
"registered": "已成功注册通知。需要重启 Frigate 才能发送任何通知(包括测试通知)。",
|
||||
|
||||
@ -1,4 +1,15 @@
|
||||
{
|
||||
"documentTitle": {
|
||||
"cameras": "摄像头统计 - Frigate",
|
||||
"storage": "存储统计 - Frigate",
|
||||
"general": "常规统计 - Frigate",
|
||||
"features": "功能统计 - Frigate",
|
||||
"logs": {
|
||||
"frigate": "Frigate 日志 - Frigate",
|
||||
"go2rtc": "Go2RTC 日志 - Frigate",
|
||||
"nginx": "Nginx 日志 - Frigate"
|
||||
}
|
||||
},
|
||||
"title": "系统",
|
||||
"metrics": "系统指标",
|
||||
"logs": {
|
||||
|
||||
@ -288,24 +288,22 @@ export default function ReviewCard({
|
||||
>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Confirm Delete</AlertDialogTitle>
|
||||
<AlertDialogTitle>
|
||||
{t("recording.confirmDelete.title")}
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete all recorded video associated with
|
||||
this review item?
|
||||
<br />
|
||||
<br />
|
||||
Hold the <em>Shift</em> key to bypass this dialog in the future.
|
||||
<Trans ns="components/dialog">recording.confirmDelete.desc</Trans>
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={() => setOptionsOpen(false)}>
|
||||
Cancel
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={buttonVariants({ variant: "destructive" })}
|
||||
onClick={onDelete}
|
||||
>
|
||||
Delete
|
||||
{t("button.delete", { ns: "common" })}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@ -318,7 +316,7 @@ export default function ReviewCard({
|
||||
onClick={onExport}
|
||||
>
|
||||
<FaCompactDisc className="text-secondary-foreground" />
|
||||
<div className="text-primary">Export</div>
|
||||
<div className="text-primary">{t("recording.button.export")}</div>
|
||||
</div>
|
||||
{!event.has_been_reviewed && (
|
||||
<div
|
||||
@ -326,7 +324,9 @@ export default function ReviewCard({
|
||||
onClick={onMarkAsReviewed}
|
||||
>
|
||||
<FaCircleCheck className="text-secondary-foreground" />
|
||||
<div className="text-primary">Mark as reviewed</div>
|
||||
<div className="text-primary">
|
||||
{t("recording.button.markAsReviewed")}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
@ -335,7 +335,9 @@ export default function ReviewCard({
|
||||
>
|
||||
<HiTrash className="text-secondary-foreground" />
|
||||
<div className="text-primary">
|
||||
{bypassDialogRef.current ? "Delete Now" : "Delete"}
|
||||
{bypassDialogRef.current
|
||||
? t("recording.button.deleteNow")
|
||||
: t("button.delete", { ns: "common" })}
|
||||
</div>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
|
||||
@ -44,8 +44,12 @@ export function CamerasFilterButton({
|
||||
if (!selectedCameras || selectedCameras.length == 0) {
|
||||
return t("menu.live.allCameras", { ns: "common" });
|
||||
}
|
||||
|
||||
return `${selectedCameras.includes("birdseye") ? selectedCameras.length - 1 : selectedCameras.length} Camera${selectedCameras.length !== 1 ? "s" : ""}`;
|
||||
return t("menu.live.cameras.count", {
|
||||
count: selectedCameras.includes("birdseye")
|
||||
? selectedCameras.length - 1
|
||||
: selectedCameras.length,
|
||||
ns: "common",
|
||||
});
|
||||
}, [selectedCameras, t]);
|
||||
|
||||
// ui
|
||||
|
||||
@ -1,21 +1,20 @@
|
||||
import Heading from "@/components/ui/heading";
|
||||
import { t } from "i18next";
|
||||
import { useEffect } from "react";
|
||||
import { FaExclamationTriangle } from "react-icons/fa";
|
||||
|
||||
export default function AccessDenied() {
|
||||
useEffect(() => {
|
||||
document.title = "Access Denied - Frigate";
|
||||
document.title = t("accessDefined.documentTitle");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen flex-col items-center justify-center text-center">
|
||||
<FaExclamationTriangle className="mb-4 size-8" />
|
||||
<Heading as="h2" className="mb-2">
|
||||
Access Denied
|
||||
{t("accessDefined.title")}
|
||||
</Heading>
|
||||
<p className="text-primary-variant">
|
||||
You don't have permission to view this page.
|
||||
</p>
|
||||
<p className="text-primary-variant">{t("accessDefined.desc")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -29,8 +29,8 @@ function ConfigEditor() {
|
||||
const apiHost = useApiHost();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Config Editor - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle");
|
||||
}, [t]);
|
||||
|
||||
const { data: config } = useSWR<string>("config/raw");
|
||||
|
||||
|
||||
@ -38,8 +38,8 @@ export default function FaceLibrary() {
|
||||
// title
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Face Library - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle");
|
||||
}, [t]);
|
||||
|
||||
const [page, setPage] = useState<string>();
|
||||
const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100);
|
||||
|
||||
@ -49,8 +49,8 @@ function Logs() {
|
||||
const lastFetchedIndexRef = useRef(-1);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${logService[0].toUpperCase()}${logService.substring(1)} Logs - Frigate`;
|
||||
}, [logService]);
|
||||
document.title = t("documentTitle.logs." + logService);
|
||||
}, [logService, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (tabsRef.current) {
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
import Heading from "@/components/ui/heading";
|
||||
import { t } from "i18next";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function NoMatch() {
|
||||
useEffect(() => {
|
||||
document.title = "Not Found - Frigate";
|
||||
document.title = t("notFound.documentTitle");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading as="h2">404</Heading>
|
||||
<p>Page not found</p>
|
||||
<Heading as="h2">{t("notFound.title")}</Heading>
|
||||
<p>{t("notFound.desc")}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -185,8 +185,8 @@ export default function Settings() {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Settings - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.default");
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<div className="flex size-full flex-col p-2">
|
||||
@ -215,7 +215,10 @@ export default function Settings() {
|
||||
className={`flex scroll-mx-10 items-center justify-between gap-2 ${page == "uiSettings" ? "last:mr-20" : ""} ${pageToggle == item ? "" : "*:text-muted-foreground"}`}
|
||||
value={item}
|
||||
data-nav-item={item}
|
||||
aria-label={`Select ${item}`}
|
||||
aria-label={t("selectItem", {
|
||||
item: t("menu." + item),
|
||||
ns: "common",
|
||||
})}
|
||||
>
|
||||
<div className="capitalize">{t("menu." + item)}</div>
|
||||
</ToggleGroupItem>
|
||||
@ -284,17 +287,19 @@ export default function Settings() {
|
||||
>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>You have unsaved changes.</AlertDialogTitle>
|
||||
<AlertDialogTitle>
|
||||
{t("dialog.unsavedChanges.title")}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to save your changes before continuing?
|
||||
{t("dialog.unsavedChanges.desc")}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={() => handleDialog(false)}>
|
||||
Cancel
|
||||
{t("button.cancel", { ns: "common" })}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={() => handleDialog(true)}>
|
||||
Save
|
||||
{t("button.save", { ns: "common" })}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@ -319,6 +324,8 @@ function CameraSelectButton({
|
||||
cameraEnabledStates,
|
||||
currentPage,
|
||||
}: CameraSelectButtonProps) {
|
||||
const { t } = useTranslation(["views/settings"]);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
if (!allCameras.length) {
|
||||
@ -334,7 +341,7 @@ function CameraSelectButton({
|
||||
<FaVideo className="text-background dark:text-primary" />
|
||||
<div className="hidden text-background dark:text-primary md:block">
|
||||
{selectedCamera == undefined
|
||||
? "No Camera"
|
||||
? t("cameraSetting.noCamera")
|
||||
: selectedCamera.replaceAll("_", " ")}
|
||||
</div>
|
||||
</Button>
|
||||
@ -344,7 +351,7 @@ function CameraSelectButton({
|
||||
{isMobile && (
|
||||
<>
|
||||
<DropdownMenuLabel className="flex justify-center">
|
||||
Camera
|
||||
{t("cameraSetting.camera")}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
|
||||
@ -12,7 +12,6 @@ import Logo from "@/components/Logo";
|
||||
import useOptimisticState from "@/hooks/use-optimistic-state";
|
||||
import CameraMetrics from "@/views/system/CameraMetrics";
|
||||
import { useHashState } from "@/hooks/use-overlay-state";
|
||||
import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import FeatureMetrics from "@/views/system/FeatureMetrics";
|
||||
@ -54,9 +53,9 @@ function System() {
|
||||
|
||||
useEffect(() => {
|
||||
if (pageToggle) {
|
||||
document.title = `${capitalizeFirstLetter(pageToggle)} Stats - Frigate`;
|
||||
document.title = t("documentTitle." + pageToggle);
|
||||
}
|
||||
}, [pageToggle]);
|
||||
}, [pageToggle, t]);
|
||||
|
||||
// stats collection
|
||||
|
||||
|
||||
@ -36,11 +36,12 @@ export default function ExploreView({
|
||||
setSimilaritySearch,
|
||||
onSelectSearch,
|
||||
}: ExploreViewProps) {
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
// title
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Explore - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle");
|
||||
}, [t]);
|
||||
|
||||
// data
|
||||
|
||||
|
||||
@ -49,8 +49,8 @@ export default function AuthenticationView() {
|
||||
>();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Authentication Settings - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.authentication");
|
||||
}, [t]);
|
||||
|
||||
const onSavePassword = useCallback(
|
||||
(user: string, password: string) => {
|
||||
|
||||
@ -193,8 +193,8 @@ export default function ClassificationSettingsView({
|
||||
}, [changedValue]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Classification Settings - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.classification");
|
||||
}, [t]);
|
||||
|
||||
if (!config) {
|
||||
return <ActivityIndicator />;
|
||||
|
||||
@ -185,8 +185,8 @@ export default function MasksAndZonesView({
|
||||
setActivePolygonIndex(undefined);
|
||||
setHoveredPolygonIndex(null);
|
||||
setUnsavedChanges(false);
|
||||
document.title = "Mask and Zone Editor - Frigate";
|
||||
}, [allPolygons, setUnsavedChanges]);
|
||||
document.title = t("documentTitle.masksAndZones");
|
||||
}, [allPolygons, setUnsavedChanges, t]);
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
setAllPolygons([...(editingPolygons ?? [])]);
|
||||
@ -425,8 +425,8 @@ export default function MasksAndZonesView({
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Mask and Zone Editor - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.masksAndZones");
|
||||
}, [t]);
|
||||
|
||||
if (!cameraConfig && !selectedCamera) {
|
||||
return <ActivityIndicator />;
|
||||
|
||||
@ -179,8 +179,8 @@ export default function MotionTunerView({
|
||||
}, [changedValue, selectedCamera]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Motion Tuner - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.motionTuner");
|
||||
}, [t]);
|
||||
|
||||
if (!cameraConfig && !selectedCamera) {
|
||||
return <ActivityIndicator />;
|
||||
|
||||
@ -560,10 +560,10 @@ export default function NotificationView({
|
||||
</Button>
|
||||
{registration != null && registration.active && (
|
||||
<Button
|
||||
aria-label="Send a test notification"
|
||||
aria-label={t("notification.sendTestNotification")}
|
||||
onClick={() => sendTestNotification("notification_test")}
|
||||
>
|
||||
Send a test notification
|
||||
{t("notification.sendTestNotification")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@ -573,14 +573,11 @@ export default function NotificationView({
|
||||
<div className="space-y-3">
|
||||
<Separator className="my-2 flex bg-secondary" />
|
||||
<Heading as="h4" className="my-2">
|
||||
Global Settings
|
||||
{t("notification.globalSettings.title")}
|
||||
</Heading>
|
||||
<div className="max-w-xl">
|
||||
<div className="mb-5 mt-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>
|
||||
Temporarily suspend notifications for specific cameras
|
||||
on all registered devices.
|
||||
</p>
|
||||
<p>{t("notification.globalSettings.desc")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -680,12 +677,13 @@ export function CameraNotificationSwitch({
|
||||
|
||||
{!isSuspended ? (
|
||||
<div className="flex flex-row items-center gap-2 text-sm text-success">
|
||||
Notifications Active
|
||||
{t("notification.active")}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-row items-center gap-2 text-sm text-danger">
|
||||
Notifications suspended{" "}
|
||||
{formatSuspendedUntil(notificationSuspendUntil)}
|
||||
{t("notification.suspended", {
|
||||
time: formatSuspendedUntil(notificationSuspendUntil),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -698,13 +696,27 @@ export function CameraNotificationSwitch({
|
||||
<SelectValue placeholder="Suspend" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="5">Suspend for 5 minutes</SelectItem>
|
||||
<SelectItem value="10">Suspend for 10 minutes</SelectItem>
|
||||
<SelectItem value="30">Suspend for 30 minutes</SelectItem>
|
||||
<SelectItem value="60">Suspend for 1 hour</SelectItem>
|
||||
<SelectItem value="840">Suspend for 12 hours</SelectItem>
|
||||
<SelectItem value="1440">Suspend for 24 hours</SelectItem>
|
||||
<SelectItem value="off">Suspend until restart</SelectItem>
|
||||
<SelectItem value="5">
|
||||
{t("notification.suspendTime.5minutes")}
|
||||
</SelectItem>
|
||||
<SelectItem value="10">
|
||||
{t("notification.suspendTime.10minutes")}
|
||||
</SelectItem>
|
||||
<SelectItem value="30">
|
||||
{t("notification.suspendTime.30minutes")}
|
||||
</SelectItem>
|
||||
<SelectItem value="60">
|
||||
{t("notification.suspendTime.1hour")}
|
||||
</SelectItem>
|
||||
<SelectItem value="840">
|
||||
{t("notification.suspendTime.12hour")}
|
||||
</SelectItem>
|
||||
<SelectItem value="1440">
|
||||
{t("notification.suspendTime.24hour")}
|
||||
</SelectItem>
|
||||
<SelectItem value="off">
|
||||
{t("notification.suspendTime.untilRestart")}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
) : (
|
||||
@ -713,7 +725,7 @@ export function CameraNotificationSwitch({
|
||||
size="sm"
|
||||
onClick={handleCancelSuspension}
|
||||
>
|
||||
Cancel Suspension
|
||||
{t("notification.cancelSuspension")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -136,8 +136,8 @@ export default function ObjectSettingsView({
|
||||
}, [options, optionsLoaded]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Object Settings - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.object");
|
||||
}, [t]);
|
||||
|
||||
if (!cameraConfig) {
|
||||
return <ActivityIndicator />;
|
||||
|
||||
@ -86,8 +86,8 @@ export default function UiSettingsView() {
|
||||
}, [config, t]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "General Settings - Frigate";
|
||||
}, []);
|
||||
document.title = t("documentTitle.general");
|
||||
}, [t]);
|
||||
|
||||
// settings
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user