chore: fix some key not work

This commit is contained in:
ZhaiSoul 2025-03-10 23:45:43 +08:00
parent ef646203a7
commit a8a4938c97
43 changed files with 348 additions and 217 deletions

View File

@ -38,6 +38,10 @@
}
}
},
"camera": {
"enable": "Enable Camera",
"disable": "Disable Camera"
},
"detect": {
"enable": "Enable Detect",
"disable": "Disable Detect"

View File

@ -64,6 +64,7 @@
"info": "信息"
},
"menu": {
"system": "系统",
"systemMetrics": "系统信息",
"configuration": "配置",
"systemLogs": "系统日志",

View File

@ -38,6 +38,10 @@
}
}
},
"camera": {
"enable": "开启摄像头",
"disable": "关闭摄像头"
},
"detect": {
"enable": "启用检测",
"disable": "关闭检测"

View File

@ -69,7 +69,7 @@ export default function CalendarFilterButton({
updateSelectedDay(undefined);
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</>

View File

@ -76,7 +76,7 @@ import { Switch } from "../ui/switch";
import { CameraStreamingDialog } from "../settings/CameraStreamingDialog";
import { DialogTrigger } from "@radix-ui/react-dialog";
import { useStreamingSettings } from "@/context/streaming-settings-provider";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type CameraGroupSelectorProps = {
className?: string;
@ -165,7 +165,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
</TooltipTrigger>
<TooltipPortal>
<TooltipContent className="" side="right">
{t("menu.live.allCameras")}
{t("menu.live.allCameras", { ns: "common" })}
</TooltipContent>
</TooltipPortal>
</Tooltip>
@ -536,15 +536,19 @@ export function CameraGroupRow({
<AlertDialogTitle>{t("group.delete.confirm")}</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogDescription>
{t("group.delete.confirm.desc", { name: group[0] })}
<Trans ns="components/camera" values={{ name: group[0] }}>
group.delete.confirm.desc
</Trans>
</AlertDialogDescription>
<AlertDialogFooter>
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
<AlertDialogCancel>
{t("button.cancel", { ns: "common" })}
</AlertDialogCancel>
<AlertDialogAction
className={buttonVariants({ variant: "destructive" })}
onClick={onDeleteGroup}
>
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
@ -562,13 +566,13 @@ export function CameraGroupRow({
aria-label="Edit group"
onClick={onEditGroup}
>
{t("button.edit")}
{t("button.edit", { ns: "common" })}
</DropdownMenuItem>
<DropdownMenuItem
aria-label="Delete group"
onClick={() => setDeleteDialogOpen(true)}
>
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPortal>
@ -585,7 +589,9 @@ export function CameraGroupRow({
onClick={onEditGroup}
/>
</TooltipTrigger>
<TooltipContent>{t("button.edit")}</TooltipContent>
<TooltipContent>
{t("button.edit", { ns: "common" })}
</TooltipContent>
</Tooltip>
<Tooltip>
@ -596,7 +602,9 @@ export function CameraGroupRow({
onClick={() => setDeleteDialogOpen(true)}
/>
</TooltipTrigger>
<TooltipContent>{t("button.delete")}</TooltipContent>
<TooltipContent>
{t("button.delete", { ns: "common" })}
</TooltipContent>
</Tooltip>
</div>
)}
@ -925,7 +933,7 @@ export function CameraGroupEdit({
aria-label="Cancel"
onClick={onCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -937,10 +945,10 @@ export function CameraGroupEdit({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -42,7 +42,7 @@ export function CamerasFilterButton({
}
if (!selectedCameras || selectedCameras.length == 0) {
return t("menu.live.allCameras");
return t("menu.live.allCameras", { ns: "common" });
}
return `${selectedCameras.includes("birdseye") ? selectedCameras.length - 1 : selectedCameras.length} Camera${selectedCameras.length !== 1 ? "s" : ""}`;
@ -236,7 +236,7 @@ export function CamerasFilterContent({
setOpen(false);
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common" })}
</Button>
<Button
aria-label="Reset"
@ -245,7 +245,7 @@ export function CamerasFilterContent({
updateCameraFilter(undefined);
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</>

View File

@ -577,10 +577,10 @@ export function GeneralFilterContent({
onClose();
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common" })}
</Button>
<Button aria-label="Reset" onClick={onReset}>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</>

View File

@ -391,7 +391,7 @@ export function GeneralFilterContent({
onClose();
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common" })}
</Button>
<Button
aria-label="Reset"
@ -400,7 +400,7 @@ export function GeneralFilterContent({
updateLabelFilter(undefined);
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</>
@ -567,7 +567,7 @@ export function SortTypeContent({
onClose();
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common" })}
</Button>
<Button
aria-label="Reset"
@ -576,7 +576,7 @@ export function SortTypeContent({
updateSortType(undefined);
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</>

View File

@ -101,10 +101,10 @@ export function GeneralFilterContent({
>
{t(
"masksAndZones." +
item.replace(/_([a-z])/g, (letter) =>
letter.toUpperCase(),
) +
"s",
item
.replace(/_([a-z])/g, (letter) => letter.toUpperCase())
.replace("_", "") +
"s.label",
{ ns: "views/settings" },
)}
</Label>

View File

@ -80,7 +80,7 @@ export function SaveSearchDialog({
)}
<DialogFooter>
<Button aria-label="Cancel" onClick={onClose}>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
onClick={handleSave}
@ -88,7 +88,7 @@ export function SaveSearchDialog({
className="mb-2 md:mb-0"
aria-label="Save this search"
>
{t("button.save")}
{t("button.save", { ns: "common" })}
</Button>
</DialogFooter>
</DialogContent>

View File

@ -187,7 +187,7 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
>
<a className="flex" href={logoutUrl}>
<LuLogOut className="mr-2 size-4" />
<span>Logout</span>
<span>{t("menu.user.logout", { ns: "common" })}</span>
</a>
</MenuItem>
</div>

View File

@ -40,7 +40,7 @@ import {
} from "@/components/ui/tooltip";
import useSWR from "swr";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type SearchResultActionsProps = {
searchResult: SearchResult;
@ -154,7 +154,7 @@ export default function SearchResultActions({
onClick={() => setDeleteDialogOpen(true)}
>
<LuTrash2 className="mr-2 size-4" />
<span>{t("button.delete")}</span>
<span>{t("button.delete", { ns: "common" })}</span>
</MenuItem>
</>
);
@ -170,15 +170,17 @@ export default function SearchResultActions({
<AlertDialogTitle>{t("dialog.confirmDelete")}</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogDescription>
{t("dialog.confirmDelete.desc")}
<Trans ns="views/explore">dialog.confirmDelete.desc</Trans>
</AlertDialogDescription>
<AlertDialogFooter>
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
<AlertDialogCancel>
{t("button.cancel", { ns: "common" })}
</AlertDialogCancel>
<AlertDialogAction
className={buttonVariants({ variant: "destructive" })}
onClick={handleDelete}
>
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>

View File

@ -61,7 +61,7 @@ export default function NavItem({
<TooltipTrigger>{content}</TooltipTrigger>
<TooltipPortal>
<TooltipContent side="right">
<p>{t("{item.title}")}</p>
<p>{t(item.title)}</p>
</TooltipContent>
</TooltipPortal>
</Tooltip>

View File

@ -15,7 +15,7 @@ import { useEffect, useState } from "react";
import axios from "axios";
import { toast } from "sonner";
import { Toaster } from "../ui/sonner";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type CameraInfoDialogProps = {
camera: CameraConfig;
@ -80,7 +80,7 @@ export default function CameraInfoDialog({
</DialogTitle>
</DialogHeader>
<DialogDescription>
{t("cameras.info.streamDataFromFFPROBE")}
<Trans ns="views/system">cameras.info.streamDataFromFFPROBE</Trans>
</DialogDescription>
<div className="mb-2 p-4">
@ -184,7 +184,7 @@ export default function CameraInfoDialog({
aria-label="Copy"
onClick={() => onCopyFfprobe()}
>
{t("button.copy")}
{t("button.copy", { ns: "common" })}
</Button>
</DialogFooter>
</DialogContent>

View File

@ -211,7 +211,7 @@ export default function CreateUserDialog({
render={({ field }) => (
<FormItem>
<FormLabel className="text-sm font-medium">
{t("role.title")}
{t("role.title", { ns: "common" })}
</FormLabel>
<Select
onValueChange={field.onChange}
@ -229,7 +229,7 @@ export default function CreateUserDialog({
>
<div className="flex items-center gap-2">
<Shield className="h-4 w-4 text-primary" />
<span>{t("role.admin")}</span>
<span>{t("role.admin", { ns: "common" })}</span>
</div>
</SelectItem>
<SelectItem
@ -238,13 +238,13 @@ export default function CreateUserDialog({
>
<div className="flex items-center gap-2">
<User className="h-4 w-4 text-muted-foreground" />
<span>{t("role.viewer")}</span>
<span>{t("role.viewer", { ns: "common" })}</span>
</div>
</SelectItem>
</SelectContent>
</Select>
<FormDescription className="text-xs text-muted-foreground">
{t("role.desc")}
{t("role.desc", { ns: "common" })}
</FormDescription>
<FormMessage />
</FormItem>
@ -261,7 +261,7 @@ export default function CreateUserDialog({
onClick={handleCancel}
type="button"
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -273,10 +273,10 @@ export default function CreateUserDialog({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -48,7 +48,7 @@ export default function DeleteUserDialog({
onClick={onCancel}
type="button"
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="destructive"
@ -56,7 +56,7 @@ export default function DeleteUserDialog({
className="flex flex-1"
onClick={onDelete}
>
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</Button>
</div>
</div>

View File

@ -321,7 +321,7 @@ export function ExportContent({
className={`cursor-pointer p-2 text-center ${isDesktop ? "" : "w-full"}`}
onClick={onCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</div>
<Button
className={isDesktop ? "" : "w-full"}

View File

@ -247,7 +247,7 @@ export default function MobileReviewSettingsDrawer({
});
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { Button } from "../ui/button";
import {
Dialog,
@ -52,7 +52,7 @@ export default function RoleChangeDialog({
<div className="py-6">
<div className="mb-4 text-sm text-muted-foreground">
{t("users.dialog.changeRole.roleInfo")}
<Trans ns="views/settings">users.dialog.changeRole.roleInfo</Trans>
</div>
<Select
@ -90,7 +90,7 @@ export default function RoleChangeDialog({
onClick={onCancel}
type="button"
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -99,7 +99,7 @@ export default function RoleChangeDialog({
onClick={() => onSave(selectedRole)}
disabled={selectedRole === currentRole}
>
{t("button.save")}
{t("button.save", { ns: "common" })}
</Button>
</div>
</div>

View File

@ -35,7 +35,7 @@ export default function SaveExportOverlay({
onClick={onCancel}
>
<LuX />
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
className="flex items-center gap-1"

View File

@ -205,7 +205,7 @@ export default function SetPasswordDialog({
onClick={onCancel}
type="button"
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -214,7 +214,7 @@ export default function SetPasswordDialog({
onClick={handleSave}
disabled={!password || password !== confirmPassword}
>
{t("button.save")}
{t("button.save", { ns: "common" })}
</Button>
</div>
</div>

View File

@ -719,7 +719,7 @@ function ObjectDetailsTab({
aria-label="Save"
onClick={updateDescription}
>
{t("button.save")}
{t("button.save", { ns: "common" })}
</Button>
)}
<TextEntryDialog
@ -834,7 +834,9 @@ export function ObjectSnapshotTab({
</a>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent>{t("button.download")}</TooltipContent>
<TooltipContent>
{t("button.download", { ns: "common" })}
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>

View File

@ -84,7 +84,9 @@ export default function RestartDialog({
<AlertDialogTitle>{t("restart.title")}</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
<AlertDialogCancel>
{t("button.cancel", { ns: "common" })}
</AlertDialogCancel>
<AlertDialogAction onClick={handleRestart}>
{t("restart.button")}
</AlertDialogAction>

View File

@ -33,7 +33,7 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type SearchFilterDialogProps = {
config?: FrigateConfig;
@ -176,7 +176,7 @@ export default function SearchFilterDialog({
setOpen(false);
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common" })}
</Button>
<Button
aria-label="Reset filters to default values"
@ -196,7 +196,7 @@ export default function SearchFilterDialog({
}));
}}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
</div>
</div>
@ -691,14 +691,14 @@ export function SnapshotClipFilterContent({
aria-label="Yes"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.yes")}
{t("button.yes", { ns: "common" })}
</ToggleGroupItem>
<ToggleGroupItem
value="no"
aria-label="No"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.no")}
{t("button.no", { ns: "common" })}
</ToggleGroupItem>
</ToggleGroup>
</div>
@ -732,7 +732,9 @@ export function SnapshotClipFilterContent({
side="left"
sideOffset={5}
>
{t("features.submittedToFrigatePlus.tips")}
<Trans ns="components/filter">
features.submittedToFrigatePlus.tips
</Trans>
</TooltipContent>
)}
</Tooltip>
@ -767,14 +769,14 @@ export function SnapshotClipFilterContent({
aria-label="Yes"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.yes")}
{t("button.yes", { ns: "common" })}
</ToggleGroupItem>
<ToggleGroupItem
value="no"
aria-label="No"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.no")}
{t("button.no", { ns: "common" })}
</ToggleGroupItem>
</ToggleGroup>
</div>
@ -822,14 +824,14 @@ export function SnapshotClipFilterContent({
aria-label="Yes"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.yes")}
{t("button.yes", { ns: "common" })}
</ToggleGroupItem>
<ToggleGroupItem
value="no"
aria-label="No"
className="data-[state=on]:bg-selected data-[state=on]:text-white data-[state=on]:hover:bg-selected data-[state=on]:hover:text-white"
>
{t("button.no")}
{t("button.no", { ns: "common" })}
</ToggleGroupItem>
</ToggleGroup>
</div>

View File

@ -91,10 +91,10 @@ export default function TextEntryDialog({
/>
<DialogFooter className="pt-4">
<Button type="button" onClick={() => setOpen(false)}>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button variant="select" type="submit">
{t("button.save")}
{t("button.save", { ns: "common" })}
</Button>
</DialogFooter>
</form>

View File

@ -31,7 +31,7 @@ import useSWR from "swr";
import { LuCheck, LuExternalLink, LuInfo, LuX } from "react-icons/lu";
import { Link } from "react-router-dom";
import { LiveStreamMetadata } from "@/types/live";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type CameraStreamingDialogProps = {
camera: string;
@ -173,7 +173,9 @@ export function CameraStreamingDialog({
cameraName: camera.replaceAll("_", " "),
})}
</DialogTitle>
<DialogDescription>{t("group.camera.setting.desc")}</DialogDescription>
<DialogDescription>
<Trans ns="components/camera">group.camera.setting.desc</Trans>
</DialogDescription>
</DialogHeader>
<div className="flex flex-col space-y-8">
{!isRestreamed && (
@ -190,7 +192,9 @@ export function CameraStreamingDialog({
<PopoverTrigger asChild>
<div className="cursor-pointer p-0">
<LuInfo className="size-4" />
<span className="sr-only">{t("button.info")}</span>
<span className="sr-only">
{t("button.info", { ns: "common" })}
</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-80 text-xs">
@ -247,7 +251,9 @@ export function CameraStreamingDialog({
<PopoverTrigger asChild>
<div className="cursor-pointer p-0">
<LuInfo className="size-4" />
<span className="sr-only">{t("button.info")}</span>
<span className="sr-only">
{t("button.info", { ns: "common" })}
</span>
</div>
</PopoverTrigger>
<PopoverContent className="w-80 text-xs">
@ -355,7 +361,7 @@ export function CameraStreamingDialog({
aria-label="Cancel"
onClick={handleCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -367,10 +373,10 @@ export function CameraStreamingDialog({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -22,7 +22,7 @@ import { Toaster } from "../ui/sonner";
import ActivityIndicator from "../indicators/activity-indicator";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type MotionMaskEditPaneProps = {
polygons?: Polygon[];
@ -232,7 +232,9 @@ export default function MotionMaskEditPane({
: t("masksAndZones.motionMasks.add")}
</Heading>
<div className="my-3 space-y-3 text-sm text-muted-foreground">
<p>{t("masksAndZones.motionMasks.context")}</p>
<p>
<Trans ns="views/settings">masksAndZones.motionMasks.context</Trans>
</p>
<div className="flex items-center text-primary">
<Link
@ -324,7 +326,7 @@ export default function MotionMaskEditPane({
aria-label="Cancel"
onClick={onCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -336,10 +338,10 @@ export default function MotionMaskEditPane({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -365,7 +365,7 @@ export default function ObjectMaskEditPane({
aria-label="Cancel"
onClick={onCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -377,10 +377,10 @@ export default function ObjectMaskEditPane({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -319,7 +319,9 @@ export default function PolygonItem({
}}
/>
</TooltipTrigger>
<TooltipContent>{t("button.edit")}</TooltipContent>
<TooltipContent>
{t("button.edit", { ns: "common" })}
</TooltipContent>
</Tooltip>
<Tooltip>
@ -332,7 +334,9 @@ export default function PolygonItem({
onClick={() => handleCopyCoordinates(index)}
/>
</TooltipTrigger>
<TooltipContent>{t("button.copyCoordinates")}</TooltipContent>
<TooltipContent>
{t("button.copyCoordinates", { ns: "common" })}
</TooltipContent>
</Tooltip>
<Tooltip>
@ -346,7 +350,9 @@ export default function PolygonItem({
onClick={() => !isLoading && setDeleteDialogOpen(true)}
/>
</TooltipTrigger>
<TooltipContent>{t("button.delete")}</TooltipContent>
<TooltipContent>
{t("button.delete", { ns: "common" })}
</TooltipContent>
</Tooltip>
</div>
)}

View File

@ -29,7 +29,7 @@ import { toast } from "sonner";
import { flattenPoints, interpolatePoints } from "@/utils/canvasUtil";
import ActivityIndicator from "../indicators/activity-indicator";
import { getAttributeLabels } from "@/utils/iconUtil";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type ZoneEditPaneProps = {
polygons?: Polygon[];
@ -558,7 +558,9 @@ export default function ZoneEditPane({
/>
</FormControl>
<FormDescription>
{t("masksAndZones.zones.inertia.desc")}
<Trans ns="views/settings">
masksAndZones.zones.inertia.desc
</Trans>
</FormDescription>
<FormMessage />
</FormItem>
@ -579,7 +581,9 @@ export default function ZoneEditPane({
/>
</FormControl>
<FormDescription>
{t("masksAndZones.zones.loiteringTime.desc")}
<Trans ns="views/settings">
masksAndZones.zones.loiteringTime.desc
</Trans>
</FormDescription>
<FormMessage />
</FormItem>
@ -808,7 +812,7 @@ export default function ZoneEditPane({
aria-label="Cancel"
onClick={onCancel}
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -820,10 +824,10 @@ export default function ZoneEditPane({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -431,7 +431,7 @@ export function DateRangePicker({
}
}}
>
{t("button.apply")}
{t("button.apply", { ns: "common"})}
</Button>
<Button
onClick={() => {
@ -442,7 +442,7 @@ export function DateRangePicker({
variant="ghost"
aria-label="Reset"
>
{t("button.reset")}
{t("button.reset", { ns: "common"})}
</Button>
</div>
</div>

View File

@ -125,14 +125,16 @@ function Exports() {
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>{t("button.cancel")}</AlertDialogCancel>
<AlertDialogCancel>
{t("button.cancel", { ns: "common" })}
</AlertDialogCancel>
<Button
className="text-white"
aria-label="Delete Export"
variant="destructive"
onClick={() => onHandleDelete()}
>
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</Button>
</AlertDialogFooter>
</AlertDialogContent>

View File

@ -96,7 +96,7 @@ export default function EventView({
pullLatestData,
updateFilter,
}: EventViewProps) {
const { t } = useTranslation(["views/event"]);
const { t } = useTranslation(["views/events"]);
const { data: config } = useSWR<FrigateConfig>("config");
const contentRef = useRef<HTMLDivElement | null>(null);
@ -472,7 +472,7 @@ function DetectionReview({
setSelectedReviews,
pullLatestData,
}: DetectionReviewProps) {
const { t } = useTranslation(["views/event"]);
const { t } = useTranslation(["views/events"]);
const reviewTimelineRef = useRef<HTMLDivElement>(null);
@ -870,7 +870,7 @@ function MotionReview({
motionOnly = false,
onOpenRecording,
}: MotionReviewProps) {
const { t } = useTranslation(["views/event"]);
const { t } = useTranslation(["views/events"]);
const segmentDuration = 30;
const { data: config } = useSWR<FrigateConfig>("config");

View File

@ -696,8 +696,8 @@ export default function DraggableGridLayout({
</TooltipTrigger>
<TooltipContent>
{fullscreen
? t("button.exitFullscreen")
: t("button.fullscreen")}
? t("button.exitFullscreen", { ns: "common" })
: t("button.fullscreen", { ns: "common" })}
</TooltipContent>
</Tooltip>
</>

View File

@ -436,7 +436,9 @@ export default function LiveCameraView({
>
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
{isDesktop && (
<div className="text-primary">{t("button.back")}</div>
<div className="text-primary">
{t("button.back", { ns: "common" })}
</div>
)}
</Button>
<Button
@ -458,7 +460,9 @@ export default function LiveCameraView({
>
<LuHistory className="size-5 text-secondary-foreground" />
{isDesktop && (
<div className="text-primary">{t("button.history")}</div>
<div className="text-primary">
{t("button.history", { ns: "common" })}
</div>
)}
</Button>
</div>
@ -479,7 +483,7 @@ export default function LiveCameraView({
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
{isDesktop && (
<div className="text-secondary-foreground">
{t("button.back")}
{t("button.back", { ns: "common" })}
</div>
)}
</Button>
@ -491,7 +495,9 @@ export default function LiveCameraView({
Icon={fullscreen ? FaCompress : FaExpand}
isActive={fullscreen}
title={
fullscreen ? t("button.close") : t("button.fullscreen")
fullscreen
? t("button.close", { ns: "common" })
: t("button.fullscreen", { ns: "common" })
}
onClick={toggleFullscreen}
/>
@ -502,7 +508,11 @@ export default function LiveCameraView({
variant={fullscreen ? "overlay" : "primary"}
Icon={LuPictureInPicture}
isActive={pip}
title={pip ? t("button.close") : t("button.pictureInPicture")}
title={
pip
? t("button.close", { ns: "common" })
: t("button.pictureInPicture", { ns: "common" })
}
onClick={() => {
if (!pip) {
setPip(true);
@ -1101,7 +1111,9 @@ function FrigateCameraFeatures({
variant={fullscreen ? "overlay" : "primary"}
Icon={enabledState == "ON" ? LuPower : LuPowerOff}
isActive={enabledState == "ON"}
title={`${enabledState == "ON" ? "Disable" : "Enable"} Camera`}
title={
enabledState == "ON" ? t("camera.disable") : t("camera.enable")
}
onClick={() => sendEnabled(enabledState == "ON" ? "OFF" : "ON")}
disabled={false}
/>
@ -1110,7 +1122,9 @@ function FrigateCameraFeatures({
variant={fullscreen ? "overlay" : "primary"}
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
isActive={detectState == "ON"}
title={`${detectState == "ON" ? "Disable" : "Enable"} Detect`}
title={
detectState == "ON" ? t("detect.disable") : t("detect.enable")
}
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
disabled={!cameraEnabled}
/>
@ -1119,7 +1133,11 @@ function FrigateCameraFeatures({
variant={fullscreen ? "overlay" : "primary"}
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
isActive={recordState == "ON"}
title={`${recordState == "ON" ? "Disable" : "Enable"} Recording`}
title={
recordState == "ON"
? t("recording.disable")
: t("recording.enable")
}
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
disabled={!cameraEnabled}
/>
@ -1128,7 +1146,11 @@ function FrigateCameraFeatures({
variant={fullscreen ? "overlay" : "primary"}
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
isActive={snapshotState == "ON"}
title={`${snapshotState == "ON" ? "Disable" : "Enable"} Snapshots`}
title={
snapshotState == "ON"
? t("snapshots.disable")
: t("snapshots.enable")
}
onClick={() => sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")}
disabled={!cameraEnabled}
/>
@ -1138,7 +1160,11 @@ function FrigateCameraFeatures({
variant={fullscreen ? "overlay" : "primary"}
Icon={audioState == "ON" ? LuEar : LuEarOff}
isActive={audioState == "ON"}
title={`${audioState == "ON" ? "Disable" : "Enable"} Audio Detect`}
title={
audioState == "ON"
? t("audioDetect.disable")
: t("audioDetect.enable")
}
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
disabled={!cameraEnabled}
/>
@ -1151,7 +1177,11 @@ function FrigateCameraFeatures({
autotrackingState == "ON" ? TbViewfinder : TbViewfinderOff
}
isActive={autotrackingState == "ON"}
title={`${autotrackingState == "ON" ? "Disable" : "Enable"} Autotracking`}
title={
autotrackingState == "ON"
? t("autotracking.disable")
: t("autotracking.enable")
}
onClick={() =>
sendAutotracking(autotrackingState == "ON" ? "OFF" : "ON")
}
@ -1189,11 +1219,13 @@ function FrigateCameraFeatures({
<div className="flex flex-col gap-5 p-4">
{!isRestreamed && (
<div className="flex flex-col gap-2">
<Label>{t("streaming", { ns: "components/dialog" })}</Label>
<Label>
{t("streaming.label", { 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>
{t("streaming.restreaming.disabled", {
{t("streaming.restreaming.NotEnabled", {
ns: "components/dialog",
})}
</div>
@ -1398,7 +1430,9 @@ function FrigateCameraFeatures({
className="mx-0 cursor-pointer text-primary"
htmlFor="showstats"
>
{t("streaming.showStats", { ns: "components/dialog" })}
{t("streaming.showStats.label", {
ns: "components/dialog",
})}
</Label>
<Switch
className="ml-1"

View File

@ -564,8 +564,8 @@ export default function LiveDashboardView({
</TooltipTrigger>
<TooltipContent>
{fullscreen
? t("button.exitFullscreen")
: t("button.fullscreen")}
? t("button.exitFullscreen", { ns: "common" })
: t("button.fullscreen", { ns: "common" })}
</TooltipContent>
</Tooltip>
</div>

View File

@ -401,7 +401,9 @@ export function RecordingView({
>
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
{isDesktop && (
<div className="text-primary">{t("button.back")}</div>
<div className="text-primary">
{t("button.back", { ns: "common" })}
</div>
)}
</Button>
<Button

View File

@ -256,7 +256,9 @@ export default function AuthenticationView() {
: ""
}
>
{t("role." + user.role || "viewer")}
{t("role." + (user.role || "viewer"), {
ns: "common",
})}
</Badge>
</TableCell>
<TableCell className="text-right">
@ -280,7 +282,7 @@ export default function AuthenticationView() {
>
<LuUserCog className="size-3.5" />
<span className="ml-1.5 hidden sm:inline-block">
{t("role.title")}
{t("role.title", { ns: "common" })}
</span>
</Button>
</TooltipTrigger>
@ -326,7 +328,7 @@ export default function AuthenticationView() {
>
<HiTrash className="size-3.5" />
<span className="ml-1.5 hidden sm:inline-block">
{t("button.delete")}
{t("button.delete", { ns: "common" })}
</span>
</Button>
</TooltipTrigger>

View File

@ -27,11 +27,11 @@ import { LuExternalLink } from "react-icons/lu";
import { capitalizeFirstLetter } from "@/utils/stringUtil";
import { MdCircle } from "react-icons/md";
import { cn } from "@/lib/utils";
import { Trans } from "react-i18next";
import { t } from "i18next";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { useAlertsState, useDetectionsState, useEnabledState } from "@/api/ws";
import { useTranslation } from "react-i18next";
type CameraSettingsViewProps = {
selectedCamera: string;
@ -47,7 +47,6 @@ export default function CameraSettingsView({
selectedCamera,
setUnsavedChanges,
}: CameraSettingsViewProps) {
const { t } = useTranslation(["views/settings"]);
const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config");
@ -82,7 +81,7 @@ export default function CameraSettingsView({
.map((label) => t(label, { ns: "objects" }))
.join(", ")
: "";
}, [cameraConfig, t]);
}, [cameraConfig]);
const detectionsLabels = useMemo(() => {
return cameraConfig?.review.detections.labels
@ -90,7 +89,7 @@ export default function CameraSettingsView({
.map((label) => t(label, { ns: "objects" }))
.join(", ")
: "";
}, [cameraConfig, t]);
}, [cameraConfig]);
// form
@ -191,7 +190,7 @@ export default function CameraSettingsView({
setIsLoading(false);
});
},
[updateConfig, setIsLoading, selectedCamera, cameraConfig, t],
[updateConfig, setIsLoading, selectedCamera, cameraConfig],
);
const onCancel = useCallback(() => {
@ -260,13 +259,13 @@ export default function CameraSettingsView({
<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">
<Heading as="h3" className="my-2">
{t("camera.title")}
<Trans ns="views/settings">camera.title</Trans>
</Heading>
<Separator className="my-2 flex bg-secondary" />
<Heading as="h4" className="my-2">
{t("camera.streams.title")}
<Trans ns="views/settings">camera.streams.title</Trans>
</Heading>
<div className="flex flex-row items-center">
@ -279,16 +278,18 @@ export default function CameraSettingsView({
}}
/>
<div className="space-y-0.5">
<Label htmlFor="camera-enabled">{t("button.enabled")}</Label>
<Label htmlFor="camera-enabled">
<Trans>button.enabled</Trans>
</Label>
</div>
</div>
<div className="mt-3 text-sm text-muted-foreground">
{t("camera.streams.desc")}
<Trans ns="views/settings">camera.streams.desc</Trans>
</div>
<Separator className="mb-2 mt-4 flex bg-secondary" />
<Heading as="h4" className="my-2">
{t("camera.review.title")}
<Trans ns="views/settings">camera.review.title</Trans>
</Heading>
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 space-y-3 text-sm text-primary-variant">
@ -303,7 +304,7 @@ export default function CameraSettingsView({
/>
<div className="space-y-0.5">
<Label htmlFor="alerts-enabled">
{t("camera.review.alerts")}
<Trans ns="views/settings">camera.review.alerts</Trans>
</Label>
</div>
</div>
@ -319,12 +320,12 @@ export default function CameraSettingsView({
/>
<div className="space-y-0.5">
<Label htmlFor="detections-enabled">
{t("camera.review.detections")}
<Trans ns="views/settings">camera.review.detections</Trans>
</Label>
</div>
</div>
<div className="mt-3 text-sm text-muted-foreground">
{t("camera.review.desc")}
<Trans ns="views/settings">camera.review.desc</Trans>
</div>
</div>
</div>
@ -332,12 +333,16 @@ export default function CameraSettingsView({
<Separator className="my-2 flex bg-secondary" />
<Heading as="h4" className="my-2">
{t("camera.reviewClassification.title")}
<Trans ns="views/settings">camera.reviewClassification.title</Trans>
</Heading>
<div className="max-w-6xl">
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
<p>{t("camera.reviewClassification.desc")}</p>
<p>
<Trans ns="views/settings">
camera.reviewClassification.desc
</Trans>
</p>
<div className="flex items-center text-primary">
<Link
to="https://docs.frigate.video/configuration/review"
@ -345,7 +350,9 @@ export default function CameraSettingsView({
rel="noopener noreferrer"
className="inline"
>
{t("camera.reviewClassification.readTheDocumentation")}{" "}
<Trans ns="views/settings">
camera.reviewClassification.readTheDocumentation
</Trans>{" "}
<LuExternalLink className="ml-2 inline-flex size-3" />
</Link>
</div>
@ -374,13 +381,15 @@ export default function CameraSettingsView({
<>
<div className="mb-2">
<FormLabel className="flex flex-row items-center text-base">
{t("camera.review.alerts")}
<Trans ns="views/settings">
camera.review.alerts
</Trans>
<MdCircle className="ml-3 size-2 text-severity_alert" />
</FormLabel>
<FormDescription>
{t(
"camera.reviewClassification.selectAlertsZones",
)}
<Trans ns="views/settings">
camera.reviewClassification.selectAlertsZones
</Trans>
</FormDescription>
</div>
<div className="max-w-md rounded-lg bg-secondary p-4 md:max-w-full">
@ -429,7 +438,9 @@ export default function CameraSettingsView({
</>
) : (
<div className="font-normal text-destructive">
{t("camera.reviewClassification.noDefinedZones")}
<Trans ns="views/settings">
camera.reviewClassification.noDefinedZones
</Trans>
</div>
)}
<FormMessage />
@ -450,6 +461,7 @@ export default function CameraSettingsView({
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
ns: "views/settings",
},
)
: t("camera.reviewClassification.objectAlertsTips", {
@ -457,6 +469,7 @@ export default function CameraSettingsView({
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
ns: "views/settings",
})}
</div>
</FormItem>
@ -472,14 +485,16 @@ export default function CameraSettingsView({
<>
<div className="mb-2">
<FormLabel className="flex flex-row items-center text-base">
{t("camera.review.detections")}
<Trans ns="views/settings">
camera.review.detections
</Trans>
<MdCircle className="ml-3 size-2 text-severity_detection" />
</FormLabel>
{selectDetections && (
<FormDescription>
{t(
"camera.reviewClassification.selectDetectionsZones",
)}
<Trans ns="views/settings">
camera.reviewClassification.selectDetectionsZones
</Trans>
</FormDescription>
)}
</div>
@ -542,9 +557,9 @@ export default function CameraSettingsView({
htmlFor="select-detections"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{t(
"camera.reviewClassification.limitDetections",
)}
<Trans ns="views/settings">
camera.reviewClassification.limitDetections
</Trans>
</label>
</div>
</div>
@ -553,51 +568,58 @@ export default function CameraSettingsView({
<div className="text-sm">
{watchedDetectionsZones &&
watchedDetectionsZones.length > 0
? !selectDetections
? t(
"camera.reviewClassification.zoneObjectDetectionsTips",
{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.join(", "),
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
},
)
: t(
"camera.reviewClassification.zoneObjectDetectionsTips.notSelectDetections",
{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.join(", "),
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
},
)
: t(
"camera.reviewClassification.objectDetectionsTips",
{
watchedDetectionsZones.length > 0 ? (
!selectDetections ? (
<Trans
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips"
values={{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.join(", "),
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
},
)}
}}
ns="views/settings"
></Trans>
) : (
<Trans
i18nKey="camera.reviewClassification.zoneObjectDetectionsTips.notSelectDetections"
values={{
detectionsLabels,
zone: watchedDetectionsZones
.map((zone) =>
capitalizeFirstLetter(zone).replaceAll(
"_",
" ",
),
)
.join(", "),
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
}}
ns="views/settings"
/>
)
) : (
<Trans
i18nKey="camera.reviewClassification.objectDetectionsTips"
values={{
detectionsLabels,
cameraName: capitalizeFirstLetter(
cameraConfig?.name ?? "",
).replaceAll("_", " "),
}}
ns="views/settings"
/>
)}
</div>
</FormItem>
)}
@ -612,7 +634,7 @@ export default function CameraSettingsView({
onClick={onCancel}
type="button"
>
{t("button.cancel")}
<Trans>button.cancel</Trans>
</Button>
<Button
variant="select"
@ -624,10 +646,12 @@ export default function CameraSettingsView({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>
<Trans>button.saving</Trans>
</span>
</div>
) : (
t("button.save")
<Trans>button.save</Trans>
)}
</Button>
</div>

View File

@ -21,7 +21,7 @@ import { Separator } from "@/components/ui/separator";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type MotionTunerViewProps = {
selectedCamera: string;
@ -236,7 +236,11 @@ export default function MotionTunerView({
{t("motionDetectionTuner.contourArea")}
</Label>
<div className="my-2 text-sm text-muted-foreground">
<p>{t("motionDetectionTuner.contourArea.desc")}</p>
<p>
<Trans ns="views/settings">
motionDetectionTuner.contourArea.desc
</Trans>
</p>
</div>
</div>
<div className="flex flex-row justify-between">
@ -264,7 +268,9 @@ export default function MotionTunerView({
{t("motionDetectionTuner.improveContrast")}
</Label>
<div className="text-sm text-muted-foreground">
{t("motionDetectionTuner.improveContrast.desc")}
<Trans ns="views/settings">
motionDetectionTuner.improveContrast.desc
</Trans>
</div>
</div>
<Switch
@ -285,7 +291,7 @@ export default function MotionTunerView({
aria-label="Reset"
onClick={onCancel}
>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
<Button
variant="select"
@ -297,10 +303,10 @@ export default function MotionTunerView({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -478,7 +478,7 @@ export default function NotificationView({
onClick={onCancel}
type="button"
>
{t("button.cancel")}
{t("button.cancel", { ns: "common" })}
</Button>
<Button
variant="select"
@ -490,10 +490,10 @@ export default function NotificationView({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>

View File

@ -250,7 +250,7 @@ export default function ObjectSettingsView({
<div className="cursor-pointer p-0">
<LuInfo className="size-4" />
<span className="sr-only">
{t("button.info")}
{t("button.info", { ns: "common" })}
</span>
</div>
</PopoverTrigger>

View File

@ -20,7 +20,7 @@ import {
SelectItem,
SelectTrigger,
} from "@/components/ui/select";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
type ExploreSettingsViewProps = {
setUnsavedChanges: React.Dispatch<React.SetStateAction<boolean>>;
@ -172,7 +172,9 @@ export default function ExploreSettingsView({
</Heading>
<div className="max-w-6xl">
<div className="mb-5 mt-2 flex max-w-5xl flex-col gap-2 text-sm text-primary-variant">
<p>{t("explore.semanticSearch.desc")}</p>
<p>
<Trans ns="views/settings">explore.semanticSearch.desc</Trans>
</p>
<div className="flex items-center text-primary">
<Link
@ -200,7 +202,9 @@ export default function ExploreSettingsView({
}}
/>
<div className="space-y-0.5">
<Label htmlFor="enabled">{t("button.enabled")}</Label>
<Label htmlFor="enabled">
{t("button.enabled", { ns: "common" })}
</Label>
</div>
</div>
<div className="flex flex-col">
@ -221,7 +225,9 @@ export default function ExploreSettingsView({
</div>
</div>
<div className="mt-3 text-sm text-muted-foreground">
{t("explore.semanticSearch.reindexOnStartup.desc")}
<Trans ns="views/settings">
explore.semanticSearch.reindexOnStartup.desc
</Trans>
</div>
</div>
<div className="mt-2 flex flex-col space-y-6">
@ -230,10 +236,22 @@ export default function ExploreSettingsView({
{t("explore.semanticSearch.modelSize.label")}
</div>
<div className="space-y-1 text-sm text-muted-foreground">
<p>{t("explore.semanticSearch.modelSize.desc")}</p>
<p>
<Trans ns="views/settings">
explore.semanticSearch.modelSize.desc
</Trans>
</p>
<ul className="list-disc pl-5 text-sm">
<li>{t("explore.semanticSearch.modelSize.small.desc")}</li>
<li>{t("explore.semanticSearch.modelSize.large.desc")}</li>
<li>
<Trans ns="views/settings">
explore.semanticSearch.modelSize.small.desc
</Trans>
</li>
<li>
<Trans ns="views/settings">
explore.semanticSearch.modelSize.large.desc
</Trans>
</li>
</ul>
</div>
</div>
@ -271,7 +289,7 @@ export default function ExploreSettingsView({
<div className="flex w-full flex-row items-center gap-2 pt-2 md:w-[25%]">
<Button className="flex flex-1" aria-label="Reset" onClick={onCancel}>
{t("button.reset")}
{t("button.reset", { ns: "common" })}
</Button>
<Button
variant="select"
@ -283,10 +301,10 @@ export default function ExploreSettingsView({
{isLoading ? (
<div className="flex flex-row items-center gap-2">
<ActivityIndicator />
<span>{t("button.saving")}</span>
<span>{t("button.saving", { ns: "common" })}</span>
</div>
) : (
t("button.save")
t("button.save", { ns: "common" })
)}
</Button>
</div>