mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-06 05:27:44 +03:00
chore: add some i18n keys
This commit is contained in:
parent
2dc6283727
commit
b35fbef325
@ -8,6 +8,24 @@
|
||||
"button": "Force Reload Now"
|
||||
}
|
||||
},
|
||||
"explore": {
|
||||
"plus": {
|
||||
"submitToPlus": {
|
||||
"label": "Submit To Frigate+",
|
||||
"desc": "Objects in locations you want to avoid are not false positives. Submitting them as false positives will confuse the model."
|
||||
},
|
||||
"review": {
|
||||
"true_one": "This is a {{label}}",
|
||||
"true_other": "This is an {{label}}",
|
||||
"false_one": "This is not a {{label}}",
|
||||
"false_other": "This is not an {{label}}",
|
||||
"state.submitted": "Submitted"
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
"viewInHistory": "View in History"
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"time": {
|
||||
"fromTimeline": "Select from Timeline",
|
||||
|
||||
@ -7,6 +7,19 @@
|
||||
"object_lifecycle": "object lifecycle"
|
||||
},
|
||||
"details": {
|
||||
"item": {
|
||||
"title": "Review Item Details",
|
||||
"desc": "Review item details",
|
||||
"button": {
|
||||
"share": "Share this review item",
|
||||
"viewInExplore": "View in Explore"
|
||||
},
|
||||
"tips": {
|
||||
"mismatch_one": "{{count}} unavailable object was detected and included in this review item. Those objects either did not qualify as an alert or detection or have already been cleaned up/deleted.",
|
||||
"mismatch_other": "{{count}} unavailable objects were detected and included in this review item. Those objects either did not qualify as an alert or detection or have already been cleaned up/deleted.",
|
||||
"hasMissingObjects": "Adjust your configuration if you want Frigate to save tracked objects for the following labels: <em>{{objects}}</em>"
|
||||
}
|
||||
},
|
||||
"label": "Label",
|
||||
"editSubLable": "Edit sub label",
|
||||
"editSubLable.desc": "Enter a new sub label for this {{label}}",
|
||||
@ -14,7 +27,9 @@
|
||||
"topScore": "Top Score",
|
||||
"topScore.info": "The top score is the highest median score for the tracked object, so this may differ from the score shown on the search result thumbnail.",
|
||||
"estimatedSpeed": "Estimated Speed",
|
||||
"objects": "Objects",
|
||||
"camera": "Camera",
|
||||
"zones": "Zones",
|
||||
"timestamp": "Timestamp",
|
||||
"button": {
|
||||
"findSimilar": "Find Similar"
|
||||
@ -52,6 +67,10 @@
|
||||
"submitToPlus": {
|
||||
"label": "Submit to Frigate+",
|
||||
"aria": "Submit to Frigate Plus"
|
||||
},
|
||||
"viewInHistory": {
|
||||
"label": "View in History",
|
||||
"aria": "View in History"
|
||||
}
|
||||
},
|
||||
"dialog": {
|
||||
|
||||
@ -8,6 +8,24 @@
|
||||
"button": "强制刷新"
|
||||
}
|
||||
},
|
||||
"explore": {
|
||||
"plus": {
|
||||
"submitToPlus": {
|
||||
"label": "提交至 Frigate+",
|
||||
"desc": "您希望避开的地点中的物体不应被视为误报。若将其作为误报提交,可能会导致AI模型容易混淆相关物体的识别。"
|
||||
},
|
||||
"review": {
|
||||
"true_one": "这是 {{label}}",
|
||||
"true_other": "这是 {{label}}",
|
||||
"false_one": "这不是 {{label}}",
|
||||
"false_other": "这不是 {{label}}",
|
||||
"state.submitted": "已提交"
|
||||
}
|
||||
},
|
||||
"video": {
|
||||
"viewInHistory": "在历史中查看"
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"time": {
|
||||
"fromTimeline": "从时间线选择",
|
||||
|
||||
3
web/public/locales/zh-CN/components/input.json
Normal file
3
web/public/locales/zh-CN/components/input.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@ -7,6 +7,19 @@
|
||||
"object_lifecycle": "对象生命周期"
|
||||
},
|
||||
"details": {
|
||||
"item": {
|
||||
"title": "回放项目详情",
|
||||
"desc": "回放项目详情",
|
||||
"button": {
|
||||
"share": "分享该回放",
|
||||
"viewInExplore": "在探测中查看"
|
||||
},
|
||||
"tips": {
|
||||
"mismatch_one": "检测到 {{count}} 个不可用的对象,并已包含在此审核项中。这些对象可能未达到警告或检测标准,或者已被清理/删除。",
|
||||
"mismatch_other": "检测到 {{count}} 个不可用的对象,并已包含在此审核项中。这些对象可能未达到警告或检测标准,或者已被清理/删除。",
|
||||
"hasMissingObjects": "如果希望 Frigate 保存以下标签的跟踪对象,请调整您的配置:<em>{{objects}}</em>"
|
||||
}
|
||||
},
|
||||
"label": "标签",
|
||||
"editSubLable": "编辑子标签",
|
||||
"editSubLable.desc": "为 {{label}} 输入新的子标签",
|
||||
@ -14,7 +27,9 @@
|
||||
"topScore": "最高得分",
|
||||
"topScore.info": "最高分是跟踪对象的最高中位数得分,因此可能与搜索结果缩略图上显示的得分不同。",
|
||||
"estimatedSpeed": "预计速度",
|
||||
"objects": "对象",
|
||||
"camera": "摄像头",
|
||||
"zones": "区域",
|
||||
"timestamp": "时间",
|
||||
"button": {
|
||||
"findSimilar": "查找相似项"
|
||||
@ -52,6 +67,10 @@
|
||||
"submitToPlus": {
|
||||
"label": "提交至 Frigate+",
|
||||
"aria": "提交至 Frigate Plus"
|
||||
},
|
||||
"viewInHistory": {
|
||||
"label": "在历史记录中查看",
|
||||
"aria": "在历史记录中查看"
|
||||
}
|
||||
},
|
||||
"dialog": {
|
||||
|
||||
@ -42,7 +42,7 @@ import { DownloadVideoButton } from "@/components/button/DownloadVideoButton";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import { LuSearch } from "react-icons/lu";
|
||||
import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||
import { t } from "i18next";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type ReviewDetailDialogProps = {
|
||||
review?: ReviewSegment;
|
||||
@ -52,6 +52,7 @@ export default function ReviewDetailDialog({
|
||||
review,
|
||||
setReview,
|
||||
}: ReviewDetailDialogProps) {
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
@ -96,8 +97,8 @@ export default function ReviewDetailDialog({
|
||||
const formattedDate = useFormattedTimestamp(
|
||||
review?.start_time ?? 0,
|
||||
config?.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampWithYear.24hour")
|
||||
: t("time.formattedTimestampWithYear"),
|
||||
? t("time.formattedTimestampWithYear.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampWithYear", { ns: "common" }),
|
||||
config?.ui.timezone,
|
||||
);
|
||||
|
||||
@ -178,8 +179,10 @@ export default function ReviewDetailDialog({
|
||||
<span tabIndex={0} className="sr-only" />
|
||||
{pane == "overview" && (
|
||||
<Header className="justify-center">
|
||||
<Title>Review Item Details</Title>
|
||||
<Description className="sr-only">Review item details</Description>
|
||||
<Title>{t("details.item.title")}</Title>
|
||||
<Description className="sr-only">
|
||||
{t("details.item.desc")}
|
||||
</Description>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute flex gap-2 lg:flex-col",
|
||||
@ -200,7 +203,9 @@ export default function ReviewDetailDialog({
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>Share this review item</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("details.item.button.share")}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
@ -212,7 +217,9 @@ export default function ReviewDetailDialog({
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>Download</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.download", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@ -223,19 +230,25 @@ export default function ReviewDetailDialog({
|
||||
<div className="flex w-full flex-row">
|
||||
<div className="flex w-full flex-col gap-3">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="text-sm text-primary/40">Camera</div>
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.camera")}
|
||||
</div>
|
||||
<div className="text-sm capitalize">
|
||||
{review.camera.replaceAll("_", " ")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="text-sm text-primary/40">Timestamp</div>
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.timestamp")}
|
||||
</div>
|
||||
<div className="text-sm">{formattedDate}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-col items-center gap-2">
|
||||
<div className="flex w-full flex-col gap-1.5 lg:pr-8">
|
||||
<div className="text-sm text-primary/40">Objects</div>
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.objects")}
|
||||
</div>
|
||||
<div className="scrollbar-container flex max-h-32 flex-col items-start gap-2 overflow-y-auto text-sm capitalize">
|
||||
{events?.map((event) => {
|
||||
return (
|
||||
@ -261,7 +274,9 @@ export default function ReviewDetailDialog({
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>View in Explore</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("details.item.button.viewInExplore")}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@ -271,7 +286,9 @@ export default function ReviewDetailDialog({
|
||||
</div>
|
||||
{review.data.zones.length > 0 && (
|
||||
<div className="scrollbar-container flex max-h-32 w-full flex-col gap-1.5">
|
||||
<div className="text-sm text-primary/40">Zones</div>
|
||||
<div className="text-sm text-primary/40">
|
||||
{t("details.zones")}
|
||||
</div>
|
||||
<div className="flex flex-col items-start gap-2 text-sm capitalize">
|
||||
{review.data.zones.map((zone) => {
|
||||
return (
|
||||
@ -295,18 +312,23 @@ export default function ReviewDetailDialog({
|
||||
(events?.length ?? 0) -
|
||||
(review?.data.detections.length ?? 0),
|
||||
);
|
||||
const objectLabel =
|
||||
detectedCount === 1 ? "object was" : "objects were";
|
||||
|
||||
return `${detectedCount} unavailable ${objectLabel} detected and included in this review item.`;
|
||||
})()}{" "}
|
||||
Those objects either did not qualify as an alert or detection
|
||||
or have already been cleaned up/deleted.
|
||||
return t("details.item.tips.mismatch", {
|
||||
count: detectedCount,
|
||||
});
|
||||
})()}
|
||||
{missingObjects.length > 0 && (
|
||||
<div className="mt-2">
|
||||
Adjust your configuration if you want Frigate to save
|
||||
tracked objects for the following labels:{" "}
|
||||
{missingObjects.join(", ")}
|
||||
<Trans
|
||||
ns="views/explore"
|
||||
values={{
|
||||
objects: missingObjects
|
||||
.map((x) => t(x, { ns: "objects" }))
|
||||
.join(", "),
|
||||
}}
|
||||
>
|
||||
details.item.tips.hasMissingObjects
|
||||
</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -349,6 +371,8 @@ function EventItem({
|
||||
setSelectedEvent,
|
||||
setUpload,
|
||||
}: EventItemProps) {
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
|
||||
const { data: config } = useSWR<FrigateConfig>("config", {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
@ -418,7 +442,9 @@ function EventItem({
|
||||
</Chip>
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Download</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.download", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{event.has_snapshot &&
|
||||
@ -436,7 +462,9 @@ function EventItem({
|
||||
<FrigatePlusIcon className="size-4 text-white" />
|
||||
</Chip>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Submit to Frigate+</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("itemMenu.submitToPlus.label")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
@ -453,7 +481,9 @@ function EventItem({
|
||||
<FaArrowsRotate className="size-4 text-white" />
|
||||
</Chip>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>View Object Lifecycle</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("itemMenu.viewObjectLifecycle.label")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
@ -471,7 +501,9 @@ function EventItem({
|
||||
<FaImages className="size-4 text-white" />
|
||||
</Chip>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Find Similar</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("itemMenu.findSimilar.label")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -578,8 +578,8 @@ function ObjectDetailsTab({
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
{averageEstimatedSpeed}{" "}
|
||||
{config?.ui.unit_system == "imperial"
|
||||
? t("unit.speed.mph")
|
||||
: t("unit.speed.kph")}{" "}
|
||||
? t("unit.speed.mph", { ns: "common" })
|
||||
: t("unit.speed.kph", { ns: "common" })}{" "}
|
||||
{velocityAngle != undefined && (
|
||||
<span className="text-primary/40">
|
||||
<FaArrowRight
|
||||
@ -624,7 +624,7 @@ function ObjectDetailsTab({
|
||||
/>
|
||||
{config?.semantic_search.enabled && search.data.type == "object" && (
|
||||
<Button
|
||||
aria-label="Find similar tracked objects"
|
||||
aria-label={t("itemMenu.findSimilar.aria")}
|
||||
onClick={() => {
|
||||
setSearch(undefined);
|
||||
|
||||
@ -633,7 +633,7 @@ function ObjectDetailsTab({
|
||||
}
|
||||
}}
|
||||
>
|
||||
Find Similar
|
||||
{t("itemMenu.findSimilar.label")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@ -855,12 +855,10 @@ export function ObjectSnapshotTab({
|
||||
"text-lg font-semibold leading-none tracking-tight"
|
||||
}
|
||||
>
|
||||
Submit To Frigate+
|
||||
{t("explore.submitToPlus.label")}
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Objects in locations you want to avoid are not false
|
||||
positives. Submitting them as false positives will
|
||||
confuse the model.
|
||||
{t("explore.submitToPlus.desc")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -875,9 +873,13 @@ export function ObjectSnapshotTab({
|
||||
onSubmitToPlus(false);
|
||||
}}
|
||||
>
|
||||
This is{" "}
|
||||
{/^[aeiou]/i.test(search?.label || "") ? "an" : "a"}{" "}
|
||||
{search?.label}
|
||||
{/^[aeiou]/i.test(search?.label || "")
|
||||
? t("explore.plus.review.true_other", {
|
||||
label: search?.label,
|
||||
})
|
||||
: t("explore.plus.review.true_one", {
|
||||
label: search?.label,
|
||||
})}
|
||||
</Button>
|
||||
<Button
|
||||
className="text-white"
|
||||
@ -888,9 +890,13 @@ export function ObjectSnapshotTab({
|
||||
onSubmitToPlus(true);
|
||||
}}
|
||||
>
|
||||
This is not{" "}
|
||||
{/^[aeiou]/i.test(search?.label || "") ? "an" : "a"}{" "}
|
||||
{search?.label}
|
||||
{/^[aeiou]/i.test(search?.label || "")
|
||||
? t("explore.plus.review.false_other", {
|
||||
label: search?.label,
|
||||
})
|
||||
: t("explore.plus.review.false_one", {
|
||||
label: search?.label,
|
||||
})}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
@ -898,7 +904,7 @@ export function ObjectSnapshotTab({
|
||||
{state == "submitted" && (
|
||||
<div className="flex flex-row items-center justify-center gap-2">
|
||||
<FaCheckCircle className="text-success" />
|
||||
Submitted
|
||||
{t("explore.plus.review.state.submitted")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -917,6 +923,7 @@ type VideoTabProps = {
|
||||
};
|
||||
|
||||
export function VideoTab({ search }: VideoTabProps) {
|
||||
const { t } = useTranslation(["views/explore"]);
|
||||
const navigate = useNavigate();
|
||||
const { data: reviewItem } = useSWR<ReviewSegment>([
|
||||
`review/event/${search.id}`,
|
||||
@ -951,7 +958,9 @@ export function VideoTab({ search }: VideoTabProps) {
|
||||
</Chip>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>View in History</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("itemMenu.viewInHistory.label")}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
@ -966,7 +975,9 @@ export function VideoTab({ search }: VideoTabProps) {
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>Download</TooltipContent>
|
||||
<TooltipContent>
|
||||
{t("button.download", { ns: "common" })}
|
||||
</TooltipContent>
|
||||
</TooltipPortal>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user