Refactor and clean up i18n (#17198)

* clean up i18n

* fix key

* fix key
This commit is contained in:
Josh Hawkins
2025-03-17 06:26:01 -06:00
committed by GitHub
parent 6e3ae0afc2
commit 03da70cb81
74 changed files with 1243 additions and 799 deletions
+36 -20
View File
@@ -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)}
+1 -1
View File
@@ -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>
+6 -4
View File
@@ -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>
+6 -6
View File
@@ -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")}
+1 -1
View File
@@ -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