mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-18 17:14:26 +03:00
add more translation
This commit is contained in:
parent
f45242d22c
commit
2ace4b896a
@ -1,12 +1,106 @@
|
||||
{
|
||||
"object.person": "Person",
|
||||
"object.cat": "Cat",
|
||||
"object.bicycle": "Bicycle",
|
||||
"object.car": "Car",
|
||||
"object.motorcycle": "Motorcycle",
|
||||
"object.airplane": "Airplane",
|
||||
"object.bus": "Bus",
|
||||
"object.train": "Train",
|
||||
"object.boat": "Boat",
|
||||
"object.traffic_light": "Traffic Light",
|
||||
"object.fire_hydrant": "Fire Hydrant",
|
||||
"object.street_sign": "Street Sign",
|
||||
"object.stop_sign": "Stop Sign",
|
||||
"object.parking_meter": "Parking Meter",
|
||||
"object.bench": "Bench",
|
||||
"object.bird": "Bird",
|
||||
"object.cat": "Cat",
|
||||
"object.dog": "Dog",
|
||||
"object.horse": "Horse",
|
||||
"object.sheep": "Sheep",
|
||||
"object.cow": "Cow",
|
||||
"object.elephant": "Elephant",
|
||||
"object.bear": "Bear",
|
||||
"object.zebra": "Zebra",
|
||||
"object.giraffe": "Giraffe",
|
||||
"object.hat": "Hat",
|
||||
"object.backpack": "Backpack",
|
||||
"object.umbrella": "Umbrella",
|
||||
"object.shoe": "Shoe",
|
||||
"object.eye_glasses": "Eye Glasses",
|
||||
"object.handbag": "Handbag",
|
||||
"object.tie": "Tie",
|
||||
"object.suitcase": "Suitcase",
|
||||
"object.frisbee": "Frisbee",
|
||||
"object.skis": "Skis",
|
||||
"object.snowboard": "Snowboard",
|
||||
"object.sports_ball": "Sports Ball",
|
||||
"object.kite": "Kite",
|
||||
"object.baseball_bat": "Baseball Bat",
|
||||
"object.baseball_glove": "Baseball Glove",
|
||||
"object.skateboard": "Skateboard",
|
||||
"object.surfboard": "Surfboard",
|
||||
"object.tennis_racket": "Tennis Racket",
|
||||
"object.bottle": "Bottle",
|
||||
"object.plate": "Plate",
|
||||
"object.wine_glass": "Wine Glass",
|
||||
"object.cup": "Cup",
|
||||
"object.fork": "Fork",
|
||||
"object.knife": "Knife",
|
||||
"object.spoon": "Spoon",
|
||||
"object.bowl": "Bowl",
|
||||
"object.banana": "Banana",
|
||||
"object.apple": "Apple",
|
||||
"object.sandwich": "Sandwich",
|
||||
"object.orange": "Orange",
|
||||
"object.broccoli": "Broccoli",
|
||||
"object.carrot": "Carrot",
|
||||
"object.hot_dog": "Hot Dog",
|
||||
"object.pizza": "Pizza",
|
||||
"object.donut": "Donut",
|
||||
"object.cake": "Cake",
|
||||
"object.chair": "Chair",
|
||||
"object.couch": "Couch",
|
||||
"object.potted_plant": "Potted Plant",
|
||||
"object.bed": "Bed",
|
||||
"object.mirror": "Mirror",
|
||||
"object.dining_table": "Dining Table",
|
||||
"object.window": "Window",
|
||||
"object.desk": "Desk",
|
||||
"object.toilet": "Toilet",
|
||||
"object.door": "Door",
|
||||
"object.tv": "TV",
|
||||
"object.laptop": "Laptop",
|
||||
"object.mouse": "Mouse",
|
||||
"object.remote": "Remote",
|
||||
"object.keyboard": "Keyboard",
|
||||
"object.cell_phone": "Cell Phone",
|
||||
"object.microwave": "Microwave",
|
||||
"object.oven": "Oven",
|
||||
"object.toaster": "Toaster",
|
||||
"object.sink": "Sink",
|
||||
"object.refrigerator": "Refrigerator",
|
||||
"object.blender": "Blender",
|
||||
"object.book": "Book",
|
||||
"object.clock": "Clock",
|
||||
"object.vase": "Vase",
|
||||
"object.scissors": "Scissors",
|
||||
"object.teddy_bear": "Teddy Bear",
|
||||
"object.hair_dryer": "Hair Dryer",
|
||||
"object.toothbrush": "Toothbrush",
|
||||
"object.hair_brush": "Hair Brush",
|
||||
|
||||
"ui.time.justNow": "Just now",
|
||||
|
||||
"ui.dialog.restart.title": "Are you sure you want to restart Frigate?",
|
||||
"ui.dialog.restart.button": "Restart",
|
||||
"ui.dialog.restart.restarting.title": "Frigate is Restarting",
|
||||
"ui.dialog.restart.restarting.content": "This page will reload in {{countdown}} seconds.",
|
||||
"ui.dialog.restart.restarting.button": "Force Reload Now",
|
||||
|
||||
"ui.stats.ffmpegHighCpuUsage": "{{camera}} has high FFMPEG CPU usage ({{ffmpegAvg}}%)",
|
||||
"ui.stats.detectHighCpuUsage": "{{camera}} has high detect CPU usage ({{detectAvg}}%)",
|
||||
"ui.stats.healthy": "System is healthy",
|
||||
|
||||
"ui.system.general": "General",
|
||||
"ui.system.storage": "Storage",
|
||||
@ -116,7 +210,38 @@
|
||||
"ui.save": "Save",
|
||||
"ui.saving": "Saving...",
|
||||
"ui.cancel": "Cancel",
|
||||
"ui.close": "Close",
|
||||
"ui.copy": "Copy",
|
||||
"ui.back": "Back",
|
||||
"ui.history": "History",
|
||||
"ui.fullscreen": "Fullscreen",
|
||||
"ui.pictureInPicture": "Picture in Picture",
|
||||
"ui.on": "ON",
|
||||
"ui.off": "OFF",
|
||||
"ui.delete": "Delete",
|
||||
|
||||
"ui.live.twoWayTalk.enable": "Enable Two Way Talk",
|
||||
"ui.live.twoWayTalk.disable": "Disable Two Way Talk",
|
||||
"ui.live.cameraAudio.enable": "Enable Camera Audio",
|
||||
"ui.live.cameraAudio.disable": "Disable Camera Audio",
|
||||
"ui.live.ptz.move.left.label": "Move PTZ camera to the left",
|
||||
"ui.live.ptz.move.up.label": "Move PTZ camera up",
|
||||
"ui.live.ptz.move.down.label": "Move PTZ camera down",
|
||||
"ui.live.ptz.move.right.label": "Move PTZ camera to the right",
|
||||
"ui.live.ptz.zoom.in.label": "Zoom PTZ camera in",
|
||||
"ui.live.ptz.zoom.out.label": "Zoom PTZ camera out",
|
||||
"ui.live.ptz.frame.center.label": "Click in the frame to center the PTZ camera",
|
||||
|
||||
"ui.live.detect.enable": "Enable Detect",
|
||||
"ui.live.detect.disable": "Disable Detect",
|
||||
"ui.live.recording.enable": "Enable Recording",
|
||||
"ui.live.recording.disable": "Disable Recording",
|
||||
"ui.live.snapshots.enable": "Enable Snapshots",
|
||||
"ui.live.snapshots.disable": "Disable Snapshots",
|
||||
"ui.live.audioDetect.enable": "Enable Audio Detect",
|
||||
"ui.live.audioDetect.disable": "Disable Audio Detect",
|
||||
"ui.live.autotracking.enable": "Enable Autotracking",
|
||||
"ui.live.autotracking.disable": "Disable Autotracking",
|
||||
|
||||
"ui.calendarFilter.last24Hours": "Last 24 Hours",
|
||||
|
||||
@ -256,6 +381,27 @@
|
||||
"ui.settingView.debug.regions.desc": "Show a box of the region of interest sent to the object detector",
|
||||
"ui.settingView.debug.regions.tips": "<p className=\"mb-2\"><strong>Region Boxes</strong></p><br><p>Bright green boxes will be overlaid on areas of interest in the frame that are being sent to the object detector.</p>",
|
||||
|
||||
"ui.settingView.users": "Users",
|
||||
"ui.settingView.users.addUser": "Add User",
|
||||
"ui.settingView.users.updatePassword": "Update Password",
|
||||
"ui.settingView.users.dialog.createUser": "Create User",
|
||||
"ui.settingView.users.dialog.createUser.user": "User",
|
||||
"ui.settingView.users.dialog.createUser.password": "Password",
|
||||
"ui.settingView.users.dialog.deleteUser": "Delete User",
|
||||
"ui.settingView.users.dialog.deleteUser.warn": "Are you sure?",
|
||||
"ui.settingView.users.dialog.setPassword": "Set Password",
|
||||
|
||||
"ui.settingView.notification": "Notifications",
|
||||
"ui.settingView.notification.notificationSettings": "Notification Settings",
|
||||
"ui.settingView.notification.desc": "Frigate can natively send push notifications to your device when it is running in the browser or installed as a PWA.",
|
||||
"ui.settingView.notification.documentation": "Read the Documentation",
|
||||
"ui.settingView.notification.email": "Email",
|
||||
"ui.settingView.notification.email.placeholder": "example@email.com",
|
||||
"ui.settingView.notification.email.desc": "Entering a valid email is required, as this is used by the push server in case problems occur.",
|
||||
"ui.settingView.notification.registerDevice": "Register for notifications on this device",
|
||||
"ui.settingView.notification.unregisterDevice": "Unregister for notifications on this device",
|
||||
|
||||
|
||||
"ui.configEditorView.configEditor": "Config Editor",
|
||||
"ui.configEditorView.copyConfig": "Copy Config",
|
||||
"ui.configEditorView.saveAndRestart": "Save & Restart",
|
||||
|
||||
@ -1,13 +1,107 @@
|
||||
{
|
||||
|
||||
"object.person": "人",
|
||||
"object.bicycle": "自行车",
|
||||
"object.car": "汽车",
|
||||
"object.motorcycle": "摩托车",
|
||||
"object.airplane": "飞机",
|
||||
"object.bus": "公交车",
|
||||
"object.train": "火车",
|
||||
"object.boat": "船",
|
||||
"object.traffic_light": "交通灯",
|
||||
"object.fire_hydrant": "消防栓",
|
||||
"object.street_sign": "路标",
|
||||
"object.stop_sign": "停车标志",
|
||||
"object.parking_meter": "停车计时器",
|
||||
"object.bench": "长椅",
|
||||
"object.bird": "鸟",
|
||||
"object.cat": "猫",
|
||||
"object.car": "车",
|
||||
"object.dog": "狗",
|
||||
"object.horse": "马",
|
||||
"object.sheep": "羊",
|
||||
"object.cow": "牛",
|
||||
"object.elephant": "大象",
|
||||
"object.bear": "熊",
|
||||
"object.zebra": "斑马",
|
||||
"object.giraffe": "长颈鹿",
|
||||
"object.hat": "帽子",
|
||||
"object.backpack": "背包",
|
||||
"object.umbrella": "雨伞",
|
||||
"object.shoe": "鞋子",
|
||||
"object.eye_glasses": "眼镜",
|
||||
"object.handbag": "手提包",
|
||||
"object.tie": "领带",
|
||||
"object.suitcase": "手提箱",
|
||||
"object.frisbee": "飞盘",
|
||||
"object.skis": "滑雪板",
|
||||
"object.snowboard": "滑雪板",
|
||||
"object.sports_ball": "运动球",
|
||||
"object.kite": "风筝",
|
||||
"object.baseball_bat": "棒球棒",
|
||||
"object.baseball_glove": "棒球手套",
|
||||
"object.skateboard": "滑板",
|
||||
"object.surfboard": "冲浪板",
|
||||
"object.tennis_racket": "网球拍",
|
||||
"object.bottle": "瓶子",
|
||||
"object.plate": "盘子",
|
||||
"object.wine_glass": "酒杯",
|
||||
"object.cup": "杯子",
|
||||
"object.fork": "叉子",
|
||||
"object.knife": "刀",
|
||||
"object.spoon": "勺子",
|
||||
"object.bowl": "碗",
|
||||
"object.banana": "香蕉",
|
||||
"object.apple": "苹果",
|
||||
"object.sandwich": "三明治",
|
||||
"object.orange": "橙子",
|
||||
"object.broccoli": "西兰花",
|
||||
"object.carrot": "胡萝卜",
|
||||
"object.hot_dog": "热狗",
|
||||
"object.pizza": "披萨",
|
||||
"object.donut": "甜甜圈",
|
||||
"object.cake": "蛋糕",
|
||||
"object.chair": "椅子",
|
||||
"object.couch": "沙发",
|
||||
"object.potted_plant": "盆栽植物",
|
||||
"object.bed": "床",
|
||||
"object.mirror": "镜子",
|
||||
"object.dining_table": "餐桌",
|
||||
"object.window": "窗户",
|
||||
"object.desk": "桌子",
|
||||
"object.toilet": "厕所",
|
||||
"object.door": "门",
|
||||
"object.tv": "电视",
|
||||
"object.laptop": "笔记本电脑",
|
||||
"object.mouse": "鼠标",
|
||||
"object.remote": "遥控器",
|
||||
"object.keyboard": "键盘",
|
||||
"object.cell_phone": "手机",
|
||||
"object.microwave": "微波炉",
|
||||
"object.oven": "烤箱",
|
||||
"object.toaster": "烤面包机",
|
||||
"object.sink": "水槽",
|
||||
"object.refrigerator": "冰箱",
|
||||
"object.blender": "搅拌机",
|
||||
"object.book": "书",
|
||||
"object.clock": "时钟",
|
||||
"object.vase": "花瓶",
|
||||
"object.scissors": "剪刀",
|
||||
"object.teddy_bear": "泰迪熊",
|
||||
"object.hair_dryer": "吹风机",
|
||||
"object.toothbrush": "牙刷",
|
||||
"object.hair_brush": "发刷",
|
||||
|
||||
"ui.time.justNow": "刚才",
|
||||
|
||||
"ui.dialog.restart.title": "你确定要重启 Frigate?",
|
||||
"ui.dialog.restart.button": "重启",
|
||||
"ui.dialog.restart.restarting.title": "Frigate 正在重启",
|
||||
"ui.dialog.restart.restarting.content": "该页面将会在 {{countdown}} 秒后自动刷新。",
|
||||
"ui.dialog.restart.restarting.button": "强制刷新",
|
||||
|
||||
"ui.stats.ffmpegHighCpuUsage": "{{camera}} 的 FFMPEG CPU 使用率较高({{ffmpegAvg}}%)",
|
||||
"ui.stats.detectHighCpuUsage": "{{camera}} 的 探测 CPU 使用率较高({{detectAvg}}%)",
|
||||
"ui.stats.healthy": "系统运行正常",
|
||||
|
||||
"ui.system.general": "常规",
|
||||
"ui.system.storage": "存储",
|
||||
@ -117,7 +211,39 @@
|
||||
"ui.save": "保存",
|
||||
"ui.saving": "保存中……",
|
||||
"ui.cancel": "取消",
|
||||
"ui.close": "关闭",
|
||||
"ui.copy": "复制",
|
||||
"ui.back": "返回",
|
||||
"ui.history": "历史",
|
||||
"ui.fullscreen": "全屏",
|
||||
"ui.exitFullscreen": "退出全屏",
|
||||
"ui.pictureInPicture": "画中画",
|
||||
"ui.on": "开",
|
||||
"ui.off": "关",
|
||||
"ui.delete": "删除",
|
||||
|
||||
"ui.live.twoWayTalk.enable": "开启双向对话",
|
||||
"ui.live.twoWayTalk.disable": "关闭双向对话",
|
||||
"ui.live.cameraAudio.enable": "开启摄像头音频",
|
||||
"ui.live.cameraAudio.disable": "关闭摄像头音频",
|
||||
"ui.live.ptz.move.left.label": "PTZ摄像头向左移动",
|
||||
"ui.live.ptz.move.up.label": "PTZ摄像头向上移动",
|
||||
"ui.live.ptz.move.down.label": "PTZ摄像头向下移动",
|
||||
"ui.live.ptz.move.right.label": "PTZ摄像头向右移动",
|
||||
"ui.live.ptz.zoom.in.label": "PTZ摄像头放大",
|
||||
"ui.live.ptz.zoom.out.label": "PTZ摄像头缩小",
|
||||
"ui.live.ptz.frame.center.label": "点击将PTZ摄像头画面居中",
|
||||
|
||||
"ui.live.detect.enable": "启用检测",
|
||||
"ui.live.detect.disable": "关闭检测",
|
||||
"ui.live.recording.enable": "启用录制",
|
||||
"ui.live.recording.disable": "关闭录制",
|
||||
"ui.live.snapshots.enable": "启用快照",
|
||||
"ui.live.snapshots.disable": "关闭快照",
|
||||
"ui.live.audioDetect.enable": "启用音频检测",
|
||||
"ui.live.audioDetect.disable": "关闭音频检测",
|
||||
"ui.live.autotracking.enable": "启用自动追踪",
|
||||
"ui.live.autotracking.disable": "关闭自动追踪",
|
||||
|
||||
"ui.calendarFilter.last24Hours": "过去24小时",
|
||||
|
||||
@ -257,6 +383,27 @@
|
||||
"ui.settingView.debug.regions.desc": "显示发送到运动检测器感兴趣范围的框。",
|
||||
"ui.settingView.debug.regions.tips": "<p className=\"mb-2\"><strong>范围框</strong></p><br><p>将在帧中发送到目标检测器的感兴趣范围上叠加绿色框。</p>",
|
||||
|
||||
"ui.settingView.users": "用户管理",
|
||||
"ui.settingView.users.addUser": "添加用户",
|
||||
"ui.settingView.users.updatePassword": "修改密码",
|
||||
"ui.settingView.users.dialog.createUser": "创建用户",
|
||||
"ui.settingView.users.dialog.createUser.user": "用户名",
|
||||
"ui.settingView.users.dialog.createUser.password": "密码",
|
||||
"ui.settingView.users.dialog.deleteUser": "删除该用户",
|
||||
"ui.settingView.users.dialog.deleteUser.warn": "你确定要删除该用户吗?",
|
||||
"ui.settingView.users.dialog.setPassword": "修改密码",
|
||||
|
||||
"ui.settingView.notification": "通知",
|
||||
"ui.settingView.notification.notificationSettings": "通知设置",
|
||||
"ui.settingView.notification.desc": "Frigate 在浏览器中运行或作为 PWA 安装时,可以原生向您的设备发送推送通知。",
|
||||
"ui.settingView.notification.documentation": "阅读文档(英文)",
|
||||
"ui.settingView.notification.email": "电子邮箱",
|
||||
"ui.settingView.notification.email.placeholder": "例如:example@email.com",
|
||||
"ui.settingView.notification.email.desc": "Frigate 在浏览器中运行或作为 PWA 应用安装时,可以原生向你的设备发送推送通知。",
|
||||
"ui.settingView.notification.registerDevice": "为这个设备注册通知",
|
||||
"ui.settingView.notification.unregisterDevice": "取消这个设备注册通知",
|
||||
|
||||
|
||||
"ui.configEditorView.configEditor": "配置编辑器",
|
||||
"ui.configEditorView.copyConfig": "复制配置",
|
||||
"ui.configEditorView.saveAndRestart": "保存并重启",
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
} from "@/context/statusbar-provider";
|
||||
import useStats, { useAutoFrigateStats } from "@/hooks/use-stats";
|
||||
import { useContext, useEffect, useMemo } from "react";
|
||||
import { Trans } from "react-i18next";
|
||||
import { FaCheck } from "react-icons/fa";
|
||||
import { IoIosWarning } from "react-icons/io";
|
||||
import { MdCircle } from "react-icons/md";
|
||||
@ -129,7 +130,7 @@ export default function Statusbar() {
|
||||
{Object.entries(messages).length === 0 ? (
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<FaCheck className="size-3 text-green-500" />
|
||||
System is healthy
|
||||
<Trans>ui.stats.healthy</Trans>
|
||||
</div>
|
||||
) : (
|
||||
Object.entries(messages).map(([key, messageArray]) => (
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "../ui/dialog";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
type CreateUserOverlayProps = {
|
||||
show: boolean;
|
||||
@ -63,7 +64,7 @@ export default function CreateUserDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create User</DialogTitle>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.createUser</Trans></DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
@ -71,7 +72,7 @@ export default function CreateUserDialog({
|
||||
name="user"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>User</FormLabel>
|
||||
<FormLabel><Trans>ui.settingView.users.dialog.createUser.user</Trans></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]"
|
||||
@ -86,7 +87,7 @@ export default function CreateUserDialog({
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormLabel><Trans>ui.settingView.users.dialog.createUser.password</Trans></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]"
|
||||
@ -104,7 +105,7 @@ export default function CreateUserDialog({
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading && <ActivityIndicator className="mr-2 h-4 w-4" />}
|
||||
Create User
|
||||
<Trans>ui.settingView.users.dialog.createUser</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { Trans } from "react-i18next";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@ -21,9 +22,9 @@ export default function DeleteUserDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Delete User</DialogTitle>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.deleteUser</Trans></DialogTitle>
|
||||
</DialogHeader>
|
||||
<div>Are you sure?</div>
|
||||
<div><Trans>ui.settingView.users.dialog.deleteUser.warn</Trans></div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
@ -32,7 +33,7 @@ export default function DeleteUserDialog({
|
||||
size="sm"
|
||||
onClick={onDelete}
|
||||
>
|
||||
Delete
|
||||
<Trans>ui.delete</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "../ui/dialog";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
type SetPasswordProps = {
|
||||
show: boolean;
|
||||
@ -25,7 +26,7 @@ export default function SetPasswordDialog({
|
||||
<Dialog open={show} onOpenChange={onCancel}>
|
||||
<DialogContent onOpenAutoFocus={(e) => e.preventDefault()}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Set Password</DialogTitle>
|
||||
<DialogTitle><Trans>ui.settingView.users.dialog.setPassword</Trans></DialogTitle>
|
||||
</DialogHeader>
|
||||
<Input
|
||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||
@ -43,7 +44,7 @@ export default function SetPasswordDialog({
|
||||
onSave(password!);
|
||||
}}
|
||||
>
|
||||
Save
|
||||
<Trans>ui.save</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
import { Button } from "@/components/ui/button";
|
||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||
import { baseUrl } from "@/api/baseUrl";
|
||||
import { t } from "i18next";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
type RestartDialogProps = {
|
||||
isOpen: boolean;
|
||||
@ -79,13 +81,13 @@ export default function RestartDialog({
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
Are you sure you want to restart Frigate?
|
||||
<Trans>ui.dialog.restart.title</Trans>
|
||||
</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogCancel><Trans>ui.cancel</Trans></AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleRestart}>
|
||||
Restart
|
||||
<Trans>ui.dialog.restart.button</Trans>
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
@ -100,10 +102,10 @@ export default function RestartDialog({
|
||||
<ActivityIndicator />
|
||||
<SheetHeader className="mt-5 text-center">
|
||||
<SheetTitle className="text-center">
|
||||
Frigate is Restarting
|
||||
<Trans>ui.dialog.restart.restarting.title</Trans>
|
||||
</SheetTitle>
|
||||
<SheetDescription className="text-center">
|
||||
<div>This page will reload in {countdown} seconds.</div>
|
||||
<div>{t("ui.dialog.restart.restarting.content", {countdown})}</div>
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<Button
|
||||
@ -112,7 +114,7 @@ export default function RestartDialog({
|
||||
aria-label="Force reload now"
|
||||
onClick={handleForceReload}
|
||||
>
|
||||
Force Reload Now
|
||||
<Trans>ui.dialog.restart.restarting.button</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
</SheetContent>
|
||||
|
||||
@ -42,6 +42,7 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import useCameraLiveMode from "@/hooks/use-camera-live-mode";
|
||||
import { t } from "i18next";
|
||||
|
||||
type DraggableGridLayoutProps = {
|
||||
cameras: CameraConfig[];
|
||||
@ -519,7 +520,7 @@ export default function DraggableGridLayout({
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{fullscreen ? "Exit Fullscreen" : "Fullscreen"}
|
||||
{fullscreen ? t("ui.exitFullscreen") : t("ui.fullscreen")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</>
|
||||
|
||||
@ -85,6 +85,8 @@ import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
|
||||
import useSWR from "swr";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useSessionPersistence } from "@/hooks/use-session-persistence";
|
||||
import { Trans } from "react-i18next";
|
||||
import { t } from "i18next";
|
||||
|
||||
type LiveCameraViewProps = {
|
||||
config?: FrigateConfig;
|
||||
@ -363,7 +365,7 @@ export default function LiveCameraView({
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
<IoMdArrowRoundBack className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && <div className="text-primary">Back</div>}
|
||||
{isDesktop && <div className="text-primary"><Trans>ui.back</Trans></div>}
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-2.5 rounded-lg"
|
||||
@ -383,7 +385,7 @@ export default function LiveCameraView({
|
||||
}}
|
||||
>
|
||||
<LuHistory className="size-5 text-secondary-foreground" />
|
||||
{isDesktop && <div className="text-primary">History</div>}
|
||||
{isDesktop && <div className="text-primary"><Trans>ui.history</Trans></div>}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
@ -412,7 +414,7 @@ export default function LiveCameraView({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={fullscreen ? FaCompress : FaExpand}
|
||||
isActive={fullscreen}
|
||||
title={fullscreen ? "Close" : "Fullscreen"}
|
||||
title={fullscreen ? t("ui.close") : t("ui.fullscreen")}
|
||||
onClick={toggleFullscreen}
|
||||
/>
|
||||
)}
|
||||
@ -422,7 +424,7 @@ export default function LiveCameraView({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={LuPictureInPicture}
|
||||
isActive={pip}
|
||||
title={pip ? "Close" : "Picture in Picture"}
|
||||
title={pip ? t("ui.close") : t("ui.pictureInPicture")}
|
||||
onClick={() => {
|
||||
if (!pip) {
|
||||
setPip(true);
|
||||
@ -665,7 +667,7 @@ function PtzControlPanel({
|
||||
{ptz?.features?.includes("pt") && (
|
||||
<>
|
||||
<TooltipButton
|
||||
label="Move camera left"
|
||||
label={t("ui.live.ptz.move.left.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_LEFT");
|
||||
@ -680,7 +682,7 @@ function PtzControlPanel({
|
||||
<FaAngleLeft />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
label="Move camera up"
|
||||
label={t("ui.live.ptz.move.up.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_UP");
|
||||
@ -695,7 +697,7 @@ function PtzControlPanel({
|
||||
<FaAngleUp />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
label="Move camera down"
|
||||
label={t("ui.live.ptz.move.down.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_DOWN");
|
||||
@ -710,7 +712,7 @@ function PtzControlPanel({
|
||||
<FaAngleDown />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
label="Move camera right"
|
||||
label={t("ui.live.ptz.move.right.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("MOVE_RIGHT");
|
||||
@ -729,7 +731,7 @@ function PtzControlPanel({
|
||||
{ptz?.features?.includes("zoom") && (
|
||||
<>
|
||||
<TooltipButton
|
||||
label="Zoom in"
|
||||
label={t("ui.live.ptz.zoom.in.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("ZOOM_IN");
|
||||
@ -744,7 +746,7 @@ function PtzControlPanel({
|
||||
<MdZoomIn />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
label="Zoom out"
|
||||
label={t("ui.live.ptz.zoom.out.label")}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
sendPtz("ZOOM_OUT");
|
||||
@ -847,7 +849,7 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={detectState == "ON" ? MdPersonSearch : MdPersonOff}
|
||||
isActive={detectState == "ON"}
|
||||
title={`${detectState == "ON" ? "Disable" : "Enable"} Detect`}
|
||||
title={detectState == "ON" ? t("ui.live.detect.disable") : t("ui.live.detect.enable")}
|
||||
onClick={() => sendDetect(detectState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
@ -855,7 +857,7 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={recordState == "ON" ? LuVideo : LuVideoOff}
|
||||
isActive={recordState == "ON"}
|
||||
title={`${recordState == "ON" ? "Disable" : "Enable"} Recording`}
|
||||
title={recordState == "ON" ? t("ui.live.recording.disable") : t("ui.live.recording.enable")}
|
||||
onClick={() => sendRecord(recordState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
<CameraFeatureToggle
|
||||
@ -863,7 +865,7 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={snapshotState == "ON" ? MdPhotoCamera : MdNoPhotography}
|
||||
isActive={snapshotState == "ON"}
|
||||
title={`${snapshotState == "ON" ? "Disable" : "Enable"} Snapshots`}
|
||||
title={snapshotState == "ON" ? t("ui.live.snapshots.disable") : t("ui.live.snapshots.enable")}
|
||||
onClick={() => sendSnapshot(snapshotState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
{audioDetectEnabled && (
|
||||
@ -872,7 +874,7 @@ 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("ui.live.audioDetect.disable") : t("ui.live.audioDetect.enable")}
|
||||
onClick={() => sendAudio(audioState == "ON" ? "OFF" : "ON")}
|
||||
/>
|
||||
)}
|
||||
@ -882,7 +884,7 @@ function FrigateCameraFeatures({
|
||||
variant={fullscreen ? "overlay" : "primary"}
|
||||
Icon={autotrackingState == "ON" ? TbViewfinder : TbViewfinderOff}
|
||||
isActive={autotrackingState == "ON"}
|
||||
title={`${autotrackingState == "ON" ? "Disable" : "Enable"} Autotracking`}
|
||||
title={autotrackingState == "ON" ? t("ui.live.autotracking.disable") : t("ui.live.autotracking.enable")}
|
||||
onClick={() =>
|
||||
sendAutotracking(autotrackingState == "ON" ? "OFF" : "ON")
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import { LivePlayerError } from "@/types/live";
|
||||
import { FaCompress, FaExpand } from "react-icons/fa";
|
||||
import useCameraLiveMode from "@/hooks/use-camera-live-mode";
|
||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||
import { t } from "i18next";
|
||||
|
||||
type LiveDashboardViewProps = {
|
||||
cameras: CameraConfig[];
|
||||
@ -387,7 +388,7 @@ export default function LiveDashboardView({
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{fullscreen ? "Exit Fullscreen" : "Fullscreen"}
|
||||
{fullscreen ? t("ui.exitFullscreen") : t("ui.fullscreen")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@ -15,6 +15,7 @@ import { Card } from "@/components/ui/card";
|
||||
import { HiTrash } from "react-icons/hi";
|
||||
import { FaUserEdit } from "react-icons/fa";
|
||||
import { LuPlus } from "react-icons/lu";
|
||||
import { Trans } from "react-i18next";
|
||||
|
||||
export default function AuthenticationView() {
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
@ -91,7 +92,7 @@ export default function AuthenticationView() {
|
||||
<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">
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<Heading as="h3" className="my-2">
|
||||
Users
|
||||
<Trans>ui.settingView.users</Trans>
|
||||
</Heading>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
@ -102,7 +103,7 @@ export default function AuthenticationView() {
|
||||
}}
|
||||
>
|
||||
<LuPlus className="text-secondary-foreground" />
|
||||
Add User
|
||||
<Trans>ui.settingView.users.addUser</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-3 space-y-3">
|
||||
@ -123,7 +124,7 @@ export default function AuthenticationView() {
|
||||
}}
|
||||
>
|
||||
<FaUserEdit />
|
||||
<div className="hidden md:block">Update Password</div>
|
||||
<div className="hidden md:block"><Trans>ui.settingView.users.updatePassword</Trans></div>
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center gap-1"
|
||||
@ -135,7 +136,7 @@ export default function AuthenticationView() {
|
||||
}}
|
||||
>
|
||||
<HiTrash />
|
||||
<div className="hidden md:block">Delete</div>
|
||||
<div className="hidden md:block"><Trans>ui.delete</Trans></div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -19,8 +19,10 @@ import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import axios from "axios";
|
||||
import { t } from "i18next";
|
||||
import { useCallback, useContext, useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Trans } from "react-i18next";
|
||||
import { LuExternalLink } from "react-icons/lu";
|
||||
import { Link } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
@ -196,14 +198,13 @@ export default function NotificationView({
|
||||
<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">
|
||||
Notification Settings
|
||||
<Trans>ui.settingView.notification.notificationSettings</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>
|
||||
Frigate can natively send push notifications to your device when
|
||||
it is running in the browser or installed as a PWA.
|
||||
<Trans>ui.settingView.notification.desc</Trans>
|
||||
</p>
|
||||
<div className="flex items-center text-primary">
|
||||
<Link
|
||||
@ -212,7 +213,7 @@ export default function NotificationView({
|
||||
rel="noopener noreferrer"
|
||||
className="inline"
|
||||
>
|
||||
Read the Documentation{" "}
|
||||
<Trans>ui.settingView.notification.documentation</Trans>{" "}
|
||||
<LuExternalLink className="ml-2 inline-flex size-3" />
|
||||
</Link>
|
||||
</div>
|
||||
@ -232,7 +233,7 @@ export default function NotificationView({
|
||||
<FormControl>
|
||||
<div className="flex flex-row items-center justify-start gap-2">
|
||||
<Label className="cursor-pointer" htmlFor="auto-live">
|
||||
Notifications
|
||||
<Trans>ui.settingView.notification</Trans>
|
||||
</Label>
|
||||
<Switch
|
||||
id="auto-live"
|
||||
@ -251,17 +252,16 @@ export default function NotificationView({
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormLabel><Trans>ui.settingView.notification.email</Trans></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"
|
||||
placeholder="example@email.com"
|
||||
placeholder={t("ui.settingView.notification.email.placeholder")}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Entering a valid email is required, as this is used by the
|
||||
push server in case problems occur.
|
||||
<Trans>ui.settingView.notification.email.desc</Trans>
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -274,7 +274,7 @@ export default function NotificationView({
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
<Trans>ui.cancel</Trans>
|
||||
</Button>
|
||||
<Button
|
||||
variant="select"
|
||||
@ -286,10 +286,10 @@ export default function NotificationView({
|
||||
{isLoading ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<ActivityIndicator />
|
||||
<span>Saving...</span>
|
||||
<span><Trans>ui.saving</Trans></span>
|
||||
</div>
|
||||
) : (
|
||||
"Save"
|
||||
<Trans>ui.save</Trans>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
@ -336,7 +336,7 @@ export default function NotificationView({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{`${registration != null ? "Unregister" : "Register"} for notifications on this device`}
|
||||
{registration != null ? t("ui.settingView.notification.unregisterDevice") : t("ui.settingView.notification.registerDevice")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user