mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 17:12:16 +03:00
Refactor and clean up i18n (#17198)
* clean up i18n * fix key * fix key
This commit is contained in:
@@ -134,7 +134,7 @@ export default function LiveCameraView({
|
||||
fullscreen,
|
||||
toggleFullscreen,
|
||||
}: LiveCameraViewProps) {
|
||||
const { t } = useTranslation(["views/live"]);
|
||||
const { t } = useTranslation(["views/live", "components/dialog"]);
|
||||
const navigate = useNavigate();
|
||||
const { isPortrait } = useMobileOrientation();
|
||||
const mainRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -530,7 +530,13 @@ export default function LiveCameraView({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={mic ? FaMicrophone : FaMicrophoneSlash}
|
||||
isActive={mic}
|
||||
title={`${mic ? "Disable" : "Enable"} Two Way Talk`}
|
||||
title={
|
||||
(mic
|
||||
? t("button.disable", { ns: "common" })
|
||||
: t("button.enable", { ns: "common" })) +
|
||||
" " +
|
||||
t("button.twoWayTalk", { ns: "common" })
|
||||
}
|
||||
onClick={() => {
|
||||
setMic(!mic);
|
||||
if (!mic && !audio) {
|
||||
@@ -546,7 +552,13 @@ export default function LiveCameraView({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={audio ? GiSpeaker : GiSpeakerOff}
|
||||
isActive={audio ?? false}
|
||||
title={`${audio ? "Disable" : "Enable"} Camera Audio`}
|
||||
title={
|
||||
(audio
|
||||
? t("button.disable", { ns: "common" })
|
||||
: t("button.enable", { ns: "common" })) +
|
||||
" " +
|
||||
t("button.cameraAudio", { ns: "common" })
|
||||
}
|
||||
onClick={() => setAudio(!audio)}
|
||||
disabled={!cameraEnabled}
|
||||
/>
|
||||
@@ -931,7 +943,7 @@ function PtzControlPanel({
|
||||
}
|
||||
|
||||
function OnDemandRetentionMessage({ camera }: { camera: CameraConfig }) {
|
||||
const { t } = useTranslation(["views/live"]);
|
||||
const { t } = useTranslation(["views/live", "views/events"]);
|
||||
const rankMap = { all: 0, motion: 1, active_objects: 2 };
|
||||
const getValidMode = (retain?: { mode?: string }): keyof typeof rankMap => {
|
||||
const mode = retain?.mode;
|
||||
@@ -946,10 +958,7 @@ function OnDemandRetentionMessage({ camera }: { camera: CameraConfig }) {
|
||||
? recordRetainMode
|
||||
: alertsRetainMode;
|
||||
|
||||
const source =
|
||||
effectiveRetainMode === recordRetainMode
|
||||
? t("camera", { ns: "views/events" })
|
||||
: t("alerts", { ns: "views/events" });
|
||||
const source = effectiveRetainMode === recordRetainMode ? "camera" : "alerts";
|
||||
|
||||
return effectiveRetainMode !== "all" ? (
|
||||
<div>
|
||||
@@ -1007,7 +1016,7 @@ function FrigateCameraFeatures({
|
||||
supports2WayTalk,
|
||||
cameraEnabled,
|
||||
}: FrigateCameraFeaturesProps) {
|
||||
const { t } = useTranslation(["views/live"]);
|
||||
const { t } = useTranslation(["views/live", "components/dialog"]);
|
||||
|
||||
const { payload: detectState, send: sendDetect } = useDetectState(
|
||||
camera.name,
|
||||
@@ -1243,7 +1252,7 @@ function FrigateCameraFeatures({
|
||||
<div className="flex flex-row items-center gap-1 text-sm text-muted-foreground">
|
||||
<LuX className="size-4 text-danger" />
|
||||
<div>
|
||||
{t("streaming.restreaming.NotEnabled", {
|
||||
{t("streaming.restreaming.disabled", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
</div>
|
||||
@@ -1257,7 +1266,7 @@ function FrigateCameraFeatures({
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 text-xs">
|
||||
{t("streaming.restreaming.desc", {
|
||||
{t("streaming.restreaming.desc.title", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
<div className="mt-2 flex items-center text-primary">
|
||||
@@ -1267,9 +1276,12 @@ function FrigateCameraFeatures({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
{t("streaming.restreaming.readTheDocumentation", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
{t(
|
||||
"streaming.restreaming.desc.readTheDocumentation",
|
||||
{
|
||||
ns: "components/dialog",
|
||||
},
|
||||
)}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@@ -1334,7 +1346,7 @@ function FrigateCameraFeatures({
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 text-xs">
|
||||
{t("stream.audio.tips")}
|
||||
{t("stream.audio.tips.title")}
|
||||
<div className="mt-2 flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/live"
|
||||
@@ -1462,12 +1474,16 @@ function FrigateCameraFeatures({
|
||||
/>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("streaming.showStats.desc", { ns: "components/dialog" })}
|
||||
{t("streaming.showStats.desc", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between text-sm font-medium leading-none">
|
||||
{t("streaming.debugView", { ns: "components/dialog" })}
|
||||
{t("streaming.debugView", {
|
||||
ns: "components/dialog",
|
||||
})}
|
||||
<LuExternalLink
|
||||
onClick={() =>
|
||||
navigate(`/settings?page=debug&camera=${camera.name}`)
|
||||
@@ -1558,7 +1574,7 @@ function FrigateCameraFeatures({
|
||||
<div className="mt-3 flex flex-col gap-5">
|
||||
{!isRestreamed && (
|
||||
<div className="flex flex-col gap-2 p-2">
|
||||
<Label>{t("streaming", { ns: "components/dialog" })}</Label>
|
||||
<Label>{t("streaming.title", { 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>
|
||||
@@ -1649,7 +1665,7 @@ function FrigateCameraFeatures({
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-52 text-xs">
|
||||
{t("stream.audio.tips")}
|
||||
{t("stream.audio.tips.title")}
|
||||
<div className="mt-2 flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/live"
|
||||
@@ -1717,7 +1733,7 @@ function FrigateCameraFeatures({
|
||||
</div>
|
||||
<Button
|
||||
className={`flex items-center gap-2.5 rounded-lg`}
|
||||
aria-label="Reset the stream"
|
||||
aria-label={t("stream.lowBandwidth.resetStream")}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setLowBandwidth(false)}
|
||||
|
||||
@@ -417,7 +417,7 @@ export function RecordingView({
|
||||
<FaVideo className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && (
|
||||
<div className="text-primary">
|
||||
{t("menu.live", { ns: "common" })}
|
||||
{t("menu.live.title", { ns: "common" })}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
@@ -199,7 +199,7 @@ export default function AuthenticationView() {
|
||||
<div className="mb-5 flex flex-row items-center justify-between gap-2">
|
||||
<div className="flex flex-col items-start">
|
||||
<Heading as="h3" className="my-2">
|
||||
{t("users.management")}
|
||||
{t("users.management.title")}
|
||||
</Heading>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("users.management.desc")}
|
||||
|
||||
@@ -166,7 +166,7 @@ export default function CameraSettingsView({
|
||||
updateConfig();
|
||||
} else {
|
||||
toast.error(
|
||||
t("toast.save.error", {
|
||||
t("toast.save.error.title", {
|
||||
errorMessage: res.statusText,
|
||||
ns: "common",
|
||||
}),
|
||||
@@ -182,7 +182,7 @@ export default function CameraSettingsView({
|
||||
error.response?.data?.detail ||
|
||||
"Unknown error";
|
||||
toast.error(
|
||||
t("toast.save.error", {
|
||||
t("toast.save.error.title", {
|
||||
errorMessage,
|
||||
ns: "common",
|
||||
}),
|
||||
@@ -574,7 +574,7 @@ export default function CameraSettingsView({
|
||||
watchedDetectionsZones.length > 0 ? (
|
||||
!selectDetections ? (
|
||||
<Trans
|
||||
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips"
|
||||
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips.text"
|
||||
values={{
|
||||
detectionsLabels,
|
||||
zone: watchedDetectionsZones
|
||||
|
||||
@@ -162,9 +162,12 @@ export default function ClassificationSettingsView({
|
||||
error.response?.data?.message ||
|
||||
error.response?.data?.detail ||
|
||||
"Unknown error";
|
||||
toast.error(t("toast.save.error", { errorMessage, ns: "common" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
toast.error(
|
||||
t("toast.save.error.title", { errorMessage, ns: "common" }),
|
||||
{
|
||||
position: "top-center",
|
||||
},
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
@@ -319,7 +322,11 @@ export default function ClassificationSettingsView({
|
||||
className="cursor-pointer"
|
||||
value={size}
|
||||
>
|
||||
{t("classification.semanticSearch.modelSize." + size)}
|
||||
{t(
|
||||
"classification.semanticSearch.modelSize." +
|
||||
size +
|
||||
".title",
|
||||
)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
|
||||
@@ -502,7 +502,7 @@ export default function MasksAndZonesView({
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>{t("masksAndZones.zones.desc")}</p>
|
||||
<p>{t("masksAndZones.zones.desc.title")}</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/zones"
|
||||
@@ -568,7 +568,7 @@ export default function MasksAndZonesView({
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>{t("masksAndZones.motionMasks.desc")}</p>
|
||||
<p>{t("masksAndZones.motionMasks.desc.title")}</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/masks#motion-masks"
|
||||
@@ -638,7 +638,7 @@ export default function MasksAndZonesView({
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
<div className="my-2 flex flex-col gap-2 text-sm text-primary-variant">
|
||||
<p>{t("masksAndZones.objectMasks.desc")}</p>
|
||||
<p>{t("masksAndZones.objectMasks.desc.title")}</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
to="https://docs.frigate.video/configuration/masks#object-filter-masks"
|
||||
@@ -646,7 +646,9 @@ export default function MasksAndZonesView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
{t("masksAndZones.objectMasks.documentation")}{" "}
|
||||
{t(
|
||||
"masksAndZones.objectMasks.desc.documentation",
|
||||
)}{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -126,7 +126,7 @@ export default function MotionTunerView({
|
||||
updateConfig();
|
||||
} else {
|
||||
toast.error(
|
||||
t("toast.save.error", {
|
||||
t("toast.save.error.title", {
|
||||
errorMessage: res.statusText,
|
||||
ns: "common",
|
||||
}),
|
||||
@@ -138,7 +138,7 @@ export default function MotionTunerView({
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(
|
||||
t("toast.save.error", {
|
||||
t("toast.save.error.title", {
|
||||
errorMessage: error.response.data.message,
|
||||
ns: "common",
|
||||
}),
|
||||
@@ -194,7 +194,7 @@ export default function MotionTunerView({
|
||||
{t("motionDetectionTuner.title")}
|
||||
</Heading>
|
||||
<div className="my-3 space-y-3 text-sm text-muted-foreground">
|
||||
<p>{t("motionDetectionTuner.desc")}</p>
|
||||
<p>{t("motionDetectionTuner.desc.title")}</p>
|
||||
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@@ -213,7 +213,7 @@ export default function MotionTunerView({
|
||||
<div className="mt-2 space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="motion-threshold" className="text-md">
|
||||
{t("motionDetectionTuner.Threshold")}
|
||||
{t("motionDetectionTuner.Threshold.title")}
|
||||
</Label>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<Trans ns="views/settings">
|
||||
@@ -242,7 +242,7 @@ export default function MotionTunerView({
|
||||
<div className="mt-2 space-y-6">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="motion-threshold" className="text-md">
|
||||
{t("motionDetectionTuner.contourArea")}
|
||||
{t("motionDetectionTuner.contourArea.title")}
|
||||
</Label>
|
||||
<div className="my-2 text-sm text-muted-foreground">
|
||||
<p>
|
||||
@@ -274,7 +274,7 @@ export default function MotionTunerView({
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<Label htmlFor="improve-contrast">
|
||||
{t("motionDetectionTuner.improveContrast")}
|
||||
{t("motionDetectionTuner.improveContrast.title")}
|
||||
</Label>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
<Trans ns="views/settings">
|
||||
|
||||
@@ -264,7 +264,7 @@ export default function NotificationView({
|
||||
updateConfig();
|
||||
} else {
|
||||
toast.error(
|
||||
t("toast.save.error", {
|
||||
t("toast.save.error.title", {
|
||||
errorMessage: res.statusText,
|
||||
ns: "common",
|
||||
}),
|
||||
@@ -279,9 +279,12 @@ export default function NotificationView({
|
||||
error.response?.data?.message ||
|
||||
error.response?.data?.detail ||
|
||||
"Unknown error";
|
||||
toast.error(t("toast.save.error", { errorMessage, ns: "common" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
toast.error(
|
||||
t("toast.save.error.title", { errorMessage, ns: "common" }),
|
||||
{
|
||||
position: "top-center",
|
||||
},
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
@@ -389,7 +392,7 @@ export default function NotificationView({
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("notification.email")}</FormLabel>
|
||||
<FormLabel>{t("notification.email.title")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark] md:w-72"
|
||||
@@ -414,7 +417,7 @@ export default function NotificationView({
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<FormLabel className="flex flex-row items-center text-base">
|
||||
{t("notification.cameras")}
|
||||
{t("notification.cameras.title")}
|
||||
</FormLabel>
|
||||
</div>
|
||||
<div className="max-w-md space-y-2 rounded-lg bg-secondary p-4">
|
||||
@@ -423,7 +426,7 @@ export default function NotificationView({
|
||||
name="allEnabled"
|
||||
render={({ field }) => (
|
||||
<FilterSwitch
|
||||
label={t("cameras.all", {
|
||||
label={t("cameras.all.title", {
|
||||
ns: "components/filter",
|
||||
})}
|
||||
isChecked={field.value}
|
||||
@@ -514,7 +517,7 @@ export default function NotificationView({
|
||||
{t("notification.deviceSpecific")}
|
||||
</Heading>
|
||||
<Button
|
||||
aria-label="Register or unregister notifications for this device"
|
||||
aria-label={t("notification.registerDevice")}
|
||||
disabled={
|
||||
!config?.notifications.enabled || publicKey == undefined
|
||||
}
|
||||
@@ -653,7 +656,7 @@ export function CameraNotificationSwitch({
|
||||
strftime_fmt:
|
||||
config?.ui.time_format == "24hour"
|
||||
? t("time.formattedTimestampExcludeSeconds.24hour", { ns: "common" })
|
||||
: t("time.formattedTimestampExcludeSeconds", { ns: "common" }),
|
||||
: t("time.formattedTimestampExcludeSeconds.12hour", { ns: "common" }),
|
||||
});
|
||||
return t("time.untilForTime", { ns: "common", time });
|
||||
};
|
||||
@@ -709,10 +712,10 @@ export function CameraNotificationSwitch({
|
||||
{t("notification.suspendTime.1hour")}
|
||||
</SelectItem>
|
||||
<SelectItem value="840">
|
||||
{t("notification.suspendTime.12hour")}
|
||||
{t("notification.suspendTime.12hours")}
|
||||
</SelectItem>
|
||||
<SelectItem value="1440">
|
||||
{t("notification.suspendTime.24hour")}
|
||||
{t("notification.suspendTime.24hours")}
|
||||
</SelectItem>
|
||||
<SelectItem value="off">
|
||||
{t("notification.suspendTime.untilRestart")}
|
||||
|
||||
@@ -581,7 +581,7 @@ export default function GeneralMetrics({
|
||||
{gpuMemSeries && (
|
||||
<div className="rounded-lg bg-background_alt p-2.5 md:rounded-2xl">
|
||||
<div className="mb-5">
|
||||
{t("general.hardwareInfo.gpuMemroy")}
|
||||
{t("general.hardwareInfo.gpuMemory")}
|
||||
</div>
|
||||
{gpuMemSeries.map((series) => (
|
||||
<ThresholdBarGraph
|
||||
|
||||
Reference in New Issue
Block a user