mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-10-05 07:27:11 +08:00
feat: add i18n (translation/localization) (#16877)
* Translation module init * Add more i18n keys * fix: fix string wrong * refactor: use namespace translation file * chore: add more translation key * fix: fix some page name error * refactor: change Trans tag for t function * chore: fix some key not work * chore: fix SearchFilterDialog i18n key error Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * chore: fix en i18n file filter missing some keys * chore: add some i18n keys * chore: add more i18n keys again * feat: add search page i18n * feat: add explore model i18n keys * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/menu/GeneralSettings.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * feat: add more live i18n keys * feat: add more search setting i18n keys * fix: remove some comment * fix: fix some setting page url error * Update web/src/views/settings/SearchSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * fix: add system missing keys * fix: update password update i18n keys * chore: remove outdate translation.json file * fix: fix exploreSettings error * chore: add object setting i18n keys * Update web/src/views/recording/RecordingView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/public/locales/en/components/filter.json Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/components/overlay/ExportDialog.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * feat: add more i18n keys * fix: fix motionDetectionTuner html node * feat: add more page i18n keys * fix: cameraStream i18n keys error * feat: add Player i18n keys * feat: add more toast i18n keys * feat: change explore setting name * feat: add more document title i18n keys * feat: add more search i18n keys * fix: fix accessDenied i18n keys error * chore: add objectType i18n * chore: add inputWithTags i18n * chore: add SearchFilterDialog i18n * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Update web/src/views/settings/ObjectSettingsView.tsx Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * chore: add some missing i18n keys * chore: remove most import { t } from "i18next"; --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
This commit is contained in:
@@ -23,9 +23,11 @@ import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
import { LuExternalLink, LuInfo } from "react-icons/lu";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import DebugDrawingLayer from "@/components/overlay/DebugDrawingLayer";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
type ObjectSettingsViewProps = {
|
||||
selectedCamera?: string;
|
||||
@@ -38,6 +40,8 @@ const emptyObject = Object.freeze({});
|
||||
export default function ObjectSettingsView({
|
||||
selectedCamera,
|
||||
}: ObjectSettingsViewProps) {
|
||||
const { t } = useTranslation(["views/settings"]);
|
||||
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -45,80 +49,45 @@ export default function ObjectSettingsView({
|
||||
const DEBUG_OPTIONS = [
|
||||
{
|
||||
param: "bbox",
|
||||
title: "Bounding boxes",
|
||||
description: "Show bounding boxes around tracked objects",
|
||||
title: t("debug.boundingBoxes.title"),
|
||||
description: t("debug.boundingBoxes.desc"),
|
||||
info: (
|
||||
<>
|
||||
<p className="mb-2">
|
||||
<strong>Object Bounding Box Colors</strong>
|
||||
<strong>{t("debug.boundingBoxes.colors.label")}</strong>
|
||||
</p>
|
||||
<ul className="list-disc space-y-1 pl-5">
|
||||
<li>
|
||||
At startup, different colors will be assigned to each object label
|
||||
</li>
|
||||
<li>
|
||||
A dark blue thin line indicates that object is not detected at
|
||||
this current point in time
|
||||
</li>
|
||||
<li>
|
||||
A gray thin line indicates that object is detected as being
|
||||
stationary
|
||||
</li>
|
||||
<li>
|
||||
A thick line indicates that object is the subject of autotracking
|
||||
(when enabled)
|
||||
</li>
|
||||
<Trans ns="views/settings">debug.boundingBoxes.colors.info</Trans>
|
||||
</ul>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
param: "timestamp",
|
||||
title: "Timestamp",
|
||||
description: "Overlay a timestamp on the image",
|
||||
title: t("debug.timestamp.title"),
|
||||
description: t("debug.timestamp.desc"),
|
||||
},
|
||||
{
|
||||
param: "zones",
|
||||
title: "Zones",
|
||||
description: "Show an outline of any defined zones",
|
||||
title: t("debug.zones.title"),
|
||||
description: t("debug.zones.desc"),
|
||||
},
|
||||
{
|
||||
param: "mask",
|
||||
title: "Motion masks",
|
||||
description: "Show motion mask polygons",
|
||||
title: t("debug.mask.title"),
|
||||
description: t("debug.mask.desc"),
|
||||
},
|
||||
{
|
||||
param: "motion",
|
||||
title: "Motion boxes",
|
||||
description: "Show boxes around areas where motion is detected",
|
||||
info: (
|
||||
<>
|
||||
<p className="mb-2">
|
||||
<strong>Motion Boxes</strong>
|
||||
</p>
|
||||
<p>
|
||||
Red boxes will be overlaid on areas of the frame where motion is
|
||||
currently being detected
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
title: t("debug.motion.title"),
|
||||
description: t("debug.motion.desc"),
|
||||
info: <Trans ns="views/settings">debug.motion.tips</Trans>,
|
||||
},
|
||||
{
|
||||
param: "regions",
|
||||
title: "Regions",
|
||||
description:
|
||||
"Show a box of the region of interest sent to the object detector",
|
||||
info: (
|
||||
<>
|
||||
<p className="mb-2">
|
||||
<strong>Region Boxes</strong>
|
||||
</p>
|
||||
<p>
|
||||
Bright green boxes will be overlaid on areas of interest in the
|
||||
frame that are being sent to the object detector.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
title: t("debug.regions.title"),
|
||||
description: t("debug.regions.desc"),
|
||||
info: <Trans ns="views/settings">debug.regions.tips</Trans>,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -167,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 />;
|
||||
@@ -179,25 +148,19 @@ export default function ObjectSettingsView({
|
||||
<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 md:w-3/12">
|
||||
<Heading as="h3" className="my-2">
|
||||
Debug
|
||||
{t("debug.title")}
|
||||
</Heading>
|
||||
<div className="mb-5 space-y-3 text-sm text-muted-foreground">
|
||||
<p>
|
||||
Frigate uses your detectors{" "}
|
||||
{config
|
||||
? "(" +
|
||||
Object.keys(config?.detectors)
|
||||
.map((detector) => capitalizeFirstLetter(detector))
|
||||
.join(",") +
|
||||
")"
|
||||
: ""}{" "}
|
||||
to detect objects in your camera's video stream.
|
||||
</p>
|
||||
<p>
|
||||
Debugging view shows a real-time view of tracked objects and their
|
||||
statistics. The object list shows a time-delayed summary of detected
|
||||
objects.
|
||||
{t("debug.detectorDesc", {
|
||||
detectors: config
|
||||
? Object.keys(config?.detectors)
|
||||
.map((detector) => capitalizeFirstLetter(detector))
|
||||
.join(",")
|
||||
: "",
|
||||
})}
|
||||
</p>
|
||||
<p>{t("debug.desc")}</p>
|
||||
</div>
|
||||
{config?.cameras[cameraConfig.name]?.webui_url && (
|
||||
<div className="mb-5 text-sm text-muted-foreground">
|
||||
@@ -217,8 +180,10 @@ export default function ObjectSettingsView({
|
||||
|
||||
<Tabs defaultValue="debug" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="debug">Debugging</TabsTrigger>
|
||||
<TabsTrigger value="objectlist">Object List</TabsTrigger>
|
||||
<TabsTrigger value="debug">{t("debug.debugging")}</TabsTrigger>
|
||||
<TabsTrigger value="objectlist">
|
||||
{t("debug.objectList")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="debug">
|
||||
<div className="flex w-full flex-col space-y-6">
|
||||
@@ -277,21 +242,20 @@ export default function ObjectSettingsView({
|
||||
className="mb-0 cursor-pointer capitalize text-primary"
|
||||
htmlFor="debugdraw"
|
||||
>
|
||||
Object Shape Filter Drawing
|
||||
{t("debug.objectShapeFilterDrawing.title")}
|
||||
</Label>
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="cursor-pointer p-0">
|
||||
<LuInfo className="size-4" />
|
||||
<span className="sr-only">Info</span>
|
||||
<span className="sr-only">
|
||||
{t("button.info", { ns: "common" })}
|
||||
</span>
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 text-sm">
|
||||
Enable this option to draw a rectangle on the
|
||||
camera image to show its area and ratio. These
|
||||
values can then be used to set object shape filter
|
||||
parameters in your config.
|
||||
{t("debug.objectShapeFilterDrawing.tips")}
|
||||
<div className="mt-2 flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/object_filters#object-shape"
|
||||
@@ -299,7 +263,7 @@ export default function ObjectSettingsView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
Read the documentation{" "}
|
||||
{t("debug.objectShapeFilterDrawing.document")}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@@ -307,8 +271,7 @@ export default function ObjectSettingsView({
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
Draw a rectangle on the image to view area and ratio
|
||||
details
|
||||
{t("debug.objectShapeFilterDrawing.desc")}
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
@@ -364,6 +327,7 @@ type ObjectListProps = {
|
||||
};
|
||||
|
||||
function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
const { t } = useTranslation(["views/settings"]);
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
const colormap = useMemo(() => {
|
||||
@@ -409,7 +373,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
<div className="text-md mr-2 w-1/3">
|
||||
<div className="flex flex-col items-end justify-end">
|
||||
<p className="mb-1.5 text-sm text-primary-variant">
|
||||
Score
|
||||
{t("debug.objectShapeFilterDrawing.score")}
|
||||
</p>
|
||||
{obj.score
|
||||
? (obj.score * 100).toFixed(1).toString()
|
||||
@@ -420,7 +384,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
<div className="text-md mr-2 w-1/3">
|
||||
<div className="flex flex-col items-end justify-end">
|
||||
<p className="mb-1.5 text-sm text-primary-variant">
|
||||
Ratio
|
||||
{t("debug.objectShapeFilterDrawing.ratio")}
|
||||
</p>
|
||||
{obj.ratio ? obj.ratio.toFixed(2).toString() : "-"}
|
||||
</div>
|
||||
@@ -428,7 +392,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
<div className="text-md mr-2 w-1/3">
|
||||
<div className="flex flex-col items-end justify-end">
|
||||
<p className="mb-1.5 text-sm text-primary-variant">
|
||||
Area
|
||||
{t("debug.objectShapeFilterDrawing.area")}
|
||||
</p>
|
||||
{obj.area ? (
|
||||
<>
|
||||
@@ -457,7 +421,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="p-3 text-center">No objects</div>
|
||||
<div className="p-3 text-center">{t("debug.noObjects")}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
Reference in New Issue
Block a user