diff --git a/web/src/components/card/SearchThumbnail.tsx b/web/src/components/card/SearchThumbnail.tsx index 294873e28..b41533f7b 100644 --- a/web/src/components/card/SearchThumbnail.tsx +++ b/web/src/components/card/SearchThumbnail.tsx @@ -12,7 +12,7 @@ import { SearchResult } from "@/types/search"; import { cn } from "@/lib/utils"; import { TooltipPortal } from "@radix-ui/react-tooltip"; import useContextMenu from "@/hooks/use-contextmenu"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; type SearchThumbnailProps = { searchResult: SearchResult; @@ -23,6 +23,7 @@ export default function SearchThumbnail({ searchResult, onClick, }: SearchThumbnailProps) { + const { t } = useTranslation(["views/search"]); const apiHost = useApiHost(); const { data: config } = useSWR("config"); const [imgRef, imgLoaded, onImgLoad] = useImageLoaded(); diff --git a/web/src/components/card/SearchThumbnailFooter.tsx b/web/src/components/card/SearchThumbnailFooter.tsx index 5d01952ca..a24dfdd70 100644 --- a/web/src/components/card/SearchThumbnailFooter.tsx +++ b/web/src/components/card/SearchThumbnailFooter.tsx @@ -6,7 +6,7 @@ import { SearchResult } from "@/types/search"; import ActivityIndicator from "../indicators/activity-indicator"; import SearchResultActions from "../menu/SearchResultActions"; import { cn } from "@/lib/utils"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; type SearchThumbnailProps = { searchResult: SearchResult; @@ -25,14 +25,15 @@ export default function SearchThumbnailFooter({ showObjectLifecycle, showSnapshot, }: SearchThumbnailProps) { + const { t } = useTranslation(["views/search"]); const { data: config } = useSWR("config"); // date const formattedDate = useFormattedTimestamp( searchResult.start_time, config?.ui.time_format == "24hour" - ? t("time.formattedTimestampExcludeSeconds.24hour") - : t("time.formattedTimestampExcludeSeconds"), + ? t("time.formattedTimestampExcludeSeconds.24hour", { ns: "common" }) + : t("time.formattedTimestampExcludeSeconds", { ns: "common" }), config?.ui.timezone, ); diff --git a/web/src/components/filter/CalendarFilterButton.tsx b/web/src/components/filter/CalendarFilterButton.tsx index 91124d65a..524c2a2e6 100644 --- a/web/src/components/filter/CalendarFilterButton.tsx +++ b/web/src/components/filter/CalendarFilterButton.tsx @@ -14,7 +14,6 @@ import { DateRangePicker } from "../ui/calendar-range"; import { DateRange } from "react-day-picker"; import { useState } from "react"; import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog"; -import { t } from "i18next"; import { useTranslation } from "react-i18next"; type CalendarFilterButtonProps = { @@ -98,12 +97,13 @@ export function CalendarRangeFilterButton({ defaultText, updateSelectedRange, }: CalendarRangeFilterButtonProps) { + const { t } = useTranslation(["components/filter"]); const [open, setOpen] = useState(false); const selectedDate = useFormattedRange( range?.from == undefined ? 0 : range.from.getTime() / 1000 + 1, range?.to == undefined ? 0 : range.to.getTime() / 1000 - 1, - t("time.formattedTimestampOnlyMonthAndDay"), + t("time.formattedTimestampOnlyMonthAndDay", { ns: "common" }), ); const trigger = ( diff --git a/web/src/components/filter/LogSettingsButton.tsx b/web/src/components/filter/LogSettingsButton.tsx index 88a0cf44d..56c440352 100644 --- a/web/src/components/filter/LogSettingsButton.tsx +++ b/web/src/components/filter/LogSettingsButton.tsx @@ -10,7 +10,6 @@ import { DropdownMenuSeparator } from "../ui/dropdown-menu"; import { cn } from "@/lib/utils"; import FilterSwitch from "./FilterSwitch"; import { useTranslation } from "react-i18next"; -import { t } from "i18next"; type LogSettingsButtonProps = { selectedLabels?: LogSeverity[]; @@ -101,6 +100,7 @@ export function GeneralFilterContent({ selectedLabels, updateLabelFilter, }: GeneralFilterContentProps) { + const { t } = useTranslation(["components/filter"]); return ( <>
diff --git a/web/src/components/menu/AccountSettings.tsx b/web/src/components/menu/AccountSettings.tsx index 408802b34..061a99e2a 100644 --- a/web/src/components/menu/AccountSettings.tsx +++ b/web/src/components/menu/AccountSettings.tsx @@ -20,18 +20,19 @@ import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { DialogClose } from "../ui/dialog"; import { LuLogOut, LuSquarePen } from "react-icons/lu"; import useSWR from "swr"; -import { t } from "i18next"; import { useState } from "react"; import axios from "axios"; import { toast } from "sonner"; import SetPasswordDialog from "../overlay/SetPasswordDialog"; +import { useTranslation } from "react-i18next"; type AccountSettingsProps = { className?: string; }; export default function AccountSettings({ className }: AccountSettingsProps) { + const { t } = useTranslation(["views/settings"]); const { data: profile } = useSWR("profile"); const { data: config } = useSWR("config"); const logoutUrl = config?.proxy?.logout_url || `${baseUrl}api/logout`; @@ -50,12 +51,9 @@ export default function AccountSettings({ className }: AccountSettingsProps) { .then((response) => { if (response.status === 200) { setPasswordDialogOpen(false); - toast.success( - t("users.toast.success.updatePassword", { ns: "views/settings" }), - { - position: "top-center", - }, - ); + toast.success(t("users.toast.success.updatePassword"), { + position: "top-center", + }); } }) .catch((error) => { @@ -65,7 +63,6 @@ export default function AccountSettings({ className }: AccountSettingsProps) { "Unknown error"; toast.error( t("users.toast.error.setPasswordFailed", { - ns: "views/settings", errorMessage, }), { @@ -94,7 +91,7 @@ export default function AccountSettings({ className }: AccountSettingsProps) { -

{t("menu.user.account")}

+

{t("menu.user.account", { ns: "common" })}

@@ -107,9 +104,12 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
{t("menu.user.current", { - user: profile?.username || t("menu.user.anonymous"), + ns: "common", + user: + profile?.username || t("menu.user.anonymous", { ns: "common" }), })}{" "} - {t("role." + profile?.role) && `(${t("role." + profile?.role)})`} + {t("role." + profile?.role) && + `(${t("role." + profile?.role, { ns: "common" })})`} {profile?.username && profile.username !== "anonymous" && ( @@ -117,22 +117,22 @@ export default function AccountSettings({ className }: AccountSettingsProps) { className={ isDesktop ? "cursor-pointer" : "flex items-center p-2 text-sm" } - aria-label={t("menu.user.setPassword")} + aria-label={t("menu.user.setPassword", { ns: "common" })} onClick={() => setPasswordDialogOpen(true)} > - {t("menu.user.setPassword")} + {t("menu.user.setPassword", { ns: "common" })} )} - {t("menu.user.logout")} + {t("menu.user.logout", { ns: "common" })}
diff --git a/web/src/components/menu/GeneralSettings.tsx b/web/src/components/menu/GeneralSettings.tsx index 918600bf4..45e567868 100644 --- a/web/src/components/menu/GeneralSettings.tsx +++ b/web/src/components/menu/GeneralSettings.tsx @@ -54,7 +54,6 @@ import { TooltipPortal } from "@radix-ui/react-tooltip"; import { cn } from "@/lib/utils"; import useSWR from "swr"; import RestartDialog from "../overlay/dialog/RestartDialog"; -import { t } from "i18next"; import { useLanguage } from "@/context/language-provider"; import { useIsAdmin } from "@/hooks/use-is-admin"; @@ -62,12 +61,14 @@ import SetPasswordDialog from "../overlay/SetPasswordDialog"; import { toast } from "sonner"; import axios from "axios"; import { FrigateConfig } from "@/types/frigateConfig"; +import { useTranslation } from "react-i18next"; type GeneralSettingsProps = { className?: string; }; export default function GeneralSettings({ className }: GeneralSettingsProps) { + const { t } = useTranslation(["common"]); const { data: profile } = useSWR("profile"); const { data: config } = useSWR("config"); const logoutUrl = config?.proxy?.logout_url || "/api/logout"; diff --git a/web/src/components/mobile/MobilePage.tsx b/web/src/components/mobile/MobilePage.tsx index 22305614a..8330f0a64 100644 --- a/web/src/components/mobile/MobilePage.tsx +++ b/web/src/components/mobile/MobilePage.tsx @@ -5,7 +5,7 @@ import { IoMdArrowRoundBack } from "react-icons/io"; import { cn } from "@/lib/utils"; import { isPWA } from "@/utils/isPWA"; import { Button } from "@/components/ui/button"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; const MobilePageContext = createContext<{ open: boolean; @@ -139,6 +139,7 @@ export function MobilePageHeader({ onClose, ...props }: MobilePageHeaderProps) { + const { t } = useTranslation(["common"]); const context = useContext(MobilePageContext); if (!context) throw new Error("MobilePageHeader must be used within MobilePage"); diff --git a/web/src/components/navigation/NavItem.tsx b/web/src/components/navigation/NavItem.tsx index a662b0a28..f8ee7eb0d 100644 --- a/web/src/components/navigation/NavItem.tsx +++ b/web/src/components/navigation/NavItem.tsx @@ -9,7 +9,7 @@ import { TooltipPortal } from "@radix-ui/react-tooltip"; import { NavData } from "@/types/navigation"; import { IconType } from "react-icons"; import { cn } from "@/lib/utils"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; const variants = { primary: { @@ -35,6 +35,7 @@ export default function NavItem({ Icon, onClick, }: NavItemProps) { + const { t } = useTranslation(["common"]); if (item.enabled == false) { return; } diff --git a/web/src/components/overlay/MobileCameraDrawer.tsx b/web/src/components/overlay/MobileCameraDrawer.tsx index 49ccf739a..742de1242 100644 --- a/web/src/components/overlay/MobileCameraDrawer.tsx +++ b/web/src/components/overlay/MobileCameraDrawer.tsx @@ -3,7 +3,7 @@ import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { Button } from "../ui/button"; import { FaVideo } from "react-icons/fa"; import { isMobile } from "react-device-detect"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; type MobileCameraDrawerProps = { allCameras: string[]; @@ -15,6 +15,7 @@ export default function MobileCameraDrawer({ selected, onSelectCamera, }: MobileCameraDrawerProps) { + const { t } = useTranslation(["common"]); const [cameraDrawer, setCameraDrawer] = useState(false); if (!isMobile) { diff --git a/web/src/components/player/PreviewThumbnailPlayer.tsx b/web/src/components/player/PreviewThumbnailPlayer.tsx index 15313e0b9..fe05a6676 100644 --- a/web/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web/src/components/player/PreviewThumbnailPlayer.tsx @@ -21,7 +21,7 @@ import { cn } from "@/lib/utils"; import { InProgressPreview, VideoPreview } from "../preview/ScrubbablePreview"; import { Preview } from "@/types/preview"; import { baseUrl } from "@/api/baseUrl"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; type PreviewPlayerProps = { review: ReviewSegment; @@ -42,6 +42,7 @@ export default function PreviewThumbnailPlayer({ onClick, onTimeUpdate, }: PreviewPlayerProps) { + const { t } = useTranslation(["components/player"]); const apiHost = useApiHost(); const { data: config } = useSWR("config"); const [imgRef, imgLoaded, onImgLoad] = useImageLoaded(); @@ -169,8 +170,8 @@ export default function PreviewThumbnailPlayer({ const formattedDate = useFormattedTimestamp( review.start_time, config?.ui.time_format == "24hour" - ? t("time.formattedTimestampExcludeSeconds.24hour") - : t("time.formattedTimestampExcludeSeconds"), + ? t("time.formattedTimestampExcludeSeconds.24hour", { ns: "common" }) + : t("time.formattedTimestampExcludeSeconds", { ns: "common" }), config?.ui?.timezone, ); diff --git a/web/src/components/ui/calendar-range.tsx b/web/src/components/ui/calendar-range.tsx index 148fe3b19..e360010b4 100644 --- a/web/src/components/ui/calendar-range.tsx +++ b/web/src/components/ui/calendar-range.tsx @@ -12,7 +12,9 @@ import { import { Switch } from "./switch"; import { cn } from "@/lib/utils"; import { LuCheck } from "react-icons/lu"; -import { t } from "i18next"; +import { useTranslation } from "react-i18next"; + +const { t } = useTranslation(["common"]); export interface DateRangePickerProps { diff --git a/web/src/components/ui/pagination.tsx b/web/src/components/ui/pagination.tsx index 0926a3d25..6d7a25073 100644 --- a/web/src/components/ui/pagination.tsx +++ b/web/src/components/ui/pagination.tsx @@ -3,7 +3,9 @@ import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react" import { cn } from "@/lib/utils" import { ButtonProps, buttonVariants } from "@/components/ui/button" -import { t } from "i18next" +import { useTranslation } from "react-i18next" + +const { t } = useTranslation(["common"]) const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (